Skip to content

Commit fd05f17

Browse files
authored
go: Support raw string subtest names (#34636)
Currently, we're not able to run Go sub-tests that have a raw string (e.g. we're using multi-line names a lot) via the UI. I added the changes that are needed, plus a handful of tests to cover the basics. Quick comparison: Before: <img width="901" height="370" alt="before" src="https://github.com/user-attachments/assets/4e5cadeb-9a0c-49e2-b976-2223e1010f85" /> After: <img width="901" height="505" alt="after" src="https://github.com/user-attachments/assets/994fc69b-f720-488c-a14b-853a3ca2f53c" /> Release Notes: - Added support for Go subtest runner with raw string names
1 parent 7e3fd7b commit fd05f17

File tree

2 files changed

+121
-5
lines changed

2 files changed

+121
-5
lines changed

crates/languages/src/go.rs

Lines changed: 117 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static VERSION_REGEX: LazyLock<Regex> =
4141
LazyLock::new(|| Regex::new(r"\d+\.\d+\.\d+").expect("Failed to create VERSION_REGEX"));
4242

4343
static GO_ESCAPE_SUBTEST_NAME_REGEX: LazyLock<Regex> = LazyLock::new(|| {
44-
Regex::new(r#"[.*+?^${}()|\[\]\\]"#).expect("Failed to create GO_ESCAPE_SUBTEST_NAME_REGEX")
44+
Regex::new(r#"[.*+?^${}()|\[\]\\"']"#).expect("Failed to create GO_ESCAPE_SUBTEST_NAME_REGEX")
4545
});
4646

4747
const BINARY: &str = if cfg!(target_os = "windows") {
@@ -685,11 +685,20 @@ impl ContextProvider for GoContextProvider {
685685
}
686686

687687
fn extract_subtest_name(input: &str) -> Option<String> {
688-
let replaced_spaces = input.trim_matches('"').replace(' ', "_");
688+
let content = if input.starts_with('`') && input.ends_with('`') {
689+
input.trim_matches('`')
690+
} else {
691+
input.trim_matches('"')
692+
};
693+
694+
let processed = content
695+
.chars()
696+
.map(|c| if c.is_whitespace() { '_' } else { c })
697+
.collect::<String>();
689698

690699
Some(
691700
GO_ESCAPE_SUBTEST_NAME_REGEX
692-
.replace_all(&replaced_spaces, |caps: &regex::Captures| {
701+
.replace_all(&processed, |caps: &regex::Captures| {
693702
format!("\\{}", &caps[0])
694703
})
695704
.to_string(),
@@ -700,7 +709,7 @@ fn extract_subtest_name(input: &str) -> Option<String> {
700709
mod tests {
701710
use super::*;
702711
use crate::language;
703-
use gpui::Hsla;
712+
use gpui::{AppContext, Hsla, TestAppContext};
704713
use theme::SyntaxTheme;
705714

706715
#[gpui::test]
@@ -790,4 +799,108 @@ mod tests {
790799
})
791800
);
792801
}
802+
803+
#[gpui::test]
804+
fn test_go_runnable_detection(cx: &mut TestAppContext) {
805+
let language = language("go", tree_sitter_go::LANGUAGE.into());
806+
807+
let interpreted_string_subtest = r#"
808+
package main
809+
810+
import "testing"
811+
812+
func TestExample(t *testing.T) {
813+
t.Run("subtest with double quotes", func(t *testing.T) {
814+
// test code
815+
})
816+
}
817+
"#;
818+
819+
let raw_string_subtest = r#"
820+
package main
821+
822+
import "testing"
823+
824+
func TestExample(t *testing.T) {
825+
t.Run(`subtest with
826+
multiline
827+
backticks`, func(t *testing.T) {
828+
// test code
829+
})
830+
}
831+
"#;
832+
833+
let buffer = cx.new(|cx| {
834+
crate::Buffer::local(interpreted_string_subtest, cx).with_language(language.clone(), cx)
835+
});
836+
cx.executor().run_until_parked();
837+
838+
let runnables: Vec<_> = buffer.update(cx, |buffer, _| {
839+
let snapshot = buffer.snapshot();
840+
snapshot
841+
.runnable_ranges(0..interpreted_string_subtest.len())
842+
.collect()
843+
});
844+
845+
assert!(
846+
runnables.len() == 2,
847+
"Should find test function and subtest with double quotes, found: {}",
848+
runnables.len()
849+
);
850+
851+
let buffer = cx.new(|cx| {
852+
crate::Buffer::local(raw_string_subtest, cx).with_language(language.clone(), cx)
853+
});
854+
cx.executor().run_until_parked();
855+
856+
let runnables: Vec<_> = buffer.update(cx, |buffer, _| {
857+
let snapshot = buffer.snapshot();
858+
snapshot
859+
.runnable_ranges(0..raw_string_subtest.len())
860+
.collect()
861+
});
862+
863+
assert!(
864+
runnables.len() == 2,
865+
"Should find test function and subtest with backticks, found: {}",
866+
runnables.len()
867+
);
868+
}
869+
870+
#[test]
871+
fn test_extract_subtest_name() {
872+
// Interpreted string literal
873+
let input_double_quoted = r#""subtest with double quotes""#;
874+
let result = extract_subtest_name(input_double_quoted);
875+
assert_eq!(result, Some(r#"subtest_with_double_quotes"#.to_string()));
876+
877+
let input_double_quoted_with_backticks = r#""test with `backticks` inside""#;
878+
let result = extract_subtest_name(input_double_quoted_with_backticks);
879+
assert_eq!(result, Some(r#"test_with_`backticks`_inside"#.to_string()));
880+
881+
// Raw string literal
882+
let input_with_backticks = r#"`subtest with backticks`"#;
883+
let result = extract_subtest_name(input_with_backticks);
884+
assert_eq!(result, Some(r#"subtest_with_backticks"#.to_string()));
885+
886+
let input_raw_with_quotes = r#"`test with "quotes" and other chars`"#;
887+
let result = extract_subtest_name(input_raw_with_quotes);
888+
assert_eq!(
889+
result,
890+
Some(r#"test_with_\"quotes\"_and_other_chars"#.to_string())
891+
);
892+
893+
let input_multiline = r#"`subtest with
894+
multiline
895+
backticks`"#;
896+
let result = extract_subtest_name(input_multiline);
897+
assert_eq!(
898+
result,
899+
Some(r#"subtest_with_________multiline_________backticks"#.to_string())
900+
);
901+
902+
let input_with_double_quotes = r#"`test with "double quotes"`"#;
903+
let result = extract_subtest_name(input_with_double_quotes);
904+
assert_eq!(result, Some(r#"test_with_\"double_quotes\""#.to_string()));
905+
}
793906
}

crates/languages/src/go/runnables.scm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@
3838
arguments: (
3939
argument_list
4040
.
41-
(interpreted_string_literal) @_subtest_name
41+
[
42+
(interpreted_string_literal)
43+
(raw_string_literal)
44+
] @_subtest_name
4245
.
4346
(func_literal
4447
parameters: (

0 commit comments

Comments
 (0)