diff --git a/Cargo.lock b/Cargo.lock index b402a16..3bbce75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -566,13 +566,18 @@ version = "0.0.1" dependencies = [ "anyhow", "clap", + "dirs", "lsp-types", "regex", "serde", "serde_json", "tempfile", "testing-language-server 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tracing", + "tracing-appender", + "tracing-subscriber", "tree-sitter", + "tree-sitter-go", "tree-sitter-javascript", "tree-sitter-rust", ] @@ -717,6 +722,16 @@ dependencies = [ "regex", ] +[[package]] +name = "tree-sitter-go" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cb318be5ccf75f44e054acf6898a5c95d59b53443eed578e16be0cd7ec037f" +dependencies = [ + "cc", + "tree-sitter", +] + [[package]] name = "tree-sitter-javascript" version = "0.21.0" diff --git a/crates/adapter/Cargo.toml b/crates/adapter/Cargo.toml index b8ccf1c..8b74dcc 100644 --- a/crates/adapter/Cargo.toml +++ b/crates/adapter/Cargo.toml @@ -19,3 +19,8 @@ tree-sitter-rust = "0.21.2" anyhow = { workspace = true } tempfile = "3.10.1" tree-sitter-javascript = "0.21.0" +tree-sitter-go = "0.21.0" +tracing-appender = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, default-features = false } +dirs = "5.0.1" diff --git a/crates/adapter/src/log.rs b/crates/adapter/src/log.rs new file mode 100644 index 0000000..c409633 --- /dev/null +++ b/crates/adapter/src/log.rs @@ -0,0 +1,14 @@ +use tracing_appender::non_blocking::WorkerGuard; + +pub struct Log; + +impl Log { + pub fn init() -> Result { + let home_dir = dirs::home_dir().unwrap(); + let log_path = home_dir.join(".config/testing_ls_adapter/logs"); + let file_appender = tracing_appender::rolling::daily(log_path, "prefix.log"); + let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); + tracing_subscriber::fmt().with_writer(non_blocking).init(); + Ok(guard) + } +} diff --git a/crates/adapter/src/main.rs b/crates/adapter/src/main.rs index 870b560..0638223 100644 --- a/crates/adapter/src/main.rs +++ b/crates/adapter/src/main.rs @@ -1,6 +1,8 @@ use crate::model::AvailableTestKind; use crate::model::Runner; +use anyhow::anyhow; use clap::Parser; +use log::Log; use std::io; use std::io::Write; use std::str::FromStr; @@ -9,18 +11,18 @@ use testing_language_server::spec::AdapterCommands; use testing_language_server::spec::DetectWorkspaceArgs; use testing_language_server::spec::DiscoverArgs; use testing_language_server::spec::RunFileTestArgs; +pub mod log; pub mod model; pub mod runner; fn pick_test_from_extra( extra: &mut [String], ) -> Result<(Vec, AvailableTestKind), anyhow::Error> { - // extraから--test-kind=のものを取り出し、元の配列から`--test-kind=`のものは除外する let mut extra = extra.to_vec(); let index = extra .iter() .position(|arg| arg.starts_with("--test-kind=")) - .unwrap(); + .ok_or(anyhow!("test-kind is not found"))?; let test_kind = extra.remove(index); let language = test_kind.replace("--test-kind=", ""); @@ -41,13 +43,14 @@ fn handle(commands: AdapterCommands) -> Result<(), LSError> { } AdapterCommands::DetectWorkspace(mut commands) => { let (extra, test_kind) = pick_test_from_extra(&mut commands.extra)?; - test_kind.detect_workspaces_root(DetectWorkspaceArgs { extra, ..commands })?; + test_kind.detect_workspaces(DetectWorkspaceArgs { extra, ..commands })?; Ok(()) } } } fn main() { + let _guard = Log::init().expect("Failed to initialize logger"); let args = AdapterCommands::parse(); if let Err(error) = handle(args) { io::stderr() @@ -60,10 +63,8 @@ fn main() { mod tests { use super::*; use crate::runner::cargo_test::CargoTestRunner; - use crate::runner::jest::JestRunner; #[test] - // If `--test-kind=` is not present, then return Err fn error_test_kind_detection() { let mut extra = vec![]; pick_test_from_extra(&mut extra).unwrap_err(); @@ -72,22 +73,20 @@ mod tests { } #[test] - // If `--test-kind=` is present, then return Ok(value) - fn test_kind_detection() { + fn single_test_kind_detection() { let mut extra = vec!["--test-kind=cargo-test".to_string()]; let (_, language) = pick_test_from_extra(&mut extra).unwrap(); assert_eq!(language, AvailableTestKind::CargoTest(CargoTestRunner)); } #[test] - // If multiple `--test-kind=` are present, then return first one - fn error_multiple_test_kind_detection() { + fn multiple_test_kind_results_first_kind() { let mut extra = vec![ "--test-kind=cargo-test".to_string(), "--test-kind=jest".to_string(), "--test-kind=foo".to_string(), ]; let (_, test_kind) = pick_test_from_extra(&mut extra).unwrap(); - assert_eq!(test_kind, AvailableTestKind::Jest(JestRunner)); + assert_eq!(test_kind, AvailableTestKind::CargoTest(CargoTestRunner)); } } diff --git a/crates/adapter/src/model.rs b/crates/adapter/src/model.rs index 7c3a007..7302cd9 100644 --- a/crates/adapter/src/model.rs +++ b/crates/adapter/src/model.rs @@ -1,4 +1,5 @@ use crate::runner::cargo_test::CargoTestRunner; +use crate::runner::go::GoTestRunner; use std::str::FromStr; use testing_language_server::error::LSError; use testing_language_server::spec::DetectWorkspaceArgs; @@ -11,12 +12,14 @@ use crate::runner::jest::JestRunner; pub enum AvailableTestKind { CargoTest(CargoTestRunner), Jest(JestRunner), + GoTest(GoTestRunner), } impl Runner for AvailableTestKind { fn disover(&self, args: DiscoverArgs) -> Result<(), LSError> { match self { AvailableTestKind::CargoTest(runner) => runner.disover(args), AvailableTestKind::Jest(runner) => runner.disover(args), + AvailableTestKind::GoTest(runner) => runner.disover(args), } } @@ -24,13 +27,15 @@ impl Runner for AvailableTestKind { match self { AvailableTestKind::CargoTest(runner) => runner.run_file_test(args), AvailableTestKind::Jest(runner) => runner.run_file_test(args), + AvailableTestKind::GoTest(runner) => runner.run_file_test(args), } } - fn detect_workspaces_root(&self, args: DetectWorkspaceArgs) -> Result<(), LSError> { + fn detect_workspaces(&self, args: DetectWorkspaceArgs) -> Result<(), LSError> { match self { - AvailableTestKind::CargoTest(runner) => runner.detect_workspaces_root(args), - AvailableTestKind::Jest(runner) => runner.detect_workspaces_root(args), + AvailableTestKind::CargoTest(runner) => runner.detect_workspaces(args), + AvailableTestKind::Jest(runner) => runner.detect_workspaces(args), + AvailableTestKind::GoTest(runner) => runner.detect_workspaces(args), } } } @@ -42,6 +47,7 @@ impl FromStr for AvailableTestKind { match s { "cargo-test" => Ok(AvailableTestKind::CargoTest(CargoTestRunner)), "jest" => Ok(AvailableTestKind::Jest(JestRunner)), + "go-test" => Ok(AvailableTestKind::GoTest(GoTestRunner)), _ => Err(anyhow::anyhow!("Unknown test kind: {}", s)), } } @@ -50,5 +56,5 @@ impl FromStr for AvailableTestKind { pub trait Runner { fn disover(&self, args: DiscoverArgs) -> Result<(), LSError>; fn run_file_test(&self, args: RunFileTestArgs) -> Result<(), LSError>; - fn detect_workspaces_root(&self, args: DetectWorkspaceArgs) -> Result<(), LSError>; + fn detect_workspaces(&self, args: DetectWorkspaceArgs) -> Result<(), LSError>; } diff --git a/crates/adapter/src/runner/go.rs b/crates/adapter/src/runner/go.rs new file mode 100644 index 0000000..f743f77 --- /dev/null +++ b/crates/adapter/src/runner/go.rs @@ -0,0 +1,383 @@ +use crate::model::Runner; +use anyhow::anyhow; +use lsp_types::Diagnostic; +use lsp_types::Position; +use lsp_types::Range; +use regex::Regex; +use serde::Deserialize; +use std::collections::HashMap; +use std::path::PathBuf; +use std::process::Output; +use std::str::FromStr; +use testing_language_server::error::LSError; +use testing_language_server::spec::DiscoverResult; +use testing_language_server::spec::DiscoverResultItem; +use testing_language_server::spec::RunFileTestResult; +use testing_language_server::spec::RunFileTestResultItem; +use testing_language_server::spec::TestItem; +use tree_sitter::Point; +use tree_sitter::Query; +use tree_sitter::QueryCursor; + +use super::util::detect_workspaces_from_file_paths; + +// If the character value is greater than the line length it defaults back to the line length. +const MAX_CHAR_LENGTH: u32 = 10000; + +#[derive(Deserialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +enum Action { + Start, + Run, + Output, + Fail, + Pass, +} + +#[allow(dead_code)] +#[derive(Deserialize)] +#[serde(rename_all = "PascalCase")] +struct TestResultLine { + time: String, + action: Action, + package: String, + test: Option, + output: Option, +} + +fn get_position_from_output(output: &str) -> Option<(String, u32)> { + let pattern = r"^\s{4}(.*_test\.go):(\d+):"; + let re = Regex::new(pattern).unwrap(); + if let Some(captures) = re.captures(output) { + if let (Some(file_name), Some(lnum)) = (captures.get(1), captures.get(2)) { + return Some(( + file_name.as_str().to_string(), + lnum.as_str().parse::().unwrap() - 1, + )); + } + } + None +} +fn get_log_from_output(output: &str) -> String { + output.replace(" ", "") +} + +fn parse_diagnostics( + contents: &str, + workspace_root: PathBuf, + file_paths: &[String], +) -> Result { + let contents = contents.replace("\r\n", "\n"); + let lines = contents.lines(); + let mut result_map: HashMap> = HashMap::new(); + let mut file_name: Option = None; + let mut lnum: Option = None; + let mut message = String::new(); + let mut last_action: Option = None; + for line in lines { + let value: TestResultLine = serde_json::from_str(line).map_err(|e| anyhow!("{:?}", e))?; + match value.action { + Action::Run => { + file_name = None; + message = String::new(); + } + Action::Output => { + let output = &value.output.unwrap(); + if let Some((detected_file_name, detected_lnum)) = get_position_from_output(output) + { + file_name = Some(detected_file_name); + lnum = Some(detected_lnum); + message = String::new(); + } else { + message += &get_log_from_output(output); + } + } + _ => {} + } + let current_action = value.action; + let is_action_changed = last_action.as_ref() != Some(¤t_action); + if is_action_changed { + last_action = Some(current_action); + } else { + continue; + } + + if let (Some(detected_fn), Some(detected_lnum)) = (&file_name, lnum) { + let diagnostic = Diagnostic { + range: Range { + start: Position { + line: detected_lnum, + character: 1, + }, + end: Position { + line: detected_lnum, + character: MAX_CHAR_LENGTH, + }, + }, + message: message.clone(), + ..Diagnostic::default() + }; + let file_path = workspace_root + .join(detected_fn) + .to_str() + .unwrap() + .to_owned(); + if file_paths.contains(&file_path) { + result_map.entry(file_path).or_default().push(diagnostic); + } + file_name = None; + lnum = None; + } + } + + Ok(result_map + .into_iter() + .map(|(path, diagnostics)| RunFileTestResultItem { path, diagnostics }) + .collect()) +} + +fn discover(file_path: &str) -> Result, LSError> { + let mut parser = tree_sitter::Parser::new(); + let mut test_items: Vec = vec![]; + parser + .set_language(&tree_sitter_go::language()) + .expect("Error loading Rust grammar"); + let source_code = std::fs::read_to_string(file_path)?; + let tree = parser.parse(&source_code, None).unwrap(); + let query_string = r#" + ;;query + ((function_declaration + name: (identifier) @test.name) + (#match? @test.name "^(Test|Example)")) + @test.definition + + (method_declaration + name: (field_identifier) @test.name + (#match? @test.name "^(Test|Example)")) @test.definition + + (call_expression + function: (selector_expression + field: (field_identifier) @test.method) + (#match? @test.method "^Run$") + arguments: (argument_list . (interpreted_string_literal) @test.name)) + @test.definition +;; query for list table tests + (block + (short_var_declaration + left: (expression_list + (identifier) @test.cases) + right: (expression_list + (composite_literal + (literal_value + (literal_element + (literal_value + (keyed_element + (literal_element + (identifier) @test.field.name) + (literal_element + (interpreted_string_literal) @test.name)))) @test.definition)))) + (for_statement + (range_clause + left: (expression_list + (identifier) @test.case) + right: (identifier) @test.cases1 + (#eq? @test.cases @test.cases1)) + body: (block + (expression_statement + (call_expression + function: (selector_expression + field: (field_identifier) @test.method) + (#match? @test.method "^Run$") + arguments: (argument_list + (selector_expression + operand: (identifier) @test.case1 + (#eq? @test.case @test.case1) + field: (field_identifier) @test.field.name1 + (#eq? @test.field.name @test.field.name1)))))))) + +;; query for map table tests + (block + (short_var_declaration + left: (expression_list + (identifier) @test.cases) + right: (expression_list + (composite_literal + (literal_value + (keyed_element + (literal_element + (interpreted_string_literal) @test.name) + (literal_element + (literal_value) @test.definition)))))) + (for_statement + (range_clause + left: (expression_list + ((identifier) @test.key.name) + ((identifier) @test.case)) + right: (identifier) @test.cases1 + (#eq? @test.cases @test.cases1)) + body: (block + (expression_statement + (call_expression + function: (selector_expression + field: (field_identifier) @test.method) + (#match? @test.method "^Run$") + arguments: (argument_list + ((identifier) @test.key.name1 + (#eq? @test.key.name @test.key.name1)))))))) +"#; + let query = + Query::new(&tree_sitter_go::language(), query_string).expect("Error creating query"); + + let mut cursor = QueryCursor::new(); + cursor.set_byte_range(tree.root_node().byte_range()); + let source = source_code.as_bytes(); + let matches = cursor.matches(&query, tree.root_node(), source); + for m in matches { + let mut namespace_name = ""; + let mut test_start_position = Point::default(); + let mut test_end_position = Point::default(); + for capture in m.captures { + let capture_name = query.capture_names()[capture.index as usize]; + let value = capture.node.utf8_text(source)?; + let start_position = capture.node.start_position(); + let end_position = capture.node.end_position(); + match capture_name { + "namespace.name" => { + namespace_name = value; + } + "test.definition" => { + test_start_position = start_position; + test_end_position = end_position; + } + "test.name" => { + let test_name = value; + let test_item = TestItem { + id: format!("{}:{}", namespace_name, test_name), + name: test_name.to_string(), + start_position: Range { + start: Position { + line: test_start_position.row as u32, + character: test_start_position.column as u32, + }, + end: Position { + line: test_start_position.row as u32, + character: MAX_CHAR_LENGTH, + }, + }, + end_position: Range { + start: Position { + line: test_end_position.row as u32, + character: 0, + }, + end: Position { + line: test_end_position.row as u32, + character: test_end_position.column as u32, + }, + }, + }; + test_items.push(test_item); + test_start_position = Point::default(); + test_end_position = Point::default(); + } + _ => {} + } + } + } + + Ok(test_items) +} + +#[derive(Eq, PartialEq, Hash, Debug)] +pub struct GoTestRunner; +impl Runner for GoTestRunner { + fn disover( + &self, + args: testing_language_server::spec::DiscoverArgs, + ) -> Result<(), testing_language_server::error::LSError> { + let file_paths = args.file_paths; + let mut discover_results: DiscoverResult = vec![]; + + for file_path in file_paths { + let tests = discover(&file_path)?; + discover_results.push(DiscoverResultItem { + tests, + path: file_path, + }); + } + serde_json::to_writer(std::io::stdout(), &discover_results)?; + Ok(()) + } + + fn run_file_test( + &self, + args: testing_language_server::spec::RunFileTestArgs, + ) -> Result<(), testing_language_server::error::LSError> { + let file_paths = args.file_paths; + let default_args = ["-v", "-json", "", "-count=1", "-timeout=60s"]; + let workspace = args.workspace; + let test_result = std::process::Command::new("go") + .current_dir(&workspace) + .arg("test") + .args(default_args) + .args(args.extra) + .output() + .unwrap(); + let Output { stdout, stderr, .. } = test_result; + if stdout.is_empty() && !stderr.is_empty() { + return Err(LSError::Adapter(String::from_utf8(stderr).unwrap())); + } + let test_result = String::from_utf8(stdout)?; + let diagnostics: RunFileTestResult = parse_diagnostics( + &test_result, + PathBuf::from_str(&workspace).unwrap(), + &file_paths, + )?; + serde_json::to_writer(std::io::stdout(), &diagnostics)?; + Ok(()) + } + + fn detect_workspaces( + &self, + args: testing_language_server::spec::DetectWorkspaceArgs, + ) -> Result<(), testing_language_server::error::LSError> { + serde_json::to_writer( + std::io::stdout(), + &detect_workspaces_from_file_paths(&args.file_paths, &["go.mod".to_string()]), + )?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::runner::go::discover; + use std::str::FromStr; + use std::{fs::read_to_string, path::PathBuf}; + + use crate::runner::go::parse_diagnostics; + + #[test] + fn test_parse_diagnostics() { + let current_dir = std::env::current_dir().unwrap(); + let test_file_path = current_dir.join("tests/go-test.txt"); + let contents = read_to_string(test_file_path).unwrap(); + let workspace = PathBuf::from_str("/home/demo/test/go/src/test").unwrap(); + let target_file_path = "/home/demo/test/go/src/test/cases_test.go"; + let result = + parse_diagnostics(&contents, workspace, &[target_file_path.to_string()]).unwrap(); + let result = result.first().unwrap(); + assert_eq!(result.path, target_file_path); + let diagnostic = result.diagnostics.first().unwrap(); + assert_eq!(diagnostic.range.start.line, 30); + assert_eq!(diagnostic.range.start.character, 1); + assert_eq!(diagnostic.range.end.line, 30); + assert_eq!(diagnostic.message, "\tError Trace:\tcases_test.go:31\n\tError: \tNot equal: \n\t \texpected: 7\n\t \tactual : -1\n\tTest: \tTestSubtract/test_two\n--- FAIL: TestSubtract (0.00s)\n --- FAIL: TestSubtract/test_one (0.00s)\n"); + } + + #[test] + fn test_discover() { + let file_path = "../../test_proj/go/cases_test.go"; + let test_items = discover(file_path).unwrap(); + assert!(!test_items.is_empty()); + } +} diff --git a/crates/adapter/src/runner/mod.rs b/crates/adapter/src/runner/mod.rs index b534f79..d739aa2 100644 --- a/crates/adapter/src/runner/mod.rs +++ b/crates/adapter/src/runner/mod.rs @@ -1,2 +1,4 @@ pub mod cargo_test; +pub mod go; pub mod jest; +pub mod util; diff --git a/crates/adapter/src/runner/util.rs b/crates/adapter/src/runner/util.rs new file mode 100644 index 0000000..863decc --- /dev/null +++ b/crates/adapter/src/runner/util.rs @@ -0,0 +1,50 @@ +use std::collections::HashMap; +use std::path::PathBuf; +use std::str::FromStr; + +/// determine if a particular file is the root of workspace based on whether it is in the same directory +pub fn detect_workspace_from_file(file_path: PathBuf, file_names: &[String]) -> Option { + let parent = file_path.parent(); + if let Some(parent) = parent { + if file_names + .iter() + .any(|file_name| parent.join(file_name).exists()) + { + return Some(parent.to_string_lossy().to_string()); + } else { + detect_workspace_from_file(parent.to_path_buf(), file_names) + } + } else { + None + } +} + +pub fn detect_workspaces_from_file_paths( + target_file_paths: &[String], + file_names: &[String], +) -> HashMap> { + let mut result_map: HashMap> = HashMap::new(); + let mut file_paths = target_file_paths.to_vec(); + file_paths.sort_by_key(|b| std::cmp::Reverse(b.len())); + for file_path in file_paths { + let existing_workspace = result_map + .iter() + .find(|(workspace_root, _)| file_path.contains(workspace_root.as_str())); + if let Some((workspace_root, _)) = existing_workspace { + result_map + .entry(workspace_root.to_string()) + .or_default() + .push(file_path.clone()); + } else { + let workspace = + detect_workspace_from_file(PathBuf::from_str(&file_path).unwrap(), file_names); + if let Some(workspace) = workspace { + result_map + .entry(workspace) + .or_default() + .push(file_path.clone()); + } + } + } + result_map +} diff --git a/crates/adapter/tests/go-test.txt b/crates/adapter/tests/go-test.txt new file mode 100644 index 0000000..064b54b --- /dev/null +++ b/crates/adapter/tests/go-test.txt @@ -0,0 +1,161 @@ +{"Time":"2024-05-25T17:06:16.98464582+09:00","Action":"start","Package":"neotest_go"} +{"Time":"2024-05-25T17:06:16.986822201+09:00","Action":"run","Package":"neotest_go","Test":"TestSubtract"} +{"Time":"2024-05-25T17:06:16.986838849+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract","Output":"=== RUN TestSubtract\n"} +{"Time":"2024-05-25T17:06:16.986859373+09:00","Action":"run","Package":"neotest_go","Test":"TestSubtract/test_one"} +{"Time":"2024-05-25T17:06:16.98686856+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_one","Output":" \tError Trace:\tcases_test.go:31\n"} +{"Time":"2024-05-25T17:06:16.986871386+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_one","Output":" \tError: \tNot equal: \n"} +{"Time":"2024-05-25T17:06:16.986874139+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_one","Output":" \t \texpected: 3\n"} +{"Time":"2024-05-25T17:06:16.986876748+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_one","Output":" \t \tactual : -1\n"} +{"Time":"2024-05-25T17:06:16.986879547+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_one","Output":" \tTest: \tTestSubtract/test_one\n"} +{"Time":"2024-05-25T17:06:16.986883029+09:00","Action":"run","Package":"neotest_go","Test":"TestSubtract/test_two"} +{"Time":"2024-05-25T17:06:16.986885264+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_two","Output":"=== RUN TestSubtract/test_two\n"} +{"Time":"2024-05-25T17:06:16.986888429+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_two","Output":" cases_test.go:31: \n"} +{"Time":"2024-05-25T17:06:16.986891613+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_two","Output":" \tError Trace:\tcases_test.go:31\n"} +{"Time":"2024-05-25T17:06:16.986894222+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_two","Output":" \tError: \tNot equal: \n"} +{"Time":"2024-05-25T17:06:16.986896835+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_two","Output":" \t \texpected: 7\n"} +{"Time":"2024-05-25T17:06:16.986899333+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_two","Output":" \t \tactual : -1\n"} +{"Time":"2024-05-25T17:06:16.986901904+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_two","Output":" \tTest: \tTestSubtract/test_two\n"} +{"Time":"2024-05-25T17:06:16.986906401+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract","Output":"--- FAIL: TestSubtract (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.986910144+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_one","Output":" --- FAIL: TestSubtract/test_one (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.986913275+09:00","Action":"fail","Package":"neotest_go","Test":"TestSubtract/test_one","Elapsed":0} +{"Time":"2024-05-25T17:06:16.986916945+09:00","Action":"output","Package":"neotest_go","Test":"TestSubtract/test_two","Output":" --- FAIL: TestSubtract/test_two (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.986919709+09:00","Action":"fail","Package":"neotest_go","Test":"TestSubtract/test_two","Elapsed":0} +{"Time":"2024-05-25T17:06:16.986922033+09:00","Action":"fail","Package":"neotest_go","Test":"TestSubtract","Elapsed":0} +{"Time":"2024-05-25T17:06:16.986924322+09:00","Action":"run","Package":"neotest_go","Test":"TestAdd"} +{"Time":"2024-05-25T17:06:16.986926439+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd","Output":"=== RUN TestAdd\n"} +{"Time":"2024-05-25T17:06:16.986929637+09:00","Action":"run","Package":"neotest_go","Test":"TestAdd/test_one"} +{"Time":"2024-05-25T17:06:16.986931891+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/test_one","Output":"=== RUN TestAdd/test_one\n"} +{"Time":"2024-05-25T17:06:16.98693449+09:00","Action":"run","Package":"neotest_go","Test":"TestAdd/test_two"} +{"Time":"2024-05-25T17:06:16.986936644+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/test_two","Output":"=== RUN TestAdd/test_two\n"} +{"Time":"2024-05-25T17:06:16.986939093+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/test_two","Output":" cases_test.go:42: \n"} +{"Time":"2024-05-25T17:06:16.986941721+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/test_two","Output":" \tError Trace:\tcases_test.go:42\n"} +{"Time":"2024-05-25T17:06:16.986944261+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/test_two","Output":" \tError: \tNot equal: \n"} +{"Time":"2024-05-25T17:06:16.986946773+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/test_two","Output":" \t \texpected: 5\n"} +{"Time":"2024-05-25T17:06:16.986949247+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/test_two","Output":" \t \tactual : 3\n"} +{"Time":"2024-05-25T17:06:16.986951706+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/test_two","Output":" \tTest: \tTestAdd/test_two\n"} +{"Time":"2024-05-25T17:06:16.986954288+09:00","Action":"run","Package":"neotest_go","Test":"TestAdd/string"} +{"Time":"2024-05-25T17:06:16.986956496+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/string","Output":"=== RUN TestAdd/string\n"} +{"Time":"2024-05-25T17:06:16.986959568+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd","Output":"--- FAIL: TestAdd (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.986964387+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/test_one","Output":" --- PASS: TestAdd/test_one (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.986967557+09:00","Action":"pass","Package":"neotest_go","Test":"TestAdd/test_one","Elapsed":0} +{"Time":"2024-05-25T17:06:16.986970137+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/test_two","Output":" --- FAIL: TestAdd/test_two (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.986973398+09:00","Action":"fail","Package":"neotest_go","Test":"TestAdd/test_two","Elapsed":0} +{"Time":"2024-05-25T17:06:16.986976554+09:00","Action":"output","Package":"neotest_go","Test":"TestAdd/string","Output":" --- PASS: TestAdd/string (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.986979769+09:00","Action":"pass","Package":"neotest_go","Test":"TestAdd/string","Elapsed":0} +{"Time":"2024-05-25T17:06:16.98698262+09:00","Action":"fail","Package":"neotest_go","Test":"TestAdd","Elapsed":0} +{"Time":"2024-05-25T17:06:16.98698541+09:00","Action":"run","Package":"neotest_go","Test":"TestAddOne"} +{"Time":"2024-05-25T17:06:16.986987976+09:00","Action":"output","Package":"neotest_go","Test":"TestAddOne","Output":"=== RUN TestAddOne\n"} +{"Time":"2024-05-25T17:06:16.986990912+09:00","Action":"output","Package":"neotest_go","Test":"TestAddOne","Output":"--- PASS: TestAddOne (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.986994224+09:00","Action":"pass","Package":"neotest_go","Test":"TestAddOne","Elapsed":0} +{"Time":"2024-05-25T17:06:16.986996509+09:00","Action":"run","Package":"neotest_go","Test":"TestAddTwo"} +{"Time":"2024-05-25T17:06:16.986999108+09:00","Action":"output","Package":"neotest_go","Test":"TestAddTwo","Output":"=== RUN TestAddTwo\n"} +{"Time":"2024-05-25T17:06:16.98700243+09:00","Action":"output","Package":"neotest_go","Test":"TestAddTwo","Output":"--- PASS: TestAddTwo (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987005287+09:00","Action":"pass","Package":"neotest_go","Test":"TestAddTwo","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987008349+09:00","Action":"run","Package":"neotest_go","Test":"TestSomeTest"} +{"Time":"2024-05-25T17:06:16.987011032+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest","Output":"=== RUN TestSomeTest\n"} +{"Time":"2024-05-25T17:06:16.987014678+09:00","Action":"run","Package":"neotest_go","Test":"TestSomeTest/AccessDenied1"} +{"Time":"2024-05-25T17:06:16.987017664+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied1","Output":"=== RUN TestSomeTest/AccessDenied1\n"} +{"Time":"2024-05-25T17:06:16.98702332+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied1","Output":"AccessDenied1 GET /api/nothing lalala 403\n"} +{"Time":"2024-05-25T17:06:16.987030097+09:00","Action":"run","Package":"neotest_go","Test":"TestSomeTest/AccessDenied2"} +{"Time":"2024-05-25T17:06:16.9870326+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied2","Output":"=== RUN TestSomeTest/AccessDenied2\n"} +{"Time":"2024-05-25T17:06:16.987035243+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied2","Output":"AccessDenied2 GET /api/nothing lalala 403\n"} +{"Time":"2024-05-25T17:06:16.98703803+09:00","Action":"run","Package":"neotest_go","Test":"TestSomeTest/AccessDenied3"} +{"Time":"2024-05-25T17:06:16.987040299+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied3","Output":"=== RUN TestSomeTest/AccessDenied3\n"} +{"Time":"2024-05-25T17:06:16.987042979+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied3","Output":"AccessDenied3 GET /api/nothing lalala 403\n"} +{"Time":"2024-05-25T17:06:16.987045694+09:00","Action":"run","Package":"neotest_go","Test":"TestSomeTest/AccessDenied4"} +{"Time":"2024-05-25T17:06:16.987048493+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied4","Output":"=== RUN TestSomeTest/AccessDenied4\n"} +{"Time":"2024-05-25T17:06:16.987051059+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied4","Output":"AccessDenied4 GET /api/nothing lalala 403\n"} +{"Time":"2024-05-25T17:06:16.987053703+09:00","Action":"run","Package":"neotest_go","Test":"TestSomeTest/AccessDenied5"} +{"Time":"2024-05-25T17:06:16.987055897+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied5","Output":"=== RUN TestSomeTest/AccessDenied5\n"} +{"Time":"2024-05-25T17:06:16.987058733+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied5","Output":"AccessDenied5 GET /api/nothing lalala 403\n"} +{"Time":"2024-05-25T17:06:16.987062114+09:00","Action":"run","Package":"neotest_go","Test":"TestSomeTest/AccessDenied6"} +{"Time":"2024-05-25T17:06:16.987064491+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied6","Output":"=== RUN TestSomeTest/AccessDenied6\n"} +{"Time":"2024-05-25T17:06:16.987067709+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied6","Output":"AccessDenied6 GET /api/nothing lalala 403\n"} +{"Time":"2024-05-25T17:06:16.987076359+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest","Output":"--- PASS: TestSomeTest (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987079722+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied1","Output":" --- PASS: TestSomeTest/AccessDenied1 (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987082855+09:00","Action":"pass","Package":"neotest_go","Test":"TestSomeTest/AccessDenied1","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987085329+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied2","Output":" --- PASS: TestSomeTest/AccessDenied2 (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987088221+09:00","Action":"pass","Package":"neotest_go","Test":"TestSomeTest/AccessDenied2","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987090756+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied3","Output":" --- PASS: TestSomeTest/AccessDenied3 (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987094115+09:00","Action":"pass","Package":"neotest_go","Test":"TestSomeTest/AccessDenied3","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987096613+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied4","Output":" --- PASS: TestSomeTest/AccessDenied4 (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987099588+09:00","Action":"pass","Package":"neotest_go","Test":"TestSomeTest/AccessDenied4","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987104022+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied5","Output":" --- PASS: TestSomeTest/AccessDenied5 (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987107814+09:00","Action":"pass","Package":"neotest_go","Test":"TestSomeTest/AccessDenied5","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987110865+09:00","Action":"output","Package":"neotest_go","Test":"TestSomeTest/AccessDenied6","Output":" --- PASS: TestSomeTest/AccessDenied6 (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987113695+09:00","Action":"pass","Package":"neotest_go","Test":"TestSomeTest/AccessDenied6","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987116401+09:00","Action":"pass","Package":"neotest_go","Test":"TestSomeTest","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987119142+09:00","Action":"run","Package":"neotest_go","Test":"TestSplit"} +{"Time":"2024-05-25T17:06:16.987121813+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit","Output":"=== RUN TestSplit\n"} +{"Time":"2024-05-25T17:06:16.987124271+09:00","Action":"run","Package":"neotest_go","Test":"TestSplit/simple"} +{"Time":"2024-05-25T17:06:16.987126899+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit/simple","Output":"=== RUN TestSplit/simple\n"} +{"Time":"2024-05-25T17:06:16.987129965+09:00","Action":"run","Package":"neotest_go","Test":"TestSplit/wrong_sep"} +{"Time":"2024-05-25T17:06:16.987132221+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit/wrong_sep","Output":"=== RUN TestSplit/wrong_sep\n"} +{"Time":"2024-05-25T17:06:16.98713529+09:00","Action":"run","Package":"neotest_go","Test":"TestSplit/no_sep"} +{"Time":"2024-05-25T17:06:16.987138035+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit/no_sep","Output":"=== RUN TestSplit/no_sep\n"} +{"Time":"2024-05-25T17:06:16.987140671+09:00","Action":"run","Package":"neotest_go","Test":"TestSplit/trailing_sep"} +{"Time":"2024-05-25T17:06:16.987143812+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit/trailing_sep","Output":"=== RUN TestSplit/trailing_sep\n"} +{"Time":"2024-05-25T17:06:16.987148473+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit/trailing_sep","Output":" map_table_test.go:25: trailing sep: expected: [a b c], got: [a b c ]\n"} +{"Time":"2024-05-25T17:06:16.987152641+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit","Output":"--- FAIL: TestSplit (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987156528+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit/simple","Output":" --- PASS: TestSplit/simple (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.98716009+09:00","Action":"pass","Package":"neotest_go","Test":"TestSplit/simple","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987163018+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit/wrong_sep","Output":" --- PASS: TestSplit/wrong_sep (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987166426+09:00","Action":"pass","Package":"neotest_go","Test":"TestSplit/wrong_sep","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987169756+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit/no_sep","Output":" --- PASS: TestSplit/no_sep (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987173446+09:00","Action":"pass","Package":"neotest_go","Test":"TestSplit/no_sep","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987176509+09:00","Action":"output","Package":"neotest_go","Test":"TestSplit/trailing_sep","Output":" --- FAIL: TestSplit/trailing_sep (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987179658+09:00","Action":"fail","Package":"neotest_go","Test":"TestSplit/trailing_sep","Elapsed":0} +{"Time":"2024-05-25T17:06:16.9871823+09:00","Action":"fail","Package":"neotest_go","Test":"TestSplit","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987185013+09:00","Action":"run","Package":"neotest_go","Test":"TestExampleTestSuite"} +{"Time":"2024-05-25T17:06:16.987187634+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite","Output":"=== RUN TestExampleTestSuite\n"} +{"Time":"2024-05-25T17:06:16.987358969+09:00","Action":"run","Package":"neotest_go","Test":"TestExampleTestSuite/TestExample"} +{"Time":"2024-05-25T17:06:16.987372775+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite/TestExample","Output":"=== RUN TestExampleTestSuite/TestExample\n"} +{"Time":"2024-05-25T17:06:16.987378537+09:00","Action":"run","Package":"neotest_go","Test":"TestExampleTestSuite/TestExampleFailure"} +{"Time":"2024-05-25T17:06:16.987383079+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite/TestExampleFailure","Output":"=== RUN TestExampleTestSuite/TestExampleFailure\n"} +{"Time":"2024-05-25T17:06:16.987611537+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite/TestExampleFailure","Output":" suite_test.go:32: \n"} +{"Time":"2024-05-25T17:06:16.987626951+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite/TestExampleFailure","Output":" \tError Trace:\tsuite_test.go:32\n"} +{"Time":"2024-05-25T17:06:16.987631582+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite/TestExampleFailure","Output":" \tError: \tNot equal: \n"} +{"Time":"2024-05-25T17:06:16.987635334+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite/TestExampleFailure","Output":" \t \texpected: 5\n"} +{"Time":"2024-05-25T17:06:16.9876384+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite/TestExampleFailure","Output":" \t \tactual : 3\n"} +{"Time":"2024-05-25T17:06:16.987641353+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite/TestExampleFailure","Output":" \tTest: \tTestExampleTestSuite/TestExampleFailure\n"} +{"Time":"2024-05-25T17:06:16.987649622+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite","Output":"--- FAIL: TestExampleTestSuite (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987655287+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite/TestExample","Output":" --- PASS: TestExampleTestSuite/TestExample (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987659094+09:00","Action":"pass","Package":"neotest_go","Test":"TestExampleTestSuite/TestExample","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987663126+09:00","Action":"output","Package":"neotest_go","Test":"TestExampleTestSuite/TestExampleFailure","Output":" --- FAIL: TestExampleTestSuite/TestExampleFailure (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987666501+09:00","Action":"fail","Package":"neotest_go","Test":"TestExampleTestSuite/TestExampleFailure","Elapsed":0} +{"Time":"2024-05-25T17:06:16.9876691+09:00","Action":"fail","Package":"neotest_go","Test":"TestExampleTestSuite","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987671645+09:00","Action":"run","Package":"neotest_go","Test":"TestOdd"} +{"Time":"2024-05-25T17:06:16.987674132+09:00","Action":"output","Package":"neotest_go","Test":"TestOdd","Output":"=== RUN TestOdd\n"} +{"Time":"2024-05-25T17:06:16.987676921+09:00","Action":"run","Package":"neotest_go","Test":"TestOdd/odd"} +{"Time":"2024-05-25T17:06:16.987680637+09:00","Action":"output","Package":"neotest_go","Test":"TestOdd/odd","Output":"=== RUN TestOdd/odd\n"} +{"Time":"2024-05-25T17:06:16.987683855+09:00","Action":"run","Package":"neotest_go","Test":"TestOdd/odd/5_is_odd"} +{"Time":"2024-05-25T17:06:16.98769839+09:00","Action":"output","Package":"neotest_go","Test":"TestOdd/odd/5_is_odd","Output":"=== RUN TestOdd/odd/5_is_odd\n"} +{"Time":"2024-05-25T17:06:16.987711715+09:00","Action":"run","Package":"neotest_go","Test":"TestOdd/odd/5_is_odd/9_is_odd"} +{"Time":"2024-05-25T17:06:16.987713743+09:00","Action":"output","Package":"neotest_go","Test":"TestOdd/odd/5_is_odd/9_is_odd","Output":"=== RUN TestOdd/odd/5_is_odd/9_is_odd\n"} +{"Time":"2024-05-25T17:06:16.987715909+09:00","Action":"run","Package":"neotest_go","Test":"TestOdd/odd/7_is_odd"} +{"Time":"2024-05-25T17:06:16.987717512+09:00","Action":"output","Package":"neotest_go","Test":"TestOdd/odd/7_is_odd","Output":"=== RUN TestOdd/odd/7_is_odd\n"} +{"Time":"2024-05-25T17:06:16.987720928+09:00","Action":"output","Package":"neotest_go","Test":"TestOdd","Output":"--- PASS: TestOdd (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987723417+09:00","Action":"output","Package":"neotest_go","Test":"TestOdd/odd","Output":" --- PASS: TestOdd/odd (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987726445+09:00","Action":"output","Package":"neotest_go","Test":"TestOdd/odd/5_is_odd","Output":" --- PASS: TestOdd/odd/5_is_odd (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987728552+09:00","Action":"output","Package":"neotest_go","Test":"TestOdd/odd/5_is_odd/9_is_odd","Output":" --- PASS: TestOdd/odd/5_is_odd/9_is_odd (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.98773067+09:00","Action":"pass","Package":"neotest_go","Test":"TestOdd/odd/5_is_odd/9_is_odd","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987733354+09:00","Action":"pass","Package":"neotest_go","Test":"TestOdd/odd/5_is_odd","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987734868+09:00","Action":"output","Package":"neotest_go","Test":"TestOdd/odd/7_is_odd","Output":" --- PASS: TestOdd/odd/7_is_odd (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987736884+09:00","Action":"pass","Package":"neotest_go","Test":"TestOdd/odd/7_is_odd","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987738363+09:00","Action":"pass","Package":"neotest_go","Test":"TestOdd/odd","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987739718+09:00","Action":"pass","Package":"neotest_go","Test":"TestOdd","Elapsed":0} +{"Time":"2024-05-25T17:06:16.987741167+09:00","Action":"run","Package":"neotest_go","Test":"Example_hello_ok"} +{"Time":"2024-05-25T17:06:16.987742665+09:00","Action":"output","Package":"neotest_go","Test":"Example_hello_ok","Output":"=== RUN Example_hello_ok\n"} +{"Time":"2024-05-25T17:06:16.987748658+09:00","Action":"output","Package":"neotest_go","Test":"Example_hello_ok","Output":"--- PASS: Example_hello_ok (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987750589+09:00","Action":"pass","Package":"neotest_go","Test":"Example_hello_ok","Elapsed":0} +{"Time":"2024-05-25T17:06:16.98775208+09:00","Action":"run","Package":"neotest_go","Test":"Example_hello_ng"} +{"Time":"2024-05-25T17:06:16.987753501+09:00","Action":"output","Package":"neotest_go","Test":"Example_hello_ng","Output":"=== RUN Example_hello_ng\n"} +{"Time":"2024-05-25T17:06:16.987755588+09:00","Action":"output","Package":"neotest_go","Test":"Example_hello_ng","Output":"--- FAIL: Example_hello_ng (0.00s)\n"} +{"Time":"2024-05-25T17:06:16.987757621+09:00","Action":"output","Package":"neotest_go","Test":"Example_hello_ng","Output":"got:\n"} +{"Time":"2024-05-25T17:06:16.987759383+09:00","Action":"output","Package":"neotest_go","Test":"Example_hello_ng","Output":"hello world\n"} +{"Time":"2024-05-25T17:06:16.987761201+09:00","Action":"output","Package":"neotest_go","Test":"Example_hello_ng","Output":"want:\n"} +{"Time":"2024-05-25T17:06:16.987762945+09:00","Action":"output","Package":"neotest_go","Test":"Example_hello_ng","Output":"NG pattern\n"} +{"Time":"2024-05-25T17:06:16.987764982+09:00","Action":"fail","Package":"neotest_go","Test":"Example_hello_ng","Elapsed":0} +{"Time":"2024-05-25T17:06:16.988651539+09:00","Action":"output","Package":"neotest_go","Output":"FAIL\n"} +{"Time":"2024-05-25T17:06:16.988706481+09:00","Action":"output","Package":"neotest_go","Output":"FAIL\tneotest_go\t0.004s\n"} +{"Time":"2024-05-25T17:06:16.988710395+09:00","Action":"fail","Package":"neotest_go","Elapsed":0.004} diff --git a/test_proj/.vim/coc-settings.json b/test_proj/.vim/coc-settings.json index 61661a8..1c61806 100644 --- a/test_proj/.vim/coc-settings.json +++ b/test_proj/.vim/coc-settings.json @@ -3,10 +3,10 @@ "testing": { "command": "testing-language-server", "trace.server": "verbose", - "filetypes": ["rust", "javascript"], + "filetypes": ["rust", "javascript", "go"], "initializationOptions": { "adapterCommand": { - ".rs": [ + "rust": [ { "path": "testing-ls-adapter", "extra_args": ["--test-kind=cargo-test"], @@ -14,13 +14,21 @@ "exclude_patterns": ["/**/target/**"] } ], - ".js": [ + "javascript": [ { "path": "testing-ls-adapter", "extra_args": ["--test-kind=jest"], "include_patterns": ["/**/*.js"], "exclude_patterns": ["/node_modules/**/*"] } + ], + "go": [ + { + "path": "testing-ls-adapter", + "extra_args": ["--test-kind=go-test"], + "include_patterns": ["/**/*.go"], + "exclude_patterns": [] + } ] } } diff --git a/test_proj/go/README.md b/test_proj/go/README.md new file mode 100644 index 0000000..5824146 --- /dev/null +++ b/test_proj/go/README.md @@ -0,0 +1 @@ +This directory is from https://github.com/nvim-neotest/neotest-go/tree/main/neotest_go. diff --git a/test_proj/go/cases.go b/test_proj/go/cases.go new file mode 100644 index 0000000..aa5c918 --- /dev/null +++ b/test_proj/go/cases.go @@ -0,0 +1,9 @@ +package main + +func add(a, b int) int { + return a + b +} + +func subtract(a, b int) int { + return a - b +} diff --git a/test_proj/go/cases_test.go b/test_proj/go/cases_test.go new file mode 100644 index 0000000..7c39201 --- /dev/null +++ b/test_proj/go/cases_test.go @@ -0,0 +1,49 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSubtract(t *testing.T) { + testCases := []struct { + desc string + a int + b int + want int + }{ + { + desc: "test one", + a: 1, + b: 2, + want: 3, + }, + { + desc: "test two", + a: 1, + b: 2, + want: 7, + }, + } + for _, tC := range testCases { + t.Run(tC.desc, func(t *testing.T) { + assert.Equal(t, tC.want, subtract(tC.a, tC.b)) + }) + } +} + +func TestAdd(t *testing.T) { + t.Run("test one", func(t *testing.T) { + assert.Equal(t, 3, add(1, 2)) + }) + + t.Run("test two", func(t *testing.T) { + assert.Equal(t, 5, add(1, 2)) + }) + + variable := "string" + t.Run(variable, func(t *testing.T) { + assert.Equal(t, 3, add(1, 2)) + }) +} diff --git a/test_proj/go/example.go b/test_proj/go/example.go new file mode 100644 index 0000000..a1f73ad --- /dev/null +++ b/test_proj/go/example.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func hello() { + fmt.Println("hello world") +} diff --git a/test_proj/go/example_test.go b/test_proj/go/example_test.go new file mode 100644 index 0000000..34ba0b0 --- /dev/null +++ b/test_proj/go/example_test.go @@ -0,0 +1,15 @@ +package main + +func Example_hello_ok() { + hello() + + // Output: + // hello world +} + +func Example_hello_ng() { + hello() + + // Output: + // NG pattern +} diff --git a/test_proj/go/go.mod b/test_proj/go/go.mod new file mode 100644 index 0000000..7e92512 --- /dev/null +++ b/test_proj/go/go.mod @@ -0,0 +1,11 @@ +module neotest_go + +go 1.18 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.4.0 // indirect + github.com/stretchr/testify v1.7.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/test_proj/go/go.sum b/test_proj/go/go.sum new file mode 100644 index 0000000..feea66e --- /dev/null +++ b/test_proj/go/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test_proj/go/main.go b/test_proj/go/main.go new file mode 100644 index 0000000..880c6bf --- /dev/null +++ b/test_proj/go/main.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + fmt.Println("hello world") +} + +func addOne(x int) int { + return x + 1 +} + +func addTwo(x int) int { + return x + 2 +} diff --git a/test_proj/go/main_tagged_test.go b/test_proj/go/main_tagged_test.go new file mode 100644 index 0000000..6269007 --- /dev/null +++ b/test_proj/go/main_tagged_test.go @@ -0,0 +1,14 @@ +//go:build files +// +build files + +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAddOne2(t *testing.T) { + assert.Equal(t, 2, addOne(1)) +} diff --git a/test_proj/go/main_test.go b/test_proj/go/main_test.go new file mode 100644 index 0000000..9b7c642 --- /dev/null +++ b/test_proj/go/main_test.go @@ -0,0 +1,15 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAddOne(t *testing.T) { + assert.Equal(t, 2, addOne(1)) +} + +func TestAddTwo(t *testing.T) { + assert.Equal(t, 3, addTwo(1)) +} diff --git a/test_proj/go/many_table_test.go b/test_proj/go/many_table_test.go new file mode 100644 index 0000000..3ee7c8c --- /dev/null +++ b/test_proj/go/many_table_test.go @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + "net/http" + "testing" +) + +func TestSomeTest(t *testing.T) { + tt := []struct { + name string + method string + url string + apiKey string + status int + }{ + {name: "AccessDenied1", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden}, + {name: "AccessDenied2", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden}, + {name: "AccessDenied3", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden}, + {name: "AccessDenied4", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden}, + {name: "AccessDenied5", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden}, + {name: "AccessDenied6", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden}, + } + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(_ *testing.T) { + fmt.Println(tc.name, tc.method, tc.url, tc.apiKey, tc.status) + }) + } + +} diff --git a/test_proj/go/map_table_test.go b/test_proj/go/map_table_test.go new file mode 100644 index 0000000..2fcba40 --- /dev/null +++ b/test_proj/go/map_table_test.go @@ -0,0 +1,40 @@ +package main + +import ( + "reflect" + "strings" + "testing" +) + +func TestSplit(t *testing.T) { + tests := map[string]struct { + input string + sep string + want []string + }{ + "simple": {input: "a/b/c", sep: "/", want: []string{"a", "b", "c"}}, + "wrong sep": {input: "a/b/c", sep: ",", want: []string{"a/b/c"}}, + "no sep": {input: "abc", sep: "/", want: []string{"abc"}}, + "trailing sep": {input: "a/b/c/", sep: "/", want: []string{"a", "b", "c"}}, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := Split(tc.input, tc.sep) + if !reflect.DeepEqual(tc.want, got) { + t.Fatalf("%s: expected: %v, got: %v", name, tc.want, got) + } + }) + } +} + +func Split(s, sep string) []string { + var result []string + i := strings.Index(s, sep) + for i > -1 { + result = append(result, s[:i]) + s = s[i+len(sep):] + i = strings.Index(s, sep) + } + return append(result, s) +} diff --git a/test_proj/go/suite_test.go b/test_proj/go/suite_test.go new file mode 100644 index 0000000..151fb00 --- /dev/null +++ b/test_proj/go/suite_test.go @@ -0,0 +1,39 @@ +package main + +// Basic imports +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +// Define the suite, and absorb the built-in basic suite +// functionality from testify - including a T() method which +// returns the current testing context +type ExampleTestSuite struct { + suite.Suite + VariableThatShouldStartAtFive int +} + +// Make sure that VariableThatShouldStartAtFive is set to five +// before each test +func (suite *ExampleTestSuite) SetupTest() { + suite.VariableThatShouldStartAtFive = 5 +} + +// All methods that begin with "Test" are run as tests within a +// suite. +func (suite *ExampleTestSuite) TestExample() { + assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive) +} + +func (suite *ExampleTestSuite) TestExampleFailure() { + assert.Equal(suite.T(), 5, 3) +} + +// In order for 'go test' to run this suite, we need to create +// a normal test function and pass our suite to suite.Run +func TestExampleTestSuite(t *testing.T) { + suite.Run(t, new(ExampleTestSuite)) +} diff --git a/test_proj/go/three_level_nested_test.go b/test_proj/go/three_level_nested_test.go new file mode 100644 index 0000000..9d3a2f9 --- /dev/null +++ b/test_proj/go/three_level_nested_test.go @@ -0,0 +1,25 @@ +package main + +import "testing" + +func TestOdd(t *testing.T) { + t.Run("odd", func(t *testing.T) { + t.Run("5 is odd", func(t *testing.T) { + if 5%2 != 1 { + t.Error("5 is actually odd") + } + t.Run("9 is odd", func(t *testing.T) { + if 9%2 != 1 { + t.Error("5 is actually odd") + } + }) + }) + t.Run("7 is odd", func(t *testing.T) { + if 7%2 != 1 { + t.Error("7 is actually odd") + } + }) + + }) + +}