11//! Patches the imports to use codspeed rather than the official "testing" package.
22
33use crate :: prelude:: * ;
4+ use itertools:: Itertools ;
45use rayon:: prelude:: * ;
56use std:: fs;
67use std:: path:: Path ;
@@ -69,19 +70,22 @@ pub fn patch_imports<P: AsRef<Path>>(folder: P) -> anyhow::Result<()> {
6970
7071/// Internal function to apply import patterns to Go source code
7172pub fn patch_imports_for_source ( source : & str ) -> String {
72- let replace_import = |mut source : String , import_path : & str , replacement : & str | -> String {
73+ let mut source = source. to_string ( ) ;
74+
75+ // If we can't parse the source, skip this replacement
76+ // This can happen with template files or malformed Go code
77+ let parsed = match gosyn:: parse_source ( & source) {
78+ Ok ( p) => p,
79+ Err ( _) => return source,
80+ } ;
81+
82+ let mut replacements = vec ! [ ] ;
83+ let mut find_replace_range = |import_path : & str , replacement : & str | {
7384 // Optimization: check if the import path exists in the source before parsing
7485 if !source. contains ( import_path) {
75- return source ;
86+ return ;
7687 }
7788
78- // If we can't parse the source, skip this replacement
79- // This can happen with template files or malformed Go code
80- let parsed = match gosyn:: parse_source ( & source) {
81- Ok ( p) => p,
82- Err ( _) => return source,
83- } ;
84-
8589 if let Some ( import) = parsed
8690 . imports
8791 . iter ( )
@@ -90,39 +94,43 @@ pub fn patch_imports_for_source(source: &str) -> String {
9094 let start_pos = import. path . pos ;
9195 let end_pos = start_pos + import. path . value . len ( ) ;
9296
93- source . replace_range ( start_pos..end_pos, replacement) ;
97+ replacements . push ( ( start_pos..end_pos, replacement. to_string ( ) ) ) ;
9498 }
95-
96- source
9799 } ;
98100
99- let mut source = replace_import (
100- source. to_string ( ) ,
101- "testing" ,
102- "testing \" github.com/CodSpeedHQ/codspeed-go/testing/testing\" " ,
103- ) ;
104-
105101 // Then replace sub-packages like "testing/synctest"
106102 for testing_pkg in & [ "fstest" , "iotest" , "quick" , "slogtest" , "synctest" ] {
107- source = replace_import (
108- source. to_string ( ) ,
103+ find_replace_range (
109104 & format ! ( "testing/{}" , testing_pkg) ,
110105 & format ! (
111106 "{testing_pkg} \" github.com/CodSpeedHQ/codspeed-go/testing/testing/{testing_pkg}\" "
112107 ) ,
113108 ) ;
114109 }
115110
116- let source = replace_import (
117- source,
111+ find_replace_range (
112+ "testing" ,
113+ "testing \" github.com/CodSpeedHQ/codspeed-go/testing/testing\" " ,
114+ ) ;
115+ find_replace_range (
118116 "github.com/thejerf/slogassert" ,
119117 "\" github.com/CodSpeedHQ/codspeed-go/pkg/slogassert\" " ,
120118 ) ;
121- replace_import (
122- source,
119+ find_replace_range (
123120 "github.com/frankban/quicktest" ,
124121 "\" github.com/CodSpeedHQ/codspeed-go/pkg/quicktest\" " ,
125- )
122+ ) ;
123+
124+ // Apply replacements in reverse order to avoid shifting positions
125+ for ( range, replacement) in replacements
126+ . into_iter ( )
127+ . sorted_by_key ( |( range, _) | range. start )
128+ . rev ( )
129+ {
130+ source. replace_range ( range, & replacement) ;
131+ }
132+
133+ source
126134}
127135
128136/// Patches imports and package in specific test files
@@ -388,6 +396,17 @@ func BenchmarkExample(b *testing.B) {
388396func TestExample(t *testing.T) {
389397 s := "package main"
390398}
399+ "# ;
400+
401+ const MANY_TESTING_IMPORTS : & str = r#"package subpackages
402+ import (
403+ "bytes"
404+ "io"
405+ "testing"
406+ "testing/fstest"
407+ "testing/iotest"
408+ "testing/synctest"
409+ )
391410"# ;
392411
393412 #[ rstest]
@@ -406,6 +425,7 @@ func TestExample(t *testing.T) {
406425 MULTILINE_IMPORT_WITH_TESTING_STRING
407426 ) ]
408427 #[ case( "package_main" , PACKAGE_MAIN ) ]
428+ #[ case( "many_testing_imports" , MANY_TESTING_IMPORTS ) ]
409429 fn test_patch_go_source ( #[ case] test_name : & str , #[ case] source : & str ) {
410430 let result = patch_imports_for_source ( source) ;
411431 let result = patch_package_for_source ( result) . unwrap ( ) ;
0 commit comments