├── .github ├── CODEOWNERS ├── workflows │ ├── no-response.yml │ └── build.yml └── llms.md ├── demo ├── settings.png ├── test_report.png ├── configuration.png ├── test_explorer.png ├── command_palette.png └── editor-decoration.png ├── resources └── logo.png ├── test ├── test-projects │ ├── junit │ │ ├── .vscode │ │ │ └── settings.json │ │ ├── src │ │ │ ├── main │ │ │ │ └── java │ │ │ │ │ └── junit │ │ │ │ │ └── App.java │ │ │ └── test │ │ │ │ ├── java │ │ │ │ ├── junit5 │ │ │ │ │ ├── MetaAnnotationTest.java │ │ │ │ │ ├── cucumber │ │ │ │ │ │ ├── CucumberTest.java │ │ │ │ │ │ └── CucumberSteps.java │ │ │ │ │ ├── PropertyTest.java │ │ │ │ │ ├── FastTest.java │ │ │ │ │ ├── tags │ │ │ │ │ │ └── TagTest.java │ │ │ │ │ ├── VertxTest.java │ │ │ │ │ ├── NestedTest.java │ │ │ │ │ ├── TestWithExtractedEqualityAssertion.java │ │ │ │ │ ├── AppTest.java │ │ │ │ │ ├── TestParameterizedWithStrangeComments.java │ │ │ │ │ ├── TestFactoryTest.java │ │ │ │ │ ├── ParallelExecutionTest.java │ │ │ │ │ └── ParameterizedAnnotationTest.java │ │ │ │ ├── junit4 │ │ │ │ │ ├── BaseTest.java │ │ │ │ │ ├── ExtendedTest.java │ │ │ │ │ ├── AssumeTest.java │ │ │ │ │ ├── RunWithAnnotation.java │ │ │ │ │ ├── TestAnnotation.java │ │ │ │ │ ├── ExceptionInBefore.java │ │ │ │ │ ├── TestEncoding.java │ │ │ │ │ ├── TheoryAnnotation.java │ │ │ │ │ ├── ParameterizedTest.java │ │ │ │ │ └── ParameterizedWithNameTest.java │ │ │ │ └── testng │ │ │ │ │ └── CharUtilsTest.java │ │ │ │ └── resources │ │ │ │ ├── Test.feature │ │ │ │ └── junit-platform.properties │ │ └── pom.xml │ ├── modular-gradle │ │ ├── .vscode │ │ │ └── settings.json │ │ ├── src │ │ │ ├── main │ │ │ │ └── java │ │ │ │ │ ├── module-info.java │ │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── project │ │ │ │ │ └── GradleModular.java │ │ │ └── test │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── project │ │ │ │ └── GradleModularTest.java │ │ ├── settings.gradle │ │ └── build.gradle │ ├── simple │ │ ├── src │ │ │ └── App.java │ │ └── .vscode │ │ │ └── settings.json │ └── old-testng │ │ ├── src │ │ ├── main │ │ │ └── java │ │ │ │ └── test │ │ │ │ └── project │ │ │ │ └── App.java │ │ └── test │ │ │ └── java │ │ │ └── test │ │ │ └── project │ │ │ └── AppTest.java │ │ └── pom.xml ├── suite │ ├── coverageUtils.test.ts │ ├── index.ts │ ├── utils.ts │ └── navigation.test.ts ├── unmanaged-folder-suite │ ├── index.ts │ └── enableTests.test.ts └── index.ts ├── java-extension ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── com.microsoft.java.test.plugin │ ├── .settings │ │ ├── org.eclipse.core.resources.prefs │ │ ├── org.eclipse.m2e.core.prefs │ │ └── org.eclipse.jdt.core.prefs │ ├── build.properties │ ├── .classpath │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── microsoft │ │ │ └── java │ │ │ └── test │ │ │ └── plugin │ │ │ ├── coverage │ │ │ └── model │ │ │ │ ├── BranchCoverage.java │ │ │ │ ├── MethodCoverage.java │ │ │ │ ├── LineCoverage.java │ │ │ │ └── SourceFileCoverage.java │ │ │ ├── launchers │ │ │ ├── JUnitLaunchArguments.java │ │ │ └── JUnitLaunchConfigurationTemplate.java │ │ │ ├── model │ │ │ ├── Option.java │ │ │ ├── TestLevel.java │ │ │ ├── Response.java │ │ │ └── TestKind.java │ │ │ ├── searcher │ │ │ ├── TestFrameworkSearcher.java │ │ │ ├── BaseFrameworkSearcher.java │ │ │ ├── JUnit6TestSearcher.java │ │ │ └── JUnit4TestSearcher.java │ │ │ ├── util │ │ │ ├── TestFrameworkUtils.java │ │ │ └── TestItemUtils.java │ │ │ ├── provider │ │ │ └── TestKindProvider.java │ │ │ └── handler │ │ │ └── ClasspathUpdateHandler.java │ ├── plugin.xml │ ├── .project │ ├── pom.xml │ └── META-INF │ │ └── MANIFEST.MF ├── com.microsoft.java.test.plugin.test │ ├── projects │ │ ├── simple │ │ │ └── src │ │ │ │ └── App.java │ │ └── coverage-test │ │ │ ├── jacoco.exec │ │ │ ├── src │ │ │ ├── test │ │ │ │ └── java │ │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── project │ │ │ │ │ └── SampleTests.java │ │ │ └── main │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── project │ │ │ │ └── Sample.java │ │ │ ├── .project │ │ │ ├── pom.xml │ │ │ └── .classpath │ ├── plugin.xml │ ├── build.properties │ ├── .classpath │ ├── pom.xml │ ├── META-INF │ │ └── MANIFEST.MF │ ├── src │ │ └── com │ │ │ └── microsoft │ │ │ └── java │ │ │ └── test │ │ │ └── plugin │ │ │ ├── TestPlugin.java │ │ │ ├── launchers │ │ │ └── JUnitLaunchConfigurationDelegateTest.java │ │ │ └── coverage │ │ │ └── CoverageHandlerTest.java │ └── .project ├── com.microsoft.java.test.plugin.site │ ├── category.xml │ ├── .project │ └── pom.xml ├── com.microsoft.java.test.target │ ├── pom.xml │ ├── .project │ └── com.microsoft.java.test.tp.target ├── build-tools │ ├── pom.xml │ ├── .project │ └── .classpath ├── .project ├── com.microsoft.java.test.runner │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── microsoft │ │ │ └── java │ │ │ └── test │ │ │ └── runner │ │ │ ├── common │ │ │ ├── TestMessageType.java │ │ │ ├── ITestLauncher.java │ │ │ ├── TestStream.java │ │ │ ├── Pair.java │ │ │ ├── MessageUtils.java │ │ │ ├── TestMessageItem.java │ │ │ ├── TestMessageConstants.java │ │ │ └── TestOutputStream.java │ │ │ ├── exceptions │ │ │ └── ParameterException.java │ │ │ ├── testng │ │ │ ├── TestNGRunner.java │ │ │ └── TestNGLauncher.java │ │ │ └── Launcher.java │ ├── .project │ ├── pom.xml │ └── .classpath └── LICENSE ├── .vscode ├── extensions.json ├── settings.json ├── tasks.json └── launch.json ├── extension.bundle.ts ├── javaConfig.json ├── .vscodeignore ├── src ├── runConfigs.ts ├── runners │ ├── ITestRunner.ts │ ├── junitRunner │ │ └── JunitRunner.ts │ └── testngRunner │ │ └── TestNGRunner.ts ├── commands │ ├── navigation │ │ ├── TestNavigationModel.ts │ │ ├── TestNavigationTreeDataProvider.ts │ │ └── testNavigationInput.ts │ ├── generationCommands.ts │ ├── testReportCommands.ts │ ├── testExplorerCommands.ts │ └── projectExplorerCommands.ts ├── utils │ ├── commandUtils.ts │ ├── coverageUtils.ts │ └── testItemUtils.ts ├── controller │ ├── testItemDataCache.ts │ ├── debouncing.ts │ └── testRunnerService.ts ├── types.ts ├── experimentationService.ts ├── provider │ ├── codeActionProvider.ts │ ├── JavaTestCoverageProvider.ts │ └── testSourceProvider.ts └── debugger.api.d.ts ├── main.js ├── tsconfig.json ├── .gitignore ├── scripts └── prepare-nightly-build.js ├── LICENSE.txt ├── webpack.config.js ├── .azure-pipelines ├── release.yml ├── release-nightly.yml └── vscode-java-test-ci.yml └── SECURITY.md /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | @testforstephen @chagong @wenytang-ms 2 | -------------------------------------------------------------------------------- /demo/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-java-test/HEAD/demo/settings.png -------------------------------------------------------------------------------- /resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-java-test/HEAD/resources/logo.png -------------------------------------------------------------------------------- /test/test-projects/junit/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.server.launchMode": "Standard" 3 | } -------------------------------------------------------------------------------- /demo/test_report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-java-test/HEAD/demo/test_report.png -------------------------------------------------------------------------------- /demo/configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-java-test/HEAD/demo/configuration.png -------------------------------------------------------------------------------- /demo/test_explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-java-test/HEAD/demo/test_explorer.png -------------------------------------------------------------------------------- /test/test-projects/modular-gradle/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.server.launchMode": "Standard" 3 | } -------------------------------------------------------------------------------- /demo/command_palette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-java-test/HEAD/demo/command_palette.png -------------------------------------------------------------------------------- /demo/editor-decoration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-java-test/HEAD/demo/editor-decoration.png -------------------------------------------------------------------------------- /test/test-projects/simple/src/App.java: -------------------------------------------------------------------------------- 1 | public class App { 2 | public static void main(String[] args) {} 3 | } 4 | -------------------------------------------------------------------------------- /test/test-projects/modular-gradle/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module gradle.modular { 2 | exports com.example.project; 3 | } 4 | -------------------------------------------------------------------------------- /java-extension/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-java-test/HEAD/java-extension/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/projects/simple/src/App.java: -------------------------------------------------------------------------------- 1 | public class App { 2 | public static void main(String[] args) {} 3 | } 4 | -------------------------------------------------------------------------------- /java-extension/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /test/test-projects/modular-gradle/src/main/java/com/example/project/GradleModular.java: -------------------------------------------------------------------------------- 1 | package com.example.project; 2 | 3 | public class GradleModular { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "vscjava.vscode-java-pack", 5 | "yaozheng.vscode-pde" 6 | ] 7 | } -------------------------------------------------------------------------------- /extension.bundle.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | export { activate, deactivate } from './src/extension'; 5 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/main/java/junit/App.java: -------------------------------------------------------------------------------- 1 | package junit; 2 | 3 | public class App { 4 | public String getGreeting() { 5 | return "Hello world."; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/MetaAnnotationTest.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | public class MetaAnnotationTest { 4 | @FastTest 5 | void myFastTest() { 6 | } 7 | } -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.site/category.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/build.properties: -------------------------------------------------------------------------------- 1 | source.. = src/main/java 2 | output.. = target/classes 3 | bin.includes = META-INF/,\ 4 | .,\ 5 | plugin.xml 6 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit4/BaseTest.java: -------------------------------------------------------------------------------- 1 | package junit4; 2 | 3 | import org.junit.Test; 4 | 5 | public class BaseTest { 6 | @Test 7 | public void test() { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/resources/Test.feature: -------------------------------------------------------------------------------- 1 | Feature: The calculator application 2 | Scenario: client wants to add 2 numbers 3 | When the client add 2 and 4 4 | Then the result should be 6 -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/build.properties: -------------------------------------------------------------------------------- 1 | source.. = src/ 2 | output.. = target/classes/ 3 | bin.includes = META-INF/,\ 4 | .,\ 5 | plugin.xml 6 | src.includes = projects 7 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/projects/coverage-test/jacoco.exec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/vscode-java-test/HEAD/java-extension/com.microsoft.java.test.plugin.test/projects/coverage-test/jacoco.exec -------------------------------------------------------------------------------- /test/test-projects/simple/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.server.launchMode": "Standard", 3 | "java.project.sourcePaths": ["src"], 4 | "java.project.referencedLibraries": [ 5 | "lib/**/*.jar" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit4/ExtendedTest.java: -------------------------------------------------------------------------------- 1 | package junit4; 2 | 3 | import org.junit.Test; 4 | 5 | public class ExtendedTest extends BaseTest { 6 | @Test 7 | public void extendedTest() { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/test-projects/modular-gradle/src/test/java/com/example/project/GradleModularTest.java: -------------------------------------------------------------------------------- 1 | package com.example.project; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | class GradleModularTest { 6 | 7 | @Test 8 | void test() { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /javaConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "projects": [ 3 | "./java-extension/com.microsoft.java.test.plugin", 4 | "./java-extension/com.microsoft.java.test.plugin.test" 5 | ], 6 | "targetPlatform": "./java-extension/com.microsoft.java.test.target/com.microsoft.java.test.tp.target" 7 | } 8 | -------------------------------------------------------------------------------- /test/test-projects/old-testng/src/main/java/test/project/App.java: -------------------------------------------------------------------------------- 1 | package test.project; 2 | 3 | /** 4 | * Hello world! 5 | * 6 | */ 7 | public class App 8 | { 9 | public static void main( String[] args ) 10 | { 11 | System.out.println( "Hello World!" ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit4/AssumeTest.java: -------------------------------------------------------------------------------- 1 | package junit4; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assume.assumeTrue; 6 | 7 | public class AssumeTest { 8 | @Test 9 | public void shouldSkip() { 10 | assumeTrue(false); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/test-projects/modular-gradle/settings.gradle: -------------------------------------------------------------------------------- 1 | 2 | pluginManagement { 3 | 4 | repositories { 5 | maven({ 6 | url "https://plugins.gradle.org/m2/" 7 | }) 8 | gradlePluginPortal() 9 | mavenLocal() 10 | } 11 | } 12 | rootProject.name = 'gradle-modular' 13 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit4/RunWithAnnotation.java: -------------------------------------------------------------------------------- 1 | package junit4; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.junit.runners.Suite; 5 | import org.junit.runners.Suite.SuiteClasses; 6 | 7 | @RunWith(Suite.class) 8 | @SuiteClasses({TestAnnotation.class}) 9 | public class RunWithAnnotation { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/cucumber/CucumberTest.java: -------------------------------------------------------------------------------- 1 | package junit5.cucumber; 2 | 3 | import io.cucumber.junit.Cucumber; 4 | import io.cucumber.junit.CucumberOptions; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(Cucumber.class) 8 | @CucumberOptions(features = "src/test/resources") 9 | public class CucumberTest {} -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/PropertyTest.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | import net.jqwik.api.ForAll; 4 | import net.jqwik.api.Property; 5 | 6 | public class PropertyTest { 7 | @Property 8 | boolean absoluteValueOfIntegerAlwaysPositive(@ForAll int anInteger) { 9 | return Math.abs(anInteger) >= 0; 10 | } 11 | } -------------------------------------------------------------------------------- /test/test-projects/modular-gradle/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | dependencies { 10 | testImplementation('org.junit.jupiter:junit-jupiter:5.6.0') 11 | } 12 | 13 | test { 14 | useJUnitPlatform() 15 | testLogging { 16 | events "passed", "skipped", "failed" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/projects/coverage-test/src/test/java/com/example/project/SampleTests.java: -------------------------------------------------------------------------------- 1 | package com.example.project; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertTrue; 6 | 7 | class SampleTests { 8 | 9 | @Test 10 | void test() { 11 | assertTrue(true); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit4/TestAnnotation.java: -------------------------------------------------------------------------------- 1 | package junit4; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertTrue; 6 | 7 | public class TestAnnotation { 8 | @Test 9 | public void shouldPass() { 10 | assertTrue(true); 11 | } 12 | 13 | @Test 14 | public void shouldFail() { 15 | assertTrue(false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit4/ExceptionInBefore.java: -------------------------------------------------------------------------------- 1 | package junit4; 2 | 3 | import org.junit.BeforeClass; 4 | import org.junit.Test; 5 | 6 | /** 7 | * ExceptionInBefore 8 | */ 9 | public class ExceptionInBefore { 10 | 11 | @BeforeClass 12 | public static void beforeClass() throws Exception { 13 | throw new Exception("Exception in @BeforeClass"); 14 | }; 15 | 16 | @Test 17 | public void test() { 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/FastTest.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import org.junit.jupiter.api.Tag; 9 | import org.junit.jupiter.api.Test; 10 | 11 | @Target(ElementType.METHOD) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Tag("fast") 14 | @Test 15 | public @interface FastTest { 16 | } -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/resources/junit-platform.properties: -------------------------------------------------------------------------------- 1 | junit.jupiter.execution.parallel.enabled = true 2 | # run all test sequentially by default 3 | # can be changed e.g. by annotating certain classes with @Execution(ExecutionMode.CONCURRENT) 4 | junit.jupiter.execution.parallel.mode.default = same_thread 5 | junit.jupiter.execution.parallel.mode.classes.default = same_thread 6 | # run at least 3 tests in parallel 7 | junit.jupiter.execution.parallel.config.dynamic.factor = 3 8 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | tslint.json 10 | package-lock.json 11 | java-extension/** 12 | scripts/** 13 | resources/templates/scss/** 14 | dist/**/test 15 | webpack.*.js 16 | node_modules 17 | **/*.log 18 | demo 19 | CONTRIBUTING.md 20 | extension.bundle.ts 21 | javaConfig.json 22 | .github/** 23 | .azure-pipelines/** 24 | vscode.d.ts 25 | 26 | # Ignore output of code sign 27 | server/*.md 28 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.release=disabled 8 | org.eclipse.jdt.core.compiler.source=1.8 9 | -------------------------------------------------------------------------------- /src/runConfigs.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { Configurations } from './constants'; 5 | import { IExecutionConfig } from './java-test-runner.api'; 6 | 7 | export function getBuiltinConfig(): IExecutionConfig { 8 | return Object.assign({}, BUILTIN_CONFIG); 9 | } 10 | 11 | const BUILTIN_CONFIG: IExecutionConfig = { 12 | name: Configurations.BUILTIN_CONFIG_NAME, 13 | workingDirectory: '${workspaceFolder}', 14 | }; 15 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit4/TestEncoding.java: -------------------------------------------------------------------------------- 1 | package junit4; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | import java.nio.charset.Charset; 8 | 9 | /** 10 | * The test case in this class will fail unless you set `java.test.config : encoding` to ISO-8859-1 11 | */ 12 | public class TestEncoding { 13 | @Test 14 | public void latin1IsSet() { 15 | assertEquals( 16 | "ISO-8859-1", 17 | Charset.defaultCharset().name() 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/tags/TagTest.java: -------------------------------------------------------------------------------- 1 | package junit5.tags; 2 | 3 | import org.junit.jupiter.api.Tag; 4 | import org.junit.jupiter.api.Test; 5 | 6 | @Tag("unit") 7 | interface IBase {} 8 | 9 | @Tag("integration") 10 | class Base {} 11 | 12 | public class TagTest extends Base implements IBase { 13 | 14 | @Test 15 | @Tag("fast") 16 | void fastTest() { 17 | } 18 | 19 | @Test 20 | @Tag("slow") 21 | void slowTest() throws InterruptedException { 22 | Thread.sleep(2000); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/cucumber/CucumberSteps.java: -------------------------------------------------------------------------------- 1 | package junit5.cucumber; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import io.cucumber.java.en.Then; 6 | import io.cucumber.java.en.When; 7 | 8 | public class CucumberSteps { 9 | 10 | @When("the client add {int} and {int}") 11 | public void addNumbers(Integer int1, Integer int2) { 12 | } 13 | 14 | @Then("the result should be {int}") 15 | public void checkSumValue(Integer value) { 16 | assertEquals(value + 1, 6); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | "use strict"; 5 | 6 | Object.defineProperty(exports, "__esModule", { value: true }); 7 | 8 | const extension = require("./dist/extension.bundle"); 9 | 10 | async function activate(ctx) { 11 | return await extension.activate(ctx); 12 | } 13 | 14 | async function deactivate(ctx) { 15 | return await extension.deactivate(ctx); 16 | } 17 | 18 | // Export as entrypoints for vscode 19 | exports.activate = activate; 20 | exports.deactivate = deactivate; 21 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/VertxTest.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | import io.vertx.core.Vertx; 4 | import io.vertx.junit5.VertxExtension; 5 | import io.vertx.junit5.VertxTestContext; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | 9 | @ExtendWith(VertxExtension.class) 10 | public class VertxTest { 11 | 12 | // test normal methods with multiple parameters 13 | @Test 14 | void test(Vertx vertx, VertxTestContext testContext) throws InterruptedException { 15 | testContext.completeNow(); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/runners/ITestRunner.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { CancellationToken, DebugConfiguration } from 'vscode'; 5 | import { IProgressReporter } from '../debugger.api'; 6 | import { IRunTestContext } from '../java-test-runner.api'; 7 | 8 | export interface ITestRunnerInternal { 9 | setup(context: IRunTestContext): Promise; 10 | run(launchConfiguration: DebugConfiguration, token: CancellationToken, progressReporter?: IProgressReporter): Promise; 11 | tearDown(isCancel: boolean): Promise; 12 | } 13 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.target/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.microsoft.java.test 6 | parent 7 | 0.43.1 8 | 9 | com.microsoft.java.test.tp 10 | ${base.name} :: Target Platform 11 | eclipse-target-definition 12 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/NestedTest.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertTrue; 4 | 5 | import org.junit.jupiter.api.*; 6 | 7 | class NestedTest { 8 | @Nested 9 | class NestedClassA { 10 | @Test 11 | public void test() { } 12 | 13 | } 14 | 15 | @Nested 16 | class NestedClassB { 17 | @Test 18 | void test() { } 19 | 20 | @Nested 21 | class ADeeperClass { 22 | @Test 23 | void test() { 24 | assertTrue(false); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/TestWithExtractedEqualityAssertion.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | class TestWithExtractedEqualityAssertion { 7 | 8 | @Test 9 | void test() { 10 | } 11 | 12 | @Test 13 | void test1() { 14 | extracted1(); 15 | } 16 | 17 | @Test 18 | void test2() { 19 | extracted2(); 20 | } 21 | 22 | private void extracted1() { 23 | extracted2(); 24 | } 25 | 26 | private void extracted2() { 27 | Assertions.assertEquals(1, 2); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /test/test-projects/old-testng/src/test/java/test/project/AppTest.java: -------------------------------------------------------------------------------- 1 | package test.project; 2 | 3 | import org.testng.annotations.DataProvider; 4 | import org.testng.annotations.Test; 5 | 6 | /** 7 | * Unit test for simple App. 8 | */ 9 | public class AppTest { 10 | @DataProvider(name = "test1") 11 | public Object[][] createData1() { 12 | return new Object[][] { 13 | { "Cedric", "" }, 14 | { "Anne", "" }, 15 | }; 16 | } 17 | 18 | @Test(dataProvider = "test1") 19 | public void test(String foo, String bar) { 20 | System.out.println(foo + " " + bar); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6", 8 | "DOM" 9 | ], 10 | "sourceMap": true, 11 | "rootDir": ".", 12 | "noUnusedLocals": true, 13 | "noImplicitThis": true, 14 | "noImplicitAny": true, 15 | "noImplicitReturns": true, 16 | "noUnusedParameters": true, 17 | "strictNullChecks": true, 18 | "alwaysStrict": true 19 | }, 20 | "exclude": [ 21 | "node_modules", 22 | ".vscode-test" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.configuration.updateBuildConfiguration": "automatic", 3 | "maven.excludedFolders": [ 4 | "**/.*", 5 | "**/node_modules", 6 | "**/target", 7 | "**/bin", 8 | "**/test/test-projects" 9 | ], 10 | "java.import.exclusions": [ 11 | "**/node_modules/**", 12 | "**/.metadata/**", 13 | "**/archetype-resources/**", 14 | "**/META-INF/maven/**", 15 | "**/test/test-projects/**" 16 | ], 17 | "java.checkstyle.version": "8.18", 18 | "java.checkstyle.configuration": "${workspaceFolder}/java-extension/build-tools/src/main/resources/checkstyle/checkstyle.xml", 19 | } -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/AppTest.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | import static org.junit.jupiter.api.Assertions.fail; 4 | 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.params.ParameterizedTest; 7 | import org.junit.jupiter.params.provider.CsvSource; 8 | 9 | public class AppTest { 10 | @Test 11 | void testGetGreeting() { 12 | 13 | } 14 | 15 | @ParameterizedTest 16 | @CsvSource({ 17 | "1, 2", 18 | "1, 1" 19 | }) 20 | public void testGetGreeting(int first, int second) throws Exception { 21 | if (second == 2) { 22 | fail("second should not be 2"); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /java-extension/build-tools/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | com.microsoft.java.test 9 | parent 10 | 0.43.1 11 | 12 | com.microsoft.java.test 13 | test-runner-build-tools 14 | 1.0.0 15 | ${base.name} :: Build Tools 16 | 17 | -------------------------------------------------------------------------------- /test/test-projects/old-testng/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | test.project 5 | test 6 | jar 7 | 1.0-SNAPSHOT 8 | test 9 | http://maven.apache.org 10 | 11 | 12 | org.testng 13 | testng 14 | 6.9.13.3 15 | test 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /java-extension/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | parent 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.m2e.core.maven2Builder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.m2e.core.maven2Nature 16 | 17 | 18 | 19 | 1695883255108 20 | 21 | 30 22 | 23 | org.eclipse.core.resources.regexFilterMatcher 24 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/common/TestMessageType.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.common; 13 | 14 | public enum TestMessageType { 15 | Info, 16 | Error, 17 | } 18 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/common/ITestLauncher.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.common; 13 | 14 | public interface ITestLauncher { 15 | void execute(String[] args); 16 | } 17 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/common/TestStream.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.common; 13 | 14 | public interface TestStream { 15 | void println(TestMessageItem item); 16 | 17 | void close(); 18 | } 19 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.target/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.microsoft.java.test.tp 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.m2e.core.maven2Builder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.m2e.core.maven2Nature 16 | 17 | 18 | 19 | 1695883255106 20 | 21 | 30 22 | 23 | org.eclipse.core.resources.regexFilterMatcher 24 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.site/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.microsoft.java.test.plugin.site 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.m2e.core.maven2Builder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.m2e.core.maven2Nature 16 | 17 | 18 | 19 | 1695883255098 20 | 21 | 30 22 | 23 | org.eclipse.core.resources.regexFilterMatcher 24 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/TestParameterizedWithStrangeComments.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | import org.junit.jupiter.params.ParameterizedTest; 4 | import org.junit.jupiter.params.provider.CsvSource; 5 | 6 | class TestParameterizedWithStrangeComments { 7 | //FORMER_TEST_PARAMS 8 | //@CsvSource( 9 | // {",must not be null", 10 | // "0L,size must be between 1 and 999999999"}) 11 | //@ParameterizedTest 12 | 13 | /** 14 | * [RequestContext.sessionId] 15 | * Tests all invalid scenarios for requestContext.logonId. 16 | */ 17 | @CsvSource(delimiter = '|', textBlock = """ 18 | -1 | size must be between 1 and 999999999 19 | """) 20 | @ParameterizedTest 21 | void whenInvalidReqCtxSessionId(Long __INPUT, String __EXPECTED) throws Exception { 22 | assert(true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/commands/navigation/TestNavigationModel.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { Uri, Position, Location } from 'vscode'; 5 | import { SymbolItemNavigation } from '../../references-view'; 6 | import { ITestNavigationItem } from './navigationCommands'; 7 | 8 | export class TestNavigationModel implements SymbolItemNavigation { 9 | nearest(): ITestNavigationItem | undefined { 10 | return undefined 11 | } 12 | 13 | next(from: ITestNavigationItem): ITestNavigationItem { 14 | return from; 15 | } 16 | 17 | previous(from: ITestNavigationItem): ITestNavigationItem { 18 | return from; 19 | } 20 | 21 | location(item: ITestNavigationItem): Location | undefined { 22 | return new Location(Uri.file(item.uri), new Position(0, 0)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit4/TheoryAnnotation.java: -------------------------------------------------------------------------------- 1 | package junit4; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.experimental.theories.DataPoints; 6 | import org.junit.experimental.theories.Theories; 7 | import org.junit.experimental.theories.Theory; 8 | import org.junit.runner.RunWith; 9 | 10 | @RunWith(Theories.class) 11 | public class TheoryAnnotation { 12 | @DataPoints 13 | public static int[] testIntegers() { 14 | return new int[]{ 1, 1 }; 15 | } 16 | 17 | @DataPoints 18 | public static String[] testStrings() { 19 | return new String[]{ "1", "2" }; 20 | } 21 | 22 | @Theory 23 | public void shouldPass(Integer a, Integer b) { 24 | assertEquals(a, b); 25 | } 26 | 27 | @Theory 28 | public void shouldFail(String a, String b) { 29 | assertEquals(a, b); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | **/test-launch.config 7 | 8 | # BlueJ files 9 | *.ctxt 10 | 11 | # Mobile Tools for Java (J2ME) 12 | .mtj.tmp/ 13 | 14 | # Package Files # 15 | *.jar 16 | *.war 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | *.iml 22 | **/*.vsix 23 | 24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 25 | hs_err_pid* 26 | 27 | 28 | **/.idea/ 29 | **/.gradle 30 | **/node_modules/ 31 | .DS_Store 32 | target/ 33 | .settings 34 | test/**/.classpath 35 | test/**/.project 36 | **/.checkstyle 37 | target/ 38 | bin/ 39 | **/lib/ 40 | out/ 41 | server/ 42 | .jqwik-database 43 | 44 | jdtls/ 45 | 46 | !java-extension/.mvn/wrapper/maven-wrapper.jar 47 | 48 | out 49 | node_modules 50 | *.vsix 51 | .vscode-test 52 | resources/templates/css/** 53 | resources/templates/js/** 54 | resources/templates/fonts/** 55 | dist -------------------------------------------------------------------------------- /scripts/prepare-nightly-build.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | const json = JSON.parse(fs.readFileSync("./package.json").toString()); 4 | const stableVersion = json.version.match(/(\d+)\.(\d+)\.(\d+)/); 5 | const major = stableVersion[1]; 6 | const minor = stableVersion[2]; 7 | 8 | function prependZero(number) { 9 | if (number > 99) { 10 | throw "Unexpected value to prepend with zero"; 11 | } 12 | return `${number < 10 ? "0" : ""}${number}`; 13 | } 14 | 15 | const date = new Date(); 16 | const month = date.getMonth() + 1; 17 | const day = date.getDate(); 18 | const hours = date.getHours(); 19 | patch = `${date.getFullYear()}${prependZero(month)}${prependZero(day)}${prependZero(hours)}`; 20 | 21 | const insiderPackageJson = Object.assign(json, { 22 | version: `${major}.${minor}.${patch}`, 23 | }); 24 | 25 | fs.writeFileSync("./package.insiders.json", JSON.stringify(insiderPackageJson)); -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/exceptions/ParameterException.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.exceptions; 13 | 14 | public class ParameterException extends RuntimeException { 15 | public ParameterException(String errorMessage) { 16 | super(errorMessage); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/commandUtils.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { commands } from 'vscode'; 5 | import { sendError } from 'vscode-extension-telemetry-wrapper'; 6 | import { JavaLanguageServerCommands } from '../constants'; 7 | 8 | export async function executeJavaLanguageServerCommand(...rest: any[]): Promise { 9 | try { 10 | return await commands.executeCommand(JavaLanguageServerCommands.EXECUTE_WORKSPACE_COMMAND, ...rest); 11 | } catch (error) { 12 | if (isCancelledError(error)) { 13 | return; 14 | } 15 | sendError(error); 16 | throw error; 17 | } 18 | } 19 | 20 | function isCancelledError(error: any): boolean { 21 | // See: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#responseMessage 22 | return error.code === -32800; 23 | } 24 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit4/ParameterizedTest.java: -------------------------------------------------------------------------------- 1 | package junit4; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.junit.runners.Parameterized; 6 | import java.util.Arrays; 7 | import java.util.Collection; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | @RunWith(Parameterized.class) 12 | public class ParameterizedTest { 13 | private int input; 14 | private int expected; 15 | 16 | public ParameterizedTest(int input, int expected) { 17 | this.input = input; 18 | this.expected = expected; 19 | } 20 | 21 | @Parameterized.Parameters 22 | public static Collection data() { 23 | return Arrays.asList(new Object[][] { 24 | { 0, 0 }, 25 | { 1, 1 }, 26 | { 2, 4 } 27 | }); 28 | } 29 | 30 | @Test 31 | public void testSquare() { 32 | assertEquals(expected, input * input); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/common/Pair.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.common; 13 | 14 | public final class Pair { 15 | public final String first; 16 | public final String second; 17 | 18 | public Pair(String first, String second) { 19 | this.first = first; 20 | this.second = second; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.microsoft.java.test 7 | parent 8 | 0.43.1 9 | 10 | com.microsoft.java.test.plugin.test 11 | eclipse-test-plugin 12 | ${base.name} :: Plugin Tests 13 | 14 | 15 | 16 | 17 | org.eclipse.tycho 18 | tycho-maven-plugin 19 | ${tycho-version} 20 | true 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/testng/CharUtilsTest.java: -------------------------------------------------------------------------------- 1 | package testng; 2 | 3 | import org.testng.Assert; 4 | import org.testng.annotations.DataProvider; 5 | import org.testng.annotations.Test; 6 | 7 | public class CharUtilsTest { 8 | 9 | @DataProvider 10 | public Object[][] ValidDataProvider() { 11 | return new Object[][] { 12 | { 'A', 65 }, { 'a', 97 }, 13 | { 'B', 66 }, { 'b', 98 }, 14 | { 'C', 67 }, { 'c', 99 }, 15 | { 'D', 68 }, { 'd', 100 }, 16 | { 'Z', 90 }, { 'z', 122 }, 17 | { '1', 49 }, { '9', 517 } 18 | 19 | }; 20 | } 21 | 22 | @Test(dataProvider = "ValidDataProvider") 23 | public void CharToASCIITest(final char character, final int ascii) { 24 | int result = (int) character; 25 | Assert.assertEquals(result, ascii); 26 | } 27 | 28 | @Test 29 | public void CharToASCIITest() { 30 | Assert.assertEquals(1, 2); 31 | } 32 | } -------------------------------------------------------------------------------- /java-extension/build-tools/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | test-runner-build-tools 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | 25 | 1695883255110 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/suite/coverageUtils.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | 'use strict'; 5 | 6 | import * as assert from 'assert'; 7 | import * as coverageUtils from '../../src/utils/coverageUtils'; 8 | import { DebugConfiguration } from 'vscode'; 9 | 10 | // tslint:disable: only-arrow-functions 11 | // tslint:disable: no-object-literal-type-assertion 12 | suite('CoverageUtils Tests', () => { 13 | 14 | test('Use project jacoco agent if it is available', async () => { 15 | const debugConfiguration: DebugConfiguration = { 16 | name: 'Tests', 17 | type: 'java', 18 | request: 'launch', 19 | classPaths: [ 20 | '/foo/bar/org.jacoco.agent-1.2.3-runtime.jar', 21 | ] 22 | } 23 | assert.strictEqual( 24 | coverageUtils.getJacocoAgentPath(debugConfiguration), 25 | '/foo/bar/org.jacoco.agent-1.2.3-runtime.jar' 26 | ); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.microsoft.java.test.runner 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | 25 | 1695883255103 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /.github/workflows/no-response.yml: -------------------------------------------------------------------------------- 1 | name: No Response 2 | 3 | # **What it does**: Closes issues where the original author doesn't respond to a request for information. 4 | # **Why we have it**: To remove the need for maintainers to remember to check back on issues periodically to see if contributors have responded. 5 | 6 | on: 7 | issue_comment: 8 | types: [created] 9 | schedule: 10 | # every morning at 5:30 AM 11 | - cron: '30 5 * * *' 12 | 13 | jobs: 14 | noResponse: 15 | runs-on: ubuntu-latest 16 | permissions: 17 | issues: write 18 | steps: 19 | - uses: lee-dohm/no-response@9bb0a4b5e6a45046f00353d5de7d90fb8bd773bb #v0.5.0 20 | with: 21 | token: ${{ github.token }} 22 | daysUntilClose: 14 23 | responseRequiredLabel: "need more info" 24 | closeComment: > 25 | This issue has been closed automatically because it needs more information and has not had recent activity. Please reach out if you have or find the answers we need so that we can investigate further. -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/projects/coverage-test/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | coverage-test 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | 25 | 1709104275722 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/coverage/model/BranchCoverage.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2023 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.coverage.model; 13 | 14 | public class BranchCoverage { 15 | int hit; 16 | 17 | public BranchCoverage(int hit) { 18 | this.hit = hit; 19 | } 20 | 21 | public int getHit() { 22 | return hit; 23 | } 24 | 25 | public void setHit(int hit) { 26 | this.hit = hit; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit4/ParameterizedWithNameTest.java: -------------------------------------------------------------------------------- 1 | package junit4; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collection; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.junit.runners.Parameterized; 11 | import org.junit.runners.Parameterized.Parameter; 12 | import org.junit.runners.Parameterized.Parameters; 13 | 14 | @RunWith(Parameterized.class) 15 | public class ParameterizedWithNameTest { 16 | 17 | @Parameter 18 | public int expected; 19 | 20 | @Parameters(name = "{index}: expect={0}") 21 | public static Collection data() { 22 | // If using the name annotation param and one of the inputs has a rounded 23 | // bracket, e.g. @Parameters(name = "test({index})"), then the test name needs 24 | // to be properly handled. 25 | return Arrays.asList(1, 2, "normalString", "()", "(()"); 26 | } 27 | 28 | @Test 29 | public void test() { 30 | assertEquals(expected, 1); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Automatic-Module-Name: com.microsoft.java.test.plugin.test 4 | Bundle-Name: %Bundle-Name 5 | Bundle-SymbolicName: com.microsoft.java.test.plugin.test;singleton:=true 6 | Bundle-Version: 0.43.1 7 | Bundle-RequiredExecutionEnvironment: JavaSE-17 8 | Import-Package: org.osgi.framework;version="1.3.0" 9 | Bundle-Localization: plugin 10 | Bundle-ActivationPolicy: lazy 11 | Require-Bundle: org.eclipse.jdt.ls.core, 12 | com.microsoft.java.test.plugin, 13 | org.junit, 14 | org.apache.commons.commons-io;bundle-version="2.12.0", 15 | org.eclipse.core.resources, 16 | org.eclipse.core.runtime, 17 | org.eclipse.jdt.core, 18 | org.apache.commons.lang3, 19 | org.eclipse.jdt.core.manipulation, 20 | org.mockito.mockito-core, 21 | org.eclipse.jdt.launching, 22 | org.eclipse.jdt.junit.core, 23 | org.eclipse.debug.core, 24 | org.eclipse.m2e.core, 25 | org.eclipse.buildship.core 26 | Bundle-Vendor: %Bundle-Vendor 27 | Bundle-Activator: com.microsoft.java.test.plugin.TestPlugin 28 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/src/com/microsoft/java/test/plugin/TestPlugin.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2023 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin; 13 | 14 | import org.osgi.framework.BundleActivator; 15 | import org.osgi.framework.BundleContext; 16 | 17 | /** 18 | * TestPlugin 19 | */ 20 | public class TestPlugin implements BundleActivator { 21 | 22 | @Override 23 | public void start(BundleContext context) throws Exception { 24 | } 25 | 26 | @Override 27 | public void stop(BundleContext context) throws Exception { 28 | } 29 | } -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchArguments.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2023 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.launchers; 13 | 14 | /** 15 | * public for testing purpose. 16 | */ 17 | public class JUnitLaunchArguments { 18 | public String workingDirectory; 19 | public String mainClass; 20 | public String projectName; 21 | public String[] classpath; 22 | public String[] modulepath; 23 | public String[] vmArguments; 24 | public String[] programArguments; 25 | } 26 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern":[ 12 | { 13 | "regexp": "\\[tsl\\] ERROR", 14 | "file": 1, 15 | "location": 2, 16 | "message": 3 17 | } 18 | ], 19 | "background": { 20 | "activeOnStart": true, 21 | "beginsPattern": "\\w+", 22 | "endsPattern": "webpack .* compiled" 23 | } 24 | }, 25 | "isBackground": true, 26 | "presentation": { 27 | "reveal": "never" 28 | }, 29 | "group": { 30 | "kind": "build", 31 | "isDefault": true 32 | } 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /src/controller/testItemDataCache.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { TestItem } from 'vscode'; 5 | import { TestKind, TestLevel } from '../java-test-runner.api'; 6 | 7 | /** 8 | * A map cache to save the metadata of the test item. 9 | * Use a WeakMap here so the key-value will be automatically collected when 10 | * the actual item is disposed. 11 | */ 12 | class TestItemDataCache { 13 | private cache: WeakMap = new WeakMap(); 14 | 15 | public set(item: TestItem, data: ITestItemData): void { 16 | this.cache.set(item, data); 17 | } 18 | 19 | public get(item: TestItem): ITestItemData | undefined { 20 | return this.cache.get(item); 21 | } 22 | 23 | public delete(item: TestItem): boolean { 24 | return this.cache.delete(item); 25 | } 26 | } 27 | 28 | export const dataCache: TestItemDataCache = new TestItemDataCache(); 29 | 30 | export interface ITestItemData { 31 | jdtHandler: string; 32 | fullName: string; 33 | projectName: string; 34 | testLevel: TestLevel; 35 | testKind: TestKind; 36 | uniqueId?: string; 37 | } 38 | -------------------------------------------------------------------------------- /src/controller/debouncing.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as LRUCache from 'lru-cache'; 5 | import { Uri } from 'vscode'; 6 | 7 | export const lruCache: LRUCache = new LRUCache({max: 32}); 8 | 9 | // See: https://github.com/microsoft/vscode/blob/94c9ea46838a9a619aeafb7e8afd1170c967bb55/src/vs/base/common/numbers.ts 10 | export class MovingAverage { 11 | 12 | private _n: number = 1; 13 | private _val: number = 0; 14 | 15 | public update(value: number): this { 16 | this._val = this._val + (value - this._val) / this._n; 17 | this._n += 1; 18 | return this; 19 | } 20 | 21 | public get value(): number { 22 | return this._val; 23 | } 24 | } 25 | 26 | export function getRequestDelay(uri: Uri): number { 27 | const avg: MovingAverage | undefined = lruCache.get(uri); 28 | if (!avg) { 29 | return 350; 30 | } 31 | // See: https://github.com/microsoft/vscode/blob/94c9ea46838a9a619aeafb7e8afd1170c967bb55/src/vs/editor/common/modes/languageFeatureRegistry.ts#L204 32 | return Math.max(350, Math.floor(1.3 * avg.value)); 33 | } 34 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { Range } from 'vscode'; 5 | import { TestKind, TestLevel } from './java-test-runner.api'; 6 | 7 | export interface IJavaTestItem { 8 | children: IJavaTestItem[]; 9 | uri: string | undefined; 10 | range: Range | undefined; 11 | jdtHandler: string; 12 | fullName: string; 13 | label: string; 14 | id: string; 15 | projectName: string; 16 | testKind: TestKind; 17 | testLevel: TestLevel; 18 | /** 19 | * Provides a hint to the UI on how to sort tests. 20 | */ 21 | sortText?: string; 22 | /** 23 | * Identifies a single invocation of a parameterized test. 24 | * Invocations for which a re-run is possible store their own uniqueId which is provided as part of the result. 25 | * Methods may store it in order to specify a certain parameter-set to be used when running again. 26 | */ 27 | uniqueId?: string; 28 | /** 29 | * Optional fields for projects 30 | */ 31 | natureIds?: string[]; 32 | } 33 | 34 | export enum ProjectType { 35 | Gradle, 36 | Maven, 37 | UnmanagedFolder, 38 | Other, 39 | } 40 | -------------------------------------------------------------------------------- /java-extension/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE -------------------------------------------------------------------------------- /test/suite/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as glob from 'glob'; 5 | import * as Mocha from 'mocha'; 6 | import * as path from 'path'; 7 | 8 | export function run(): Promise { 9 | // Create the mocha test 10 | const mocha = new Mocha({ 11 | ui: 'tdd', 12 | color: true, 13 | timeout: 1 * 60 * 1000, 14 | }); 15 | 16 | const testsRoot = __dirname; 17 | 18 | return new Promise((c, e) => { 19 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 20 | if (err) { 21 | return e(err); 22 | } 23 | 24 | // Add files to the test suite 25 | files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); 26 | 27 | try { 28 | // Run the mocha test 29 | mocha.run((failures) => { 30 | if (failures > 0) { 31 | e(new Error(`${failures} tests failed.`)); 32 | } else { 33 | c(); 34 | } 35 | }); 36 | } catch (err) { 37 | e(err); 38 | } 39 | }); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /test/unmanaged-folder-suite/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as glob from 'glob'; 5 | import * as Mocha from 'mocha'; 6 | import * as path from 'path'; 7 | 8 | export function run(): Promise { 9 | // Create the mocha test 10 | const mocha = new Mocha({ 11 | ui: 'tdd', 12 | color: true, 13 | timeout: 1 * 60 * 1000, 14 | }); 15 | 16 | const testsRoot = __dirname; 17 | 18 | return new Promise((c, e) => { 19 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 20 | if (err) { 21 | return e(err); 22 | } 23 | 24 | // Add files to the test suite 25 | files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); 26 | 27 | try { 28 | // Run the mocha test 29 | mocha.run((failures) => { 30 | if (failures > 0) { 31 | e(new Error(`${failures} tests failed.`)); 32 | } else { 33 | c(); 34 | } 35 | }); 36 | } catch (err) { 37 | e(err); 38 | } 39 | }); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /src/commands/generationCommands.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { TextEdit, Uri, window, workspace, WorkspaceEdit } from 'vscode'; 5 | import * as protocolConverter from 'vscode-languageclient/lib/protocolConverter'; 6 | import { JavaTestRunnerDelegateCommands } from '../constants'; 7 | import { executeJavaLanguageServerCommand } from '../utils/commandUtils'; 8 | 9 | const converter: protocolConverter.Converter = protocolConverter.createConverter(); 10 | export async function generateTests(uri: Uri, cursorOffset: number): Promise { 11 | const edit: WorkspaceEdit = converter.asWorkspaceEdit(await askServerToGenerateTests(uri, cursorOffset)); 12 | if (edit) { 13 | await workspace.applyEdit(edit); 14 | const entries: [Uri, TextEdit[]][] = edit.entries(); 15 | if (entries?.[0]?.[0]) { 16 | await window.showTextDocument(entries[0][0], { 17 | preserveFocus: true, 18 | }); 19 | } 20 | } 21 | } 22 | 23 | async function askServerToGenerateTests(uri: Uri, cursorOffset: number): Promise { 24 | return await executeJavaLanguageServerCommand(JavaTestRunnerDelegateCommands.GENERATE_TESTS, uri.toString(), cursorOffset); 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/navigation/TestNavigationTreeDataProvider.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { ProviderResult, TreeDataProvider, TreeItem, Uri } from 'vscode'; 5 | import { ITestNavigationItem } from './navigationCommands'; 6 | 7 | export class TestNavigationTreeDataProvider implements TreeDataProvider { 8 | items: ITestNavigationItem[] 9 | 10 | constructor(items: ITestNavigationItem[]) { 11 | this.items = items; 12 | } 13 | 14 | getTreeItem(element: ITestNavigationItem): TreeItem | Thenable { 15 | const treeItem: TreeItem = new TreeItem(element.simpleName); 16 | treeItem.resourceUri = Uri.file(element.uri); 17 | treeItem.description = element.fullyQualifiedName; 18 | treeItem.command = { 19 | command: 'vscode.open', 20 | title: 'Open Type Location', 21 | arguments: [ 22 | Uri.parse(element.uri) 23 | ] 24 | } 25 | return treeItem; 26 | } 27 | 28 | getChildren(element?: ITestNavigationItem): ProviderResult { 29 | if (!element) { 30 | return this.items; 31 | } 32 | 33 | return undefined; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/TestFactoryTest.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | import static org.junit.jupiter.api.DynamicContainer.dynamicContainer; 6 | import static org.junit.jupiter.api.DynamicTest.dynamicTest; 7 | 8 | import java.util.List; 9 | import java.util.function.Function; 10 | import java.util.stream.Stream; 11 | 12 | import org.junit.jupiter.api.DynamicContainer; 13 | import org.junit.jupiter.api.DynamicTest; 14 | import org.junit.jupiter.api.TestFactory; 15 | import org.junit.jupiter.api.function.ThrowingConsumer; 16 | 17 | class TestFactoryTest { 18 | @TestFactory 19 | Stream testDynamicTest() { 20 | final Stream parameters = Stream.of(1L); 21 | final Function testNames = input -> "TestInput " + input; 22 | final ThrowingConsumer test = input -> {assertEquals(1L, input);}; 23 | return DynamicTest.stream(parameters, testNames, test); 24 | } 25 | 26 | @TestFactory 27 | public Stream testContainers() { 28 | return Stream.of(dynamicContainer("Container", List.of( 29 | dynamicTest("Test", () -> {assertTrue(true);}) 30 | ))); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.microsoft.java.test.plugin 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.pde.ManifestBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.pde.SchemaBuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.m2e.core.maven2Nature 31 | org.eclipse.pde.PluginNature 32 | org.eclipse.jdt.core.javanature 33 | 34 | 35 | 36 | 1668558612463 37 | 38 | 30 39 | 40 | org.eclipse.core.resources.regexFilterMatcher 41 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------ START OF LICENSE ----------------------------------------- 2 | 3 | vscode-java-test 4 | 5 | Copyright (c) Microsoft Corporation 6 | 7 | All rights reserved. 8 | 9 | MIT License 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | 17 | ----------------------------------------------- END OF LICENSE ------------------------------------------ 18 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.microsoft.java.test.plugin.test 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.pde.ManifestBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.pde.SchemaBuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.m2e.core.maven2Nature 31 | org.eclipse.pde.PluginNature 32 | org.eclipse.jdt.core.javanature 33 | 34 | 35 | 36 | 1695867787188 37 | 38 | 30 39 | 40 | org.eclipse.core.resources.regexFilterMatcher 41 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/utils/coverageUtils.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { DebugConfiguration } from 'vscode'; 5 | import { extensionContext } from '../extension'; 6 | import * as path from 'path'; 7 | 8 | const jacocoAgentRegex: RegExp = /org\.jacoco\.agent-\d+\.\d+\.\d+-runtime\.jar$/; 9 | 10 | export function getJacocoAgentPath(debugConfiguration: DebugConfiguration): string { 11 | if (debugConfiguration.classPaths) { 12 | for (const classPath of debugConfiguration.classPaths) { 13 | if (jacocoAgentRegex.test(classPath)) { 14 | return classPath; 15 | } 16 | } 17 | } 18 | 19 | if (debugConfiguration.modulePaths) { 20 | for (const modulePath of debugConfiguration.modulePaths) { 21 | if (jacocoAgentRegex.test(modulePath)) { 22 | return modulePath; 23 | } 24 | } 25 | } 26 | 27 | return extensionContext.asAbsolutePath('server/jacocoagent.jar'); 28 | } 29 | 30 | export function getJacocoReportBasePath(projectName: string): string { 31 | return path.join(extensionContext.storageUri!.fsPath, projectName, 'coverage'); 32 | } 33 | 34 | export function getJacocoDataFilePath(projectName: string): string { 35 | return path.join(getJacocoReportBasePath(projectName), 'jacoco.exec'); 36 | } 37 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/Option.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2021 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.model; 13 | 14 | public class Option { 15 | public String value; 16 | public String label; 17 | public String description; 18 | public boolean isAdvanced; 19 | public boolean picked; 20 | 21 | public Option(String label) { 22 | this.label = label; 23 | } 24 | 25 | public Option(String value, String label, String description) { 26 | this.value = value; 27 | this.label = label; 28 | this.description = description; 29 | } 30 | 31 | public Option(String value, String label, String description, boolean isAdvanced) { 32 | this(value, label, description); 33 | this.isAdvanced = isAdvanced; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/ParallelExecutionTest.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | import java.util.concurrent.Semaphore; 4 | 5 | import org.junit.jupiter.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.parallel.Execution; 8 | import org.junit.jupiter.api.parallel.ExecutionMode; 9 | 10 | /** 11 | * Test class with 3 test methods which are executed concurrently, so that the 12 | * correct result processing of overlapping test runs can be verified. 13 | */ 14 | @Execution(ExecutionMode.CONCURRENT) 15 | class ParallelExecutionTest { 16 | 17 | private static final Semaphore s1 = new Semaphore(0); 18 | private static final Semaphore s2 = new Semaphore(0); 19 | private static final Semaphore s3 = new Semaphore(0); 20 | 21 | @Test 22 | void test1() { 23 | s1.release(); 24 | s2.acquireUninterruptibly(); 25 | assertComparison("expected1", "actual1"); 26 | } 27 | 28 | @Test 29 | void test2() { 30 | s2.release(); 31 | s3.acquireUninterruptibly(); 32 | assertComparison("expected2", "actual2"); 33 | } 34 | 35 | @Test 36 | void test3() { 37 | s3.release(); 38 | s1.acquireUninterruptibly(); 39 | } 40 | 41 | private void assertComparison(String expected, String actual) { 42 | Assertions.assertEquals(expected, actual); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/controller/testRunnerService.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { TestRunProfileKind } from 'vscode'; 5 | import { creatTestProfile } from './testController'; 6 | import { TestRunner } from '../java-test-runner.api'; 7 | 8 | // TODO: this should be refactored. The test controller should be extended and hosting the registered runners. 9 | class TestRunnerService { 10 | 11 | private registeredRunners: Map; 12 | 13 | constructor() { 14 | this.registeredRunners = new Map(); 15 | } 16 | 17 | public registerTestRunner(name: string, kind: TestRunProfileKind, runner: TestRunner) { 18 | const key: string = `${name}:${kind}`; 19 | if (this.registeredRunners.has(key)) { 20 | throw new Error(`Runner ${key} has already been registered.`); 21 | } 22 | creatTestProfile(name, kind); 23 | this.registeredRunners.set(key, runner); 24 | } 25 | 26 | public getRunner(name: string | undefined, kind: TestRunProfileKind | undefined): TestRunner | undefined { 27 | if (!name || !kind) { 28 | return undefined; 29 | } 30 | const key: string = `${name}:${kind}`; 31 | return this.registeredRunners.get(key); 32 | } 33 | } 34 | 35 | export const testRunnerService: TestRunnerService = new TestRunnerService(); 36 | -------------------------------------------------------------------------------- /src/commands/navigation/testNavigationInput.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { Location, ProviderResult } from 'vscode'; 5 | import { SymbolTreeInput, SymbolTreeModel } from '../../references-view'; 6 | import { ITestNavigationItem } from './navigationCommands'; 7 | import { TestNavigationTreeDataProvider } from './TestNavigationTreeDataProvider'; 8 | 9 | export class TestNavigationInput implements SymbolTreeInput { 10 | readonly title: string; 11 | readonly location: Location; 12 | readonly contextValue: string = 'javaTestNavigation'; 13 | items: ITestNavigationItem[]; 14 | 15 | 16 | constructor(title: string, location: Location, items: ITestNavigationItem[]) { 17 | this.title = title; 18 | this.location = location; 19 | this.items = items; 20 | } 21 | 22 | resolve(): ProviderResult> { 23 | const provider: TestNavigationTreeDataProvider = new TestNavigationTreeDataProvider(this.items); 24 | const treeModel: SymbolTreeModel = { 25 | message: undefined, 26 | provider, 27 | }; 28 | return treeModel; 29 | } 30 | 31 | with(location: Location): SymbolTreeInput { 32 | return new TestNavigationInput(this.title, location, this.items); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/projects/coverage-test/src/main/java/com/example/project/Sample.java: -------------------------------------------------------------------------------- 1 | package com.example.project; 2 | 3 | import java.util.List; 4 | import java.util.function.Consumer; 5 | import java.util.function.Function; 6 | import java.util.function.Supplier; 7 | 8 | public class Sample { 9 | 10 | void sample(boolean x) { 11 | Foo foo = getFoo(); 12 | if (x) { 13 | foo = new Foo(); // <-- BOTH THIS LINE 14 | } 15 | Bar bar = new Bar(); 16 | Baz baz = new Baz(); 17 | baz.from(bar::bar) 18 | .as(Sample::toArray) // <-- AND THIS LINE 19 | .to(foo::foo); 20 | } 21 | 22 | static String[] toArray(List s) { 23 | return s.toArray(String[]::new); 24 | } 25 | 26 | static Foo getFoo() { 27 | return new Foo(); 28 | } 29 | 30 | static class Foo { 31 | void foo(String... foo) { 32 | } 33 | } 34 | 35 | static class Bar { 36 | List bar() { 37 | return List.of("bar"); 38 | } 39 | } 40 | 41 | static class Baz { 42 | Baz from(Supplier> from) { 43 | return this; 44 | } 45 | 46 | Baz as(Function, String[]> as) { 47 | return this; 48 | } 49 | 50 | Baz to(Consumer to) { 51 | return this; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.microsoft.java.test 7 | parent 8 | 0.43.1 9 | 10 | com.microsoft.java.test.plugin 11 | eclipse-plugin 12 | ${base.name} :: Plugin 13 | 14 | 15 | 16 | org.eclipse.tycho 17 | target-platform-configuration 18 | ${tycho-version} 19 | 20 | 21 | org.eclipse.tycho 22 | tycho-maven-plugin 23 | ${tycho-version} 24 | true 25 | 26 | 27 | org.apache.maven.plugins 28 | maven-checkstyle-plugin 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/common/MessageUtils.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.common; 13 | 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | public class MessageUtils { 18 | 19 | public static TestMessageItem createWithName(String title, String nameValue) { 20 | return create(title, new Pair(TestMessageConstants.NAME, nameValue)); 21 | } 22 | 23 | public static TestMessageItem create(String title, Pair... attributes) { 24 | List pairList = null; 25 | if (attributes != null) { 26 | pairList = Arrays.asList(attributes); 27 | } 28 | return create(title, pairList); 29 | } 30 | 31 | public static TestMessageItem create(String title, List attributes) { 32 | final TestMessageItem item = new TestMessageItem(TestMessageType.Info, title, attributes); 33 | return item; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/coverage/model/MethodCoverage.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2023 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.coverage.model; 13 | 14 | public class MethodCoverage { 15 | int lineNumber; 16 | int hit; 17 | String name; 18 | 19 | public MethodCoverage(int lineNumber, int hit, String name) { 20 | this.lineNumber = lineNumber; 21 | this.hit = hit; 22 | this.name = name; 23 | } 24 | 25 | public int getLineNumber() { 26 | return lineNumber; 27 | } 28 | 29 | public void setLineNumber(int lineNumber) { 30 | this.lineNumber = lineNumber; 31 | } 32 | 33 | public int getHit() { 34 | return hit; 35 | } 36 | 37 | public void setHit(int hit) { 38 | this.hit = hit; 39 | } 40 | 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | public void setName(String name) { 46 | this.name = name; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/runners/junitRunner/JunitRunner.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { AddressInfo } from 'net'; 5 | import { CancellationToken, DebugConfiguration } from 'vscode'; 6 | import { IProgressReporter } from '../../debugger.api'; 7 | import { BaseRunner } from '../baseRunner/BaseRunner'; 8 | import { RunnerResultAnalyzer } from '../baseRunner/RunnerResultAnalyzer'; 9 | import { JUnitRunnerResultAnalyzer } from './JUnitRunnerResultAnalyzer'; 10 | 11 | export class JUnitRunner extends BaseRunner { 12 | public async run(launchConfiguration: DebugConfiguration, token: CancellationToken, progressReporter?: IProgressReporter): Promise { 13 | if (launchConfiguration.args) { 14 | // We need to replace the socket port number since the socket is established from the client side. 15 | // The port number returned from the server side is a fake one. 16 | const args: string[] = launchConfiguration.args as string[]; 17 | const portIndex: number = args.lastIndexOf('-port'); 18 | if (portIndex > -1 && portIndex + 1 < args.length) { 19 | args[portIndex + 1] = `${(this.server.address() as AddressInfo).port}`; 20 | } else { 21 | args.push('-port', `${(this.server.address() as AddressInfo).port}`); 22 | } 23 | } 24 | 25 | return super.run(launchConfiguration, token, progressReporter); 26 | } 27 | 28 | protected getAnalyzer(): RunnerResultAnalyzer { 29 | return new JUnitRunnerResultAnalyzer(this.testContext); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/experimentationService.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { ExtensionContext } from 'vscode'; 5 | import { addContextProperty, sendInfo } from 'vscode-extension-telemetry-wrapper'; 6 | import { getExperimentationServiceAsync, IExperimentationService, IExperimentationTelemetry, TargetPopulation } from 'vscode-tas-client'; 7 | 8 | class ExperimentationTelemetry implements IExperimentationTelemetry { 9 | 10 | public setSharedProperty(name: string, value: string): void { 11 | addContextProperty(name, value); 12 | } 13 | 14 | public postEvent(eventName: string, props: Map): void { 15 | const payload: any = { __event_name__: eventName }; 16 | for (const [key, value] of props) { 17 | payload[key] = value; 18 | } 19 | 20 | sendInfo('', payload); 21 | } 22 | } 23 | 24 | let expService: IExperimentationService; 25 | 26 | export function getExpService(): IExperimentationService { 27 | return expService; 28 | } 29 | 30 | export async function initExpService(context: ExtensionContext): Promise { 31 | // eslint-disable-next-line @typescript-eslint/no-var-requires 32 | const packageJson: {[key: string]: any} = require('../package.json'); 33 | const extensionName: string = `${packageJson['publisher']}.${packageJson['name']}`; 34 | const extensionVersion: string = packageJson['version']; 35 | expService = await getExperimentationServiceAsync(extensionName, extensionVersion, 36 | TargetPopulation.Public, new ExperimentationTelemetry(), context.globalState); 37 | } 38 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/projects/coverage-test/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | coverage-test 8 | 1.0-SNAPSHOT 9 | 10 | 11 | UTF-8 12 | 17 13 | ${maven.compiler.source} 14 | 15 | 16 | 17 | 18 | 19 | org.junit 20 | junit-bom 21 | 5.7.1 22 | pom 23 | import 24 | 25 | 26 | 27 | 28 | 29 | 30 | org.junit.jupiter 31 | junit-jupiter 32 | test 33 | 34 | 35 | 36 | 37 | 38 | 39 | maven-compiler-plugin 40 | 3.8.1 41 | 42 | 43 | maven-surefire-plugin 44 | 2.22.2 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/TestFrameworkSearcher.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017-2021 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.searcher; 13 | 14 | import com.microsoft.java.test.plugin.model.TestKind; 15 | 16 | import org.eclipse.core.runtime.CoreException; 17 | import org.eclipse.core.runtime.IProgressMonitor; 18 | import org.eclipse.jdt.core.IJavaElement; 19 | import org.eclipse.jdt.core.IType; 20 | import org.eclipse.jdt.core.JavaModelException; 21 | import org.eclipse.jdt.core.dom.IAnnotationBinding; 22 | import org.eclipse.jdt.core.dom.IMethodBinding; 23 | 24 | import java.util.Set; 25 | 26 | public interface TestFrameworkSearcher { 27 | 28 | TestKind getTestKind(); 29 | 30 | String getJdtTestKind(); 31 | 32 | boolean isTestMethod(IMethodBinding methodBinding); 33 | 34 | boolean isTestClass(IType type) throws JavaModelException; 35 | 36 | String[] getTestMethodAnnotations(); 37 | 38 | boolean findAnnotation(IAnnotationBinding[] annotations, String[] annotationNames); 39 | 40 | Set findTestItemsInContainer(IJavaElement element, IProgressMonitor monitor) throws CoreException; 41 | } 42 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/coverage/model/LineCoverage.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2023 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.coverage.model; 13 | 14 | import java.util.List; 15 | 16 | public class LineCoverage { 17 | int lineNumber; 18 | int hit; 19 | List branchCoverages; 20 | 21 | public LineCoverage(int lineNumber, int hit, List branchCoverages) { 22 | this.lineNumber = lineNumber; 23 | this.hit = hit; 24 | this.branchCoverages = branchCoverages; 25 | } 26 | 27 | public int getLineNumber() { 28 | return lineNumber; 29 | } 30 | 31 | public void setLineNumber(int lineNumber) { 32 | this.lineNumber = lineNumber; 33 | } 34 | 35 | public int getHit() { 36 | return hit; 37 | } 38 | 39 | public void setHit(int hit) { 40 | this.hit = hit; 41 | } 42 | 43 | public List getBranchCoverages() { 44 | return branchCoverages; 45 | } 46 | 47 | public void setBranchCoverages(List branchCoverages) { 48 | this.branchCoverages = branchCoverages; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.site/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | parent 6 | com.microsoft.java.test 7 | 0.43.1 8 | 9 | com.microsoft.java.test.plugin.site 10 | eclipse-repository 11 | ${base.name} :: update site 12 | 13 | 14 | 15 | org.eclipse.tycho 16 | tycho-p2-repository-plugin 17 | ${tycho-version} 18 | 19 | true 20 | 21 | 22 | 23 | org.eclipse.tycho 24 | tycho-maven-plugin 25 | ${tycho-version} 26 | true 27 | 28 | 29 | org.eclipse.tycho 30 | target-platform-configuration 31 | ${tycho-version} 32 | 33 | p2 34 | consider 35 | true 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/TestLevel.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018-2021 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.model; 13 | 14 | import com.google.gson.annotations.SerializedName; 15 | 16 | public enum TestLevel { 17 | @SerializedName("0") 18 | ROOT, 19 | 20 | @SerializedName("1") 21 | WORKSPACE, 22 | 23 | @SerializedName("2") 24 | WORKSPACE_FOLDER, 25 | 26 | @SerializedName("3") 27 | PROJECT, 28 | 29 | @SerializedName("4") 30 | PACKAGE, 31 | 32 | @SerializedName("5") 33 | CLASS, 34 | 35 | @SerializedName("6") 36 | METHOD; 37 | 38 | public static TestLevel fromInteger(Integer i) { 39 | switch(i) { 40 | case 0: 41 | return ROOT; 42 | case 1: 43 | return WORKSPACE; 44 | case 2: 45 | return WORKSPACE_FOLDER; 46 | case 3: 47 | return PROJECT; 48 | case 4: 49 | return PACKAGE; 50 | case 5: 51 | return CLASS; 52 | case 6: 53 | return METHOD; 54 | default: 55 | return null; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/Response.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2023 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.model; 13 | 14 | public class Response { 15 | 16 | public static final int OK = 0; 17 | public static final int ERROR = 1; 18 | 19 | private T body; 20 | private int status; 21 | private String errorMessage; 22 | 23 | public Response(T body, String errorMessage) { 24 | this.body = body; 25 | if (errorMessage == null) { 26 | this.status = OK; 27 | } else { 28 | this.errorMessage = errorMessage; 29 | this.status = ERROR; 30 | } 31 | } 32 | 33 | public T getBody() { 34 | return body; 35 | } 36 | 37 | public void setBody(T body) { 38 | this.body = body; 39 | } 40 | 41 | public int getStatus() { 42 | return status; 43 | } 44 | 45 | public void setStatus(int status) { 46 | this.status = status; 47 | } 48 | 49 | public String getErrorMessage() { 50 | return errorMessage; 51 | } 52 | 53 | public void setErrorMessage(String errorMessage) { 54 | this.errorMessage = errorMessage; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/runners/testngRunner/TestNGRunner.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { TestItem } from 'vscode'; 5 | import { dataCache } from '../../controller/testItemDataCache'; 6 | import { BaseRunner } from '../baseRunner/BaseRunner'; 7 | import { RunnerResultAnalyzer } from '../baseRunner/RunnerResultAnalyzer'; 8 | import { TestNGRunnerResultAnalyzer } from './TestNGRunnerResultAnalyzer'; 9 | import { TestLevel } from '../../java-test-runner.api'; 10 | 11 | export class TestNGRunner extends BaseRunner { 12 | 13 | public getRunnerCommandParams(): string[] { 14 | const testMethods: TestItem[] = []; 15 | const queue: TestItem[] = [...this.testContext.testItems]; 16 | while (queue.length) { 17 | const item: TestItem = queue.shift()!; 18 | const testLevel: TestLevel | undefined = dataCache.get(item)?.testLevel; 19 | if (testLevel === undefined) { 20 | continue; 21 | } 22 | if (testLevel === TestLevel.Method) { 23 | testMethods.push(item); 24 | } else { 25 | item.children.forEach((child: TestItem) => { 26 | queue.push(child); 27 | }); 28 | } 29 | } 30 | 31 | return ['testng', ...testMethods.map((method: TestItem) => { 32 | // parse to fullName 33 | const index: number = method.id.indexOf('@'); 34 | if (index < 0) { 35 | return ''; 36 | } 37 | return method.id.slice(index + 1); 38 | }).filter(Boolean)]; 39 | } 40 | 41 | protected getAnalyzer(): RunnerResultAnalyzer { 42 | return new TestNGRunnerResultAnalyzer(this.testContext); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/utils/testItemUtils.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { TestIdParts } from '../java-test-runner.api'; 5 | 6 | export function parseTestIdFromParts(parts: TestIdParts): string { 7 | let testId: string = parts.project; 8 | if (parts.class) { 9 | testId += `@${parts.class}`; 10 | } else if (parts.package) { 11 | testId += `@${parts.package}`; 12 | } 13 | 14 | if (parts.invocations?.length) { 15 | testId += `#${parts.invocations.join('#')}`; 16 | } 17 | 18 | return testId; 19 | } 20 | 21 | export function parsePartsFromTestId(testId: string): TestIdParts { 22 | const idxOfProjectSeparator: number = testId.indexOf('@'); 23 | if (idxOfProjectSeparator < 0) { 24 | return { project: testId }; 25 | } 26 | 27 | const project: string = testId.substring(0, idxOfProjectSeparator); 28 | testId = testId.substring(idxOfProjectSeparator + 1); 29 | 30 | const idxOfMethodStart: number = testId.indexOf('#'); 31 | let classFullyQualifiedName: string; 32 | if (idxOfMethodStart > 0) { 33 | classFullyQualifiedName = testId.substring(0, idxOfMethodStart); 34 | } else { 35 | classFullyQualifiedName = testId; 36 | } 37 | 38 | const idxOfLastDot: number = classFullyQualifiedName.lastIndexOf('.'); 39 | const packageName: string = idxOfLastDot > 0 ? classFullyQualifiedName.substring(0, idxOfLastDot) : ''; 40 | 41 | let invocations: string[] | undefined; 42 | if (idxOfMethodStart > 0) { 43 | testId = testId.substring(idxOfMethodStart + 1); 44 | invocations = [...testId.split('#')]; 45 | } 46 | 47 | return { 48 | project, 49 | package: packageName, 50 | class: classFullyQualifiedName, 51 | invocations, 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | //@ts-check 5 | const path = require('path'); 6 | 7 | /**@type {import('webpack').Configuration}*/ 8 | const config = { 9 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 10 | node: { 11 | __dirname: false, 12 | __filename: false, 13 | }, 14 | entry: { 15 | "extension.bundle": './extension.bundle.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 16 | }, 17 | output: { // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 18 | path: path.resolve(__dirname, 'dist'), 19 | filename: '[name].js', 20 | libraryTarget: "commonjs2", 21 | devtoolModuleFilenameTemplate: "../[resource-path]", 22 | }, 23 | externals: { 24 | 'applicationinsights-native-metrics': 'commonjs applicationinsights-native-metrics', // ignored because we don't ship native module 25 | 'diagnostic-channel-publishers': 'commonjs diagnostic-channel-publishers', 26 | vscode: "commonjs vscode", // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 27 | }, 28 | devtool: 'source-map', 29 | resolve: { // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 30 | extensions: ['.ts', '.js'], 31 | }, 32 | module: { 33 | rules: [{ 34 | test: /\.ts$/, 35 | exclude: /node_modules/, 36 | use: [{ 37 | loader: 'ts-loader', 38 | }] 39 | }] 40 | } 41 | } 42 | module.exports = config; 43 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationTemplate.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2019 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.launchers; 13 | 14 | public class JUnitLaunchConfigurationTemplate { 15 | 16 | //@formatter:off 17 | public static final String JUNIT_TEMPLATE = "\n" + 18 | "\n" + 19 | "\n" + 20 | "\n" + 21 | "\n" + 22 | "\n" + 23 | "\n" + 24 | "\n" + 25 | "\n" + 26 | "\n" + 27 | "\n" + 28 | "\n"; 29 | //@formatter:on 30 | } 31 | -------------------------------------------------------------------------------- /test/unmanaged-folder-suite/enableTests.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | 'use strict'; 5 | 6 | import * as assert from 'assert'; 7 | import * as path from 'path'; 8 | import * as fse from 'fs-extra'; 9 | import { Uri, window } from 'vscode'; 10 | import { enableTests } from '../../src/commands/testDependenciesCommands'; 11 | import { setupTestEnv, sleep } from '../suite/utils'; 12 | import { TestKind } from '../../src/java-test-runner.api'; 13 | 14 | // tslint:disable: only-arrow-functions 15 | // tslint:disable: no-object-literal-type-assertion 16 | const PROJECT_PATH: string = path.join(__dirname, '../../..', 'test', 'test-projects','simple'); 17 | const LIB_PATH: string = path.join(PROJECT_PATH, 'lib'); 18 | 19 | suite('Test Enable Tests', () => { 20 | 21 | suiteSetup(async function() { 22 | const filePath: string = path.join(PROJECT_PATH, 'src', 'App.java'); 23 | await window.showTextDocument(Uri.file(filePath)); 24 | await setupTestEnv(); 25 | }); 26 | 27 | test('test enable tests for unmanaged folder', async () => { 28 | await enableTests(TestKind.JUnit5); 29 | for (let i = 0; i < 5; i++) { 30 | if (await fse.pathExists(LIB_PATH)) { 31 | const files: string[] = await fse.readdir(LIB_PATH); 32 | const downloaded: boolean = files.some((file) => { 33 | return file.includes('junit-platform-console-standalone'); 34 | }); 35 | if (downloaded) { 36 | return; 37 | } 38 | } 39 | await sleep(1000 /*ms*/); 40 | } 41 | 42 | assert.fail('Failed to download test dependencies for unmanaged folder.'); 43 | }); 44 | 45 | suiteTeardown(async function() { 46 | await fse.remove(LIB_PATH); 47 | }) 48 | 49 | }); 50 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/BaseFrameworkSearcher.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018-2021 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.searcher; 13 | 14 | import com.microsoft.java.test.plugin.model.TestKind; 15 | import com.microsoft.java.test.plugin.util.TestFrameworkUtils; 16 | 17 | import org.eclipse.jdt.core.dom.IAnnotationBinding; 18 | import org.eclipse.jdt.core.dom.ITypeBinding; 19 | 20 | public abstract class BaseFrameworkSearcher implements TestFrameworkSearcher { 21 | 22 | protected String[] testMethodAnnotations; 23 | 24 | @Override 25 | public abstract TestKind getTestKind(); 26 | 27 | @Override 28 | public String[] getTestMethodAnnotations() { 29 | return this.testMethodAnnotations; 30 | } 31 | 32 | @Override 33 | public boolean findAnnotation(IAnnotationBinding[] annotations, String[] annotationNames) { 34 | for (final IAnnotationBinding annotation : annotations) { 35 | final ITypeBinding annotationType = annotation.getAnnotationType(); 36 | for (final String annotationName : annotationNames) { 37 | if (TestFrameworkUtils.isEquivalentAnnotationType(annotationType, annotationName)) { 38 | return true; 39 | } 40 | } 41 | } 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/coverage/model/SourceFileCoverage.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2023 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.coverage.model; 13 | 14 | import java.util.List; 15 | 16 | public class SourceFileCoverage { 17 | String uriString; 18 | List lineCoverages; 19 | List methodCoverages; 20 | 21 | public SourceFileCoverage(String uriString, List lineCoverages, 22 | List methodCoverages) { 23 | this.uriString = uriString; 24 | this.lineCoverages = lineCoverages; 25 | this.methodCoverages = methodCoverages; 26 | } 27 | 28 | public String getUriString() { 29 | return uriString; 30 | } 31 | 32 | public void setUriString(String uriString) { 33 | this.uriString = uriString; 34 | } 35 | 36 | public List getLineCoverages() { 37 | return lineCoverages; 38 | } 39 | 40 | public void setLineCoverages(List lineCoverages) { 41 | this.lineCoverages = lineCoverages; 42 | } 43 | 44 | public List getMethodCoverages() { 45 | return methodCoverages; 46 | } 47 | 48 | public void setMethodCoverages(List methodCoverages) { 49 | this.methodCoverages = methodCoverages; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/common/TestMessageItem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.common; 13 | 14 | import java.io.PrintWriter; 15 | import java.io.StringWriter; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | public class TestMessageItem { 20 | String name; 21 | 22 | List attributes; 23 | 24 | TestMessageType type; 25 | 26 | public TestMessageItem(TestMessageType type, String name, List attributes) { 27 | this.type = type; 28 | this.name = name; 29 | this.attributes = attributes; 30 | } 31 | 32 | public TestMessageItem(TestMessageType type, String name, Pair... attributes) { 33 | this(type, name, attributes != null ? Arrays.asList(attributes) : null); 34 | } 35 | 36 | public TestMessageItem(String message, Throwable e) { 37 | this(TestMessageType.Error, TestMessageConstants.TEST_RUNNER_ERROR, 38 | new Pair(TestMessageConstants.MESSAGE, message), 39 | new Pair(TestMessageConstants.TRACE, getStacktrace(e))); 40 | } 41 | 42 | private static String getStacktrace(Throwable throwable) { 43 | final StringWriter errors = new StringWriter(); 44 | throwable.printStackTrace(new PrintWriter(errors)); 45 | return errors.toString(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/provider/codeActionProvider.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { CodeAction, CodeActionKind, CodeActionProvider, Disposable, languages, Range, Selection, TextDocument } from 'vscode'; 5 | 6 | let provider: Disposable; 7 | export class TestCodeActionProvider implements CodeActionProvider { 8 | 9 | public async provideCodeActions(document: TextDocument, range: Range | Selection): Promise { 10 | if (document.fileName === 'module-info.java' || document.fileName === 'package-info.java') { 11 | return []; 12 | } 13 | return [this.getCodeAction(document, range)]; 14 | } 15 | 16 | private getCodeAction(document: TextDocument, range: Range | Selection): CodeAction { 17 | const offset: number = document.offsetAt(range.start); 18 | const codeAction: CodeAction = new CodeAction('Generate Tests...', CodeActionKind.Source.append('generate.tests')); 19 | codeAction.command = { 20 | title: 'Generate Tests...', 21 | command: 'java.test.generateTests', 22 | arguments: [document.uri, offset], 23 | }; 24 | // This is only to make sure the rank of the code actions will not jitter 25 | // See: https://github.com/microsoft/vscode/issues/62267 26 | codeAction.isPreferred = true; 27 | return codeAction; 28 | } 29 | } 30 | 31 | export async function registerTestCodeActionProvider(): Promise { 32 | disposeCodeActionProvider(); 33 | 34 | provider = languages.registerCodeActionsProvider( 35 | {language: 'java', scheme: 'file', pattern: '**/*.java'}, 36 | new TestCodeActionProvider(), 37 | { providedCodeActionKinds: [CodeActionKind.Source.append('generate.tests')] }, 38 | ); 39 | return provider; 40 | } 41 | 42 | export function disposeCodeActionProvider(): void { 43 | provider?.dispose(); 44 | } 45 | -------------------------------------------------------------------------------- /src/commands/testReportCommands.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { commands, Position, Range, Uri, ViewColumn, window } from 'vscode'; 5 | import { JavaLanguageServerCommands } from '../constants'; 6 | import { executeJavaLanguageServerCommand } from '../utils/commandUtils'; 7 | 8 | export async function openStackTrace(trace: string, fullName: string): Promise { 9 | if (!trace || !fullName) { 10 | return; 11 | } 12 | 13 | const projectName: string = fullName.substring(0, fullName.indexOf('@')); 14 | 15 | const uri: string = await resolveStackTraceLocation(trace, projectName ? [projectName] : []); 16 | if (uri) { 17 | let lineNumber: number = 0; 18 | const lineNumberGroup: RegExpExecArray | null = /\((?:[\w-$]+\.java:(\d+))\)/.exec(trace); 19 | if (lineNumberGroup) { 20 | lineNumber = parseInt(lineNumberGroup[1], 10) - 1; 21 | } 22 | await window.showTextDocument(Uri.parse(uri), { 23 | selection: new Range(new Position(lineNumber, 0), new Position(lineNumber + 1, 0)), 24 | viewColumn: ViewColumn.One, 25 | }); 26 | } else { 27 | const methodNameGroup: RegExpExecArray | null = /([\w$\.]+\/)?(([\w$]+\.)+[<\w$>]+)\(.*\)/.exec(trace); 28 | if (methodNameGroup) { 29 | const fullyQualifiedName: string = methodNameGroup[2].substring(0, methodNameGroup[2].lastIndexOf('.')); 30 | const className: string = fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf('.') + 1); 31 | commands.executeCommand('workbench.action.quickOpen', '#' + className); 32 | } 33 | } 34 | } 35 | 36 | async function resolveStackTraceLocation(trace: string, projectNames: string[]): Promise { 37 | return await executeJavaLanguageServerCommand( 38 | JavaLanguageServerCommands.RESOLVE_STACKTRACE_LOCATION, trace, projectNames) || ''; 39 | } 40 | -------------------------------------------------------------------------------- /test/test-projects/junit/src/test/java/junit5/ParameterizedAnnotationTest.java: -------------------------------------------------------------------------------- 1 | package junit5; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import java.util.Collections; 6 | import java.util.List; 7 | import java.util.stream.Stream; 8 | 9 | import org.junit.jupiter.params.ParameterizedTest; 10 | import org.junit.jupiter.params.provider.Arguments; 11 | import org.junit.jupiter.params.provider.CsvSource; 12 | import org.junit.jupiter.params.provider.MethodSource; 13 | 14 | import junit.App; 15 | 16 | public class ParameterizedAnnotationTest { 17 | 18 | // this is a comment 19 | @ParameterizedTest 20 | @CsvSource({ 21 | "Hello world.,true", 22 | "Good morining,false" 23 | }) 24 | public void canRunWithComment(String str, Boolean bool) throws Exception { 25 | App classUnderTest = new App(); 26 | assertEquals(classUnderTest.getGreeting().equals(str), bool); 27 | } 28 | 29 | @ParameterizedTest 30 | @CsvSource({ 31 | "1, 2", 32 | "1, 1" 33 | }) 34 | public void equal(int first, int second) throws Exception { 35 | assertEquals(first, second); 36 | } 37 | 38 | @ParameterizedTest(name = "Test {0} is a Palindrome") 39 | @MethodSource("palindromeProvider") 40 | void canRunWithGenericTypedParameter(List argument) { 41 | } 42 | 43 | static Stream> palindromeProvider() { 44 | return Stream.of(Collections.singletonList(1), Collections.singletonList(1)); 45 | } 46 | 47 | class User {} 48 | 49 | static Stream users(){ 50 | return Stream.of(Arguments.of(new ParameterizedAnnotationTest().new User())); 51 | } 52 | 53 | @ParameterizedTest 54 | @MethodSource("users") 55 | public void testCheckUser(User user){ 56 | } 57 | 58 | @ParameterizedTest 59 | @CsvSource({"a,b,c"}) 60 | public void testMultiArguments(String a, String b, String c) throws Exception { 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/src/com/microsoft/java/test/plugin/launchers/JUnitLaunchConfigurationDelegateTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2023 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.launchers; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static org.junit.Assert.assertTrue; 16 | 17 | import java.util.Arrays; 18 | import java.util.List; 19 | 20 | import org.eclipse.core.resources.IProject; 21 | import org.eclipse.core.runtime.NullProgressMonitor; 22 | import org.junit.Test; 23 | 24 | import com.microsoft.java.test.plugin.AbstractProjectsManagerBasedTest; 25 | import com.microsoft.java.test.plugin.model.Response; 26 | 27 | public class JUnitLaunchConfigurationDelegateTest extends AbstractProjectsManagerBasedTest { 28 | 29 | @Test 30 | public void testWorkingDirectoryForTestNgUnmanagedFolder() throws Exception { 31 | IProject invisibleProject = copyAndImportFolder("simple", "src/App.java"); 32 | assertTrue(invisibleProject.exists()); 33 | 34 | List arguments = Arrays.asList("{\"projectName\":\"" + invisibleProject.getName() 35 | + "\",\"testLevel\":5,\"testKind\":2,\"testNames\":[\"App\"]}"); 36 | 37 | Response response = JUnitLaunchUtils.resolveLaunchArgument(arguments, new NullProgressMonitor()); 38 | 39 | assertEquals(0, response.getStatus()); 40 | assertTrue(response.getBody().workingDirectory.endsWith("simple")); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/common/TestMessageConstants.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.common; 13 | 14 | public class TestMessageConstants { 15 | public static final String TEST_REPORTER_ATTACHED = "testReporterAttached"; 16 | public static final String ROOT_NAME = "rootName"; 17 | public static final String NAME = "name"; 18 | public static final String ID = "id"; 19 | public static final String TYPE = "type"; 20 | public static final String LOCATION = "location"; 21 | public static final String TEST_STARTED = "testStarted"; 22 | public static final String TEST_IGNORED = "testIgnored"; 23 | public static final String TEST_FINISHED = "testFinished"; 24 | public static final String DURATION = "duration"; 25 | public static final String SUITE_TREE_NODE = "suiteTreeNode"; 26 | public static final String TEST_SUITE_FINISHED = "testSuiteFinished"; 27 | public static final String TEST_SUITE_STARTED = "testSuiteStarted"; 28 | public static final String SUITE_TREE_STARTED = "suiteTreeStarted"; 29 | public static final String SUITE_TREE_ENDED = "suiteTreeEnded"; 30 | public static final String MESSAGE = "message"; 31 | public static final String TRACE = "trace"; 32 | public static final String STATUS = "status"; 33 | public static final String TEST_FAILED = "testFailed"; 34 | public static final String TEST_RESULT_SUMMARY = "testSummary"; 35 | public static final String TEST_RUNNER_ERROR = "error"; 36 | } 37 | -------------------------------------------------------------------------------- /src/commands/testExplorerCommands.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { DebugConfiguration, TestItem, TestRunRequest } from 'vscode'; 5 | import { sendInfo } from 'vscode-extension-telemetry-wrapper'; 6 | import { runTests, testController } from '../controller/testController'; 7 | import { loadJavaProjects } from '../controller/utils'; 8 | import { showTestItemsInCurrentFile } from '../extension'; 9 | 10 | /** 11 | * This function is used to exposed as a command, which other extensions can trigger 12 | * their customized run/debug requests to test runner. (e.g. the PDE extension) 13 | * 14 | * Note that, the test item in the method parameters is not the exact test item in the test explorer (another instance). 15 | * To get the metadata of the real test item, we have to record the path from test item to root, and then trace back that 16 | * path to get the real one. 17 | */ 18 | export async function runTestsFromTestExplorer(testItem: TestItem, launchConfiguration: DebugConfiguration, isDebug: boolean): Promise { 19 | const pathToRoot: string[] = []; 20 | do { 21 | pathToRoot.push(testItem.id); 22 | testItem = testItem.parent!; 23 | } while (testItem); 24 | let currentItem: TestItem | undefined = testController?.items.get(pathToRoot.pop()!); 25 | if (!currentItem) { 26 | return; 27 | } 28 | while (pathToRoot.length) { 29 | const id: string = pathToRoot.pop()!; 30 | currentItem = currentItem.children.get(id); 31 | if (!currentItem) { 32 | return; 33 | } 34 | } 35 | const request: TestRunRequest = new TestRunRequest([currentItem], undefined); 36 | 37 | await runTests(request, { launchConfiguration, isDebug }); 38 | } 39 | 40 | export async function refreshExplorer(): Promise { 41 | sendInfo('', { name: 'refreshTests' }); 42 | testController?.items.forEach((root: TestItem) => { 43 | testController?.items.delete(root.id); 44 | }); 45 | 46 | await loadJavaProjects(); 47 | await showTestItemsInCurrentFile(); 48 | } 49 | -------------------------------------------------------------------------------- /test/test-projects/junit/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | java.test.runner 8 | junit 9 | 1.0-SNAPSHOT 10 | 11 | junit 12 | 13 | 14 | UTF-8 15 | 21 16 | 21 17 | 18 | 19 | 20 | 21 | junit 22 | junit 23 | 4.13.1 24 | test 25 | 26 | 27 | io.vertx 28 | vertx-junit5 29 | 4.3.8 30 | test 31 | 32 | 33 | org.junit.jupiter 34 | junit-jupiter 35 | 5.6.0 36 | test 37 | 38 | 39 | net.jqwik 40 | jqwik 41 | 1.2.7 42 | test 43 | 44 | 45 | io.cucumber 46 | cucumber-java 47 | 5.6.0 48 | test 49 | 50 | 51 | io.cucumber 52 | cucumber-junit 53 | 5.6.0 54 | test 55 | 56 | 57 | org.testng 58 | testng 59 | 7.7.1 60 | test 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /.github/llms.md: -------------------------------------------------------------------------------- 1 | # Test Runner for Java 2 | 3 | Test Runner for Java is a lightweight extension to run and debug Java test cases in Visual Studio Code. It works with Language Support for Java by Red Hat to provide comprehensive Java testing capabilities. 4 | 5 | ## Features 6 | - Run & Debug JUnit/TestNG Test Cases 7 | - Test discovery and execution 8 | - Test result visualization 9 | - Integration with Java project structure 10 | - Support for Maven and Gradle projects 11 | 12 | ## Label 13 | When labeling an issue, follow the rules below per label category: 14 | ### General Rules 15 | - Analyze if the issue is related with the scope of Java testing functionality in VS Code. If not, STOP labelling IMMEDIATELY. 16 | - Assign label per category. 17 | - If a category is not applicable or you're unsure, you may skip it. 18 | - Do not assign multiple labels within the same category, unless explicitly allowed as an exception. 19 | 20 | ### Issue Type Labels 21 | - [bug]: Primary label for real bug issues 22 | - [enhancement]: Primary label for enhancement issues 23 | - [documentation]: Primary label for documentation issues 24 | - [question]: Primary label for question issues 25 | 26 | ### Test Framework Labels 27 | - [junit]: Issues specific to JUnit test framework 28 | - [testng]: Issues specific to TestNG test framework 29 | 30 | ### Project Type Labels 31 | - [maven]: Issues related to Maven projects 32 | - [gradle]: Issues related to Gradle projects 33 | 34 | ### Component Labels 35 | - [test-discovery]: Issues related to finding and discovering tests 36 | - [test-execution]: Issues related to running tests 37 | - [test-debugging]: Issues related to debugging tests 38 | - [test-reporting]: Issues related to test results and reporting 39 | - [ui]: Issues related to user interface and experience 40 | 41 | ### Priority Labels 42 | - [high-priority]: Critical issues that significantly impact functionality 43 | - [low-priority]: Nice-to-have improvements or minor issues 44 | 45 | ### Status Labels 46 | - [waiting-for-user-info]: Waiting for additional information from the user 47 | - [investigating]: Issue is being investigated 48 | - [needs-reproduction]: Issue needs to be reproduced 49 | - [fixed-next-release]: Issue has been fixed and will be in the next release -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/model/TestKind.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2021 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.model; 13 | 14 | import com.google.gson.annotations.SerializedName; 15 | 16 | public enum TestKind { 17 | 18 | @SerializedName("0") 19 | JUnit5(0), 20 | 21 | @SerializedName("1") 22 | JUnit(1), 23 | 24 | @SerializedName("2") 25 | TestNG(2), 26 | 27 | @SerializedName("3") 28 | JUnit6(3), 29 | 30 | @SerializedName("100") 31 | None(100); 32 | 33 | private int value; 34 | 35 | public static TestKind fromString(String s) { 36 | switch (s) { 37 | case "Unknown": 38 | return None; 39 | case "JUnit 4": 40 | return JUnit; 41 | case "JUnit 5": 42 | return JUnit5; 43 | case "JUnit 6": 44 | return JUnit6; 45 | case "TestNG": 46 | return TestNG; 47 | default: 48 | return null; 49 | } 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | switch (this) { 55 | case None: 56 | return "Unknown"; 57 | case JUnit: 58 | return "JUnit 4"; 59 | case JUnit5: 60 | return "JUnit 5"; 61 | case JUnit6: 62 | return "JUnit 6"; 63 | case TestNG: 64 | return "TestNG"; 65 | default: 66 | return ""; 67 | } 68 | } 69 | 70 | public int getValue() { 71 | return this.value; 72 | } 73 | 74 | private TestKind(int value) { 75 | this.value = value; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.1.0", 4 | "configurations": [ 5 | { 6 | "name": "Launch Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "runtimeExecutable": "${execPath}", 10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], 11 | "sourceMaps": true, 12 | "outFiles": [ "${workspaceRoot}/dist/**/*.js" ], 13 | "preLaunchTask": "npm: watch", 14 | "env": { 15 | "DEBUG_VSCODE_JAVA":"true" 16 | } 17 | }, 18 | { 19 | "type": "java", 20 | "name": "Debug Test Runner Java Plugin (Attach)", 21 | "request": "attach", 22 | "hostName": "localhost", 23 | "port": 1044, 24 | "projectName": "com.microsoft.java.test.plugin", 25 | }, 26 | { 27 | "name": "Launch Tests (maven-junit)", 28 | "type": "extensionHost", 29 | "request": "launch", 30 | "runtimeExecutable": "${execPath}", 31 | "args": ["${workspaceFolder}/test/test-projects/junit", "--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/out/test/suite" ], 32 | "sourceMaps": true, 33 | "pauseForSourceMap": true, 34 | "outFiles": [ 35 | "${workspaceFolder}/dist/**/*.js", 36 | "${workspaceFolder}/out/**/*.js" 37 | ], 38 | "preLaunchTask": "npm: compile" 39 | }, 40 | { 41 | "name": "Launch Tests (unmanaged-folder)", 42 | "type": "extensionHost", 43 | "request": "launch", 44 | "runtimeExecutable": "${execPath}", 45 | "args": ["${workspaceFolder}/test/test-projects/simple", "--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/out/test/unmanaged-folder-suite" ], 46 | "sourceMaps": true, 47 | "outFiles": [ 48 | "${workspaceFolder}/dist/**/*.js", 49 | "${workspaceFolder}/out/**/*.js" 50 | ], 51 | "preLaunchTask": "npm: compile" 52 | } 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /.azure-pipelines/release.yml: -------------------------------------------------------------------------------- 1 | # This pipeline is used to release the VS Code Java Debug extension from the nightly/stable build. 2 | # It contains following steps: 3 | # 1. Download the plugin artifact from the nightly/stable build pipeline. 4 | # 2. Publish the plugin to the marketplace. 5 | 6 | name: $(Date:yyyyMMdd).$(Rev:r) # Use the current date and a revision number for the build name. 7 | 8 | variables: 9 | - name: Codeql.Enabled 10 | value: true 11 | resources: 12 | repositories: 13 | - repository: self 14 | type: git 15 | ref: refs/heads/main 16 | - repository: 1esPipelines 17 | type: git 18 | name: 1ESPipelineTemplates/1ESPipelineTemplates 19 | ref: refs/tags/release 20 | trigger: none 21 | extends: 22 | template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines 23 | parameters: 24 | pool: 25 | os: linux 26 | name: 1ES_JavaTooling_Pool 27 | image: 1ES_JavaTooling_Ubuntu-2004 28 | stages: 29 | - stage: Release 30 | jobs: 31 | - job: Job 32 | displayName: Release VS Code Java Debug Extension 33 | templateContext: 34 | type: releaseJob 35 | isProduction: true 36 | inputs: 37 | - input: pipelineArtifact 38 | buildType: specific 39 | project: $(AzDo.ProjectId) # Azure DevOps project ID 40 | definition: $(AzDo.BuildPipelineId) # artifact build pipeline ID 41 | artifactName: extension 42 | downloadType: specific 43 | targetPath: '$(Build.SourcesDirectory)' 44 | steps: 45 | - task: UseNode@1 46 | displayName: 'Use Node.js 20.x' 47 | inputs: 48 | version: '20.x' 49 | - task: AzureCLI@2 50 | displayName: 'Publish Extension' 51 | inputs: 52 | azureSubscription: 'VSCode-Ext-Publishing' 53 | scriptType: pscore 54 | scriptLocation: inlineScript 55 | inlineScript: 'npx @vscode/vsce@latest publish -i ''$(Build.SourcesDirectory)/extension.vsix'' --manifestPath ''$(Build.SourcesDirectory)/extension.manifest'' --signaturePath ''$(Build.SourcesDirectory)/extension.signature.p7s'' --azure-credential' -------------------------------------------------------------------------------- /.azure-pipelines/release-nightly.yml: -------------------------------------------------------------------------------- 1 | # This pipeline is used to release the VS Code Java Debug extension from the nightly/stable build. 2 | # It contains following steps: 3 | # 1. Download the plugin artifact from the nightly/stable build pipeline. 4 | # 2. Publish the plugin to the marketplace. 5 | 6 | name: $(Date:yyyyMMdd).$(Rev:r) # Use the current date and a revision number for the build name. 7 | 8 | variables: 9 | - name: Codeql.Enabled 10 | value: true 11 | resources: 12 | repositories: 13 | - repository: self 14 | type: git 15 | ref: refs/heads/main 16 | - repository: 1esPipelines 17 | type: git 18 | name: 1ESPipelineTemplates/1ESPipelineTemplates 19 | ref: refs/tags/release 20 | trigger: none 21 | extends: 22 | template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines 23 | parameters: 24 | pool: 25 | os: linux 26 | name: 1ES_JavaTooling_Pool 27 | image: 1ES_JavaTooling_Ubuntu-2004 28 | stages: 29 | - stage: Release 30 | jobs: 31 | - job: Job 32 | displayName: Release VS Code Java Debug Extension 33 | templateContext: 34 | type: releaseJob 35 | isProduction: true 36 | inputs: 37 | - input: pipelineArtifact 38 | buildType: specific 39 | project: $(AzDo.ProjectId) # Azure DevOps project ID 40 | definition: $(AzDo.BuildPipelineId) # artifact build pipeline ID 41 | artifactName: extension 42 | downloadType: specific 43 | targetPath: '$(Build.SourcesDirectory)' 44 | steps: 45 | - task: UseNode@1 46 | displayName: 'Use Node.js 20.x' 47 | inputs: 48 | version: '20.x' 49 | - task: AzureCLI@2 50 | displayName: 'Publish Extension' 51 | inputs: 52 | azureSubscription: 'VSCode-Ext-Publishing' 53 | scriptType: pscore 54 | scriptLocation: inlineScript 55 | inlineScript: 'npx @vscode/vsce@latest publish -i ''$(Build.SourcesDirectory)/extension.vsix'' --manifestPath ''$(Build.SourcesDirectory)/extension.manifest'' --signaturePath ''$(Build.SourcesDirectory)/extension.signature.p7s'' --azure-credential' -------------------------------------------------------------------------------- /test/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as cp from 'child_process'; 5 | import * as os from 'os'; 6 | import * as path from 'path'; 7 | import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath, runTests } from '@vscode/test-electron'; 8 | 9 | async function main(): Promise { 10 | try { 11 | const vscodeExecutablePath = await downloadAndUnzipVSCode(); 12 | const [cli, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); 13 | 14 | // Resolve redhat.java dependency 15 | const options: cp.SpawnSyncOptionsWithStringEncoding = { 16 | encoding: 'utf-8', 17 | stdio: 'inherit', 18 | }; 19 | if (process.platform === 'win32') { 20 | options.shell = true; 21 | } 22 | cp.spawnSync(cli, [...args, '--install-extension', 'redhat.java', '--pre-release'], options); 23 | 24 | cp.spawnSync(cli, [...args, '--install-extension', 'vscjava.vscode-java-debug', '--pre-release'], options); 25 | 26 | // The folder containing the Extension Manifest package.json 27 | // Passed to `--extensionDevelopmentPath` 28 | const extensionDevelopmentPath: string = path.resolve(__dirname, '..', '..'); 29 | 30 | // Run maven test 31 | await runTests({ 32 | vscodeExecutablePath, 33 | extensionDevelopmentPath, 34 | extensionTestsPath: path.resolve(__dirname, 'suite'), 35 | launchArgs: [ 36 | '--disable-workspace-trust', 37 | path.join(__dirname, '..', '..', 'test', 'test-projects', 'junit'), 38 | ], 39 | }); 40 | 41 | // Run unmanaged folder test 42 | await runTests({ 43 | vscodeExecutablePath, 44 | extensionDevelopmentPath, 45 | extensionTestsPath: path.resolve(__dirname, 'unmanaged-folder-suite'), 46 | launchArgs: [ 47 | '--disable-workspace-trust', 48 | path.join(__dirname, '..', '..', 'test', 'test-projects', 'simple'), 49 | ], 50 | }); 51 | 52 | process.exit(0); 53 | 54 | } catch (err) { 55 | process.stdout.write(`${err}${os.EOL}`); 56 | process.exit(1); 57 | } 58 | } 59 | 60 | main(); 61 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestFrameworkUtils.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.util; 13 | 14 | import com.microsoft.java.test.plugin.model.TestKind; 15 | import com.microsoft.java.test.plugin.searcher.JUnit4TestSearcher; 16 | import com.microsoft.java.test.plugin.searcher.JUnit5TestSearcher; 17 | import com.microsoft.java.test.plugin.searcher.JUnit6TestSearcher; 18 | import com.microsoft.java.test.plugin.searcher.TestFrameworkSearcher; 19 | import com.microsoft.java.test.plugin.searcher.TestNGTestSearcher; 20 | 21 | import org.eclipse.jdt.core.dom.ITypeBinding; 22 | 23 | import java.util.Objects; 24 | 25 | public class TestFrameworkUtils { 26 | 27 | public static final TestFrameworkSearcher JUNIT4_TEST_SEARCHER = new JUnit4TestSearcher(); 28 | public static final TestFrameworkSearcher JUNIT5_TEST_SEARCHER = new JUnit5TestSearcher(); 29 | public static final TestFrameworkSearcher JUNIT6_TEST_SEARCHER = new JUnit6TestSearcher(); 30 | public static final TestFrameworkSearcher TESTNG_TEST_SEARCHER = new TestNGTestSearcher(); 31 | 32 | public static boolean isEquivalentAnnotationType(ITypeBinding annotationType, String annotationName) { 33 | return annotationType != null && Objects.equals(annotationType.getQualifiedName(), annotationName); 34 | } 35 | 36 | public static TestFrameworkSearcher getSearcherByTestKind(TestKind kind) { 37 | switch (kind) { 38 | case JUnit: 39 | return JUNIT4_TEST_SEARCHER; 40 | case JUnit5: 41 | return JUNIT5_TEST_SEARCHER; 42 | case JUnit6: 43 | return JUNIT6_TEST_SEARCHER; 44 | case TestNG: 45 | return TESTNG_TEST_SEARCHER; 46 | default: 47 | return null; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/src/com/microsoft/java/test/plugin/coverage/CoverageHandlerTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2024 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.coverage; 13 | 14 | import com.microsoft.java.test.plugin.AbstractProjectsManagerBasedTest; 15 | import com.microsoft.java.test.plugin.coverage.model.LineCoverage; 16 | import com.microsoft.java.test.plugin.coverage.model.MethodCoverage; 17 | import com.microsoft.java.test.plugin.coverage.model.SourceFileCoverage; 18 | 19 | import org.eclipse.core.runtime.NullProgressMonitor; 20 | import org.eclipse.jdt.core.IJavaProject; 21 | import org.eclipse.jdt.ls.core.internal.ProjectUtils; 22 | import org.junit.Test; 23 | 24 | import java.util.Collections; 25 | import java.util.List; 26 | 27 | import static org.junit.Assert.assertTrue; 28 | 29 | public class CoverageHandlerTest extends AbstractProjectsManagerBasedTest { 30 | 31 | @Test 32 | public void testGetCoverageDetail() throws Exception { 33 | importProjects(Collections.singleton("coverage-test")); 34 | final IJavaProject javaProject = ProjectUtils.getJavaProject("coverage-test"); 35 | final String basePath = javaProject.getProject().getLocation().toFile().getAbsolutePath(); 36 | final CoverageHandler coverageHandler = new CoverageHandler(javaProject, basePath); 37 | final List coverageDetail = coverageHandler.getCoverageDetail(new NullProgressMonitor()); 38 | for (final SourceFileCoverage fileCoverage : coverageDetail) { 39 | for (final LineCoverage lineCoverage : fileCoverage.getLineCoverages()) { 40 | assertTrue(lineCoverage.getLineNumber() > 0); 41 | } 42 | 43 | for (final MethodCoverage methodCoverage : fileCoverage.getMethodCoverages()) { 44 | assertTrue(methodCoverage.getLineNumber() > 0); 45 | } 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /test/suite/utils.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | 'use strict'; 5 | 6 | import * as fse from 'fs-extra'; 7 | import * as path from 'path'; 8 | import { commands, extensions, Range, TestController, TestItem, Uri, workspace } from "vscode"; 9 | import { dataCache } from "../../src/controller/testItemDataCache"; 10 | import { TestKind, TestLevel } from '../../src/java-test-runner.api'; 11 | 12 | export function generateTestItem(testController: TestController, id: string, testKind: TestKind, 13 | range?: Range, jdtHandler?: string, uri: string = '/mock/test/TestAnnotation.java'): TestItem { 14 | 15 | if (!id) { 16 | throw new Error('id cannot be null'); 17 | } 18 | 19 | const projectName = id.substring(0, id.indexOf('@')); 20 | const fullName = id.substring(id.indexOf('@') + 1); 21 | const label = testKind === TestKind.JUnit5 ? id : id.substring(id.indexOf('#') + 1) + '()'; 22 | 23 | const testItem = testController.createTestItem(id, label, Uri.file(uri)); 24 | testItem.range = range || new Range(0, 0, 0, 0); 25 | dataCache.set(testItem, { 26 | jdtHandler: jdtHandler || '', 27 | fullName, 28 | projectName, 29 | testLevel: TestLevel.Method, 30 | testKind, 31 | }); 32 | 33 | return testItem; 34 | } 35 | 36 | export async function setupTestEnv() { 37 | await extensions.getExtension("redhat.java")!.activate(); 38 | const javaExt = extensions.getExtension("redhat.java"); 39 | await javaExt!.activate(); 40 | const api = javaExt?.exports; 41 | while (api.serverMode !== "Standard") { 42 | await sleep(2 * 1000/*ms*/); 43 | } 44 | await extensions.getExtension("vscjava.vscode-java-test")!.activate(); 45 | 46 | const workspaceRootPath: string = workspace.workspaceFolders![0]!.uri.fsPath; 47 | if (await fse.pathExists(path.join(workspaceRootPath, 'pom.xml'))) { 48 | await commands.executeCommand('java.projectConfiguration.update', Uri.file(path.join(workspaceRootPath, 'pom.xml'))); 49 | } else if (await fse.pathExists(path.join(workspaceRootPath, 'build.gradle'))) { 50 | await commands.executeCommand('java.projectConfiguration.update', Uri.file(path.join(workspaceRootPath, 'build.gradle'))); 51 | } 52 | } 53 | 54 | export async function sleep(ms: number) { 55 | return new Promise((resolve) => { 56 | setTimeout(resolve, ms); 57 | }); 58 | } 59 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.target/com.microsoft.java.test.tp.target: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.jacoco 29 | org.jacoco.core 30 | 0.8.14 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.microsoft.java.test 6 | parent 7 | 0.43.1 8 | 9 | com.microsoft.java.test.runner 10 | jar 11 | ${base.name} :: Runner 12 | http://maven.apache.org 13 | 14 | 15 | com.google.code.gson 16 | gson 17 | 2.10.1 18 | 19 | 20 | org.testng 21 | testng 22 | 7.7.1 23 | provided 24 | 25 | 26 | 27 | ${project.artifactId} 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-compiler-plugin 32 | 3.1 33 | 34 | 1.8 35 | 1.8 36 | 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-assembly-plugin 41 | 3.3.0 42 | 43 | 44 | jar-with-dependencies 45 | 46 | 47 | 48 | com.microsoft.java.test.runner.Launcher 49 | 50 | 51 | 52 | 53 | 54 | make-assembly 55 | package 56 | 57 | single 58 | 59 | 60 | 61 | 62 | 63 | org.apache.maven.plugins 64 | maven-checkstyle-plugin 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /java-extension/build-tools/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin.test/projects/coverage-test/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /test/suite/navigation.test.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | 'use strict'; 5 | 6 | import * as assert from 'assert'; 7 | import * as path from 'path'; 8 | import { Location, Uri, window } from 'vscode'; 9 | import { ITestNavigationResult } from '../../src/commands/navigation/navigationCommands'; 10 | import { JavaTestRunnerDelegateCommands } from '../../src/constants'; 11 | import { findTestLocation } from '../../src/runners/utils'; 12 | import { executeJavaLanguageServerCommand } from '../../src/utils/commandUtils'; 13 | import { setupTestEnv } from "./utils"; 14 | 15 | // tslint:disable: only-arrow-functions 16 | // tslint:disable: no-object-literal-type-assertion 17 | const PROJECT_PATH: string = path.join(__dirname, '../../..', 'test', 'test-projects','junit'); 18 | suite('Test Navigation Tests', () => { 19 | 20 | suiteSetup(async function() { 21 | await setupTestEnv(); 22 | }); 23 | 24 | test('test go to test', async () => { 25 | const filePath: string = path.join(PROJECT_PATH, 'src', 'main', 'java', 'junit', 'App.java'); 26 | await window.showTextDocument(Uri.file(filePath)); 27 | const uri: Uri = window.activeTextEditor!.document.uri; 28 | const searchResult = await executeJavaLanguageServerCommand( 29 | JavaTestRunnerDelegateCommands.NAVIGATE_TO_TEST_OR_TARGET, uri.toString(), true); 30 | assert.strictEqual(searchResult?.items.length, 1); 31 | assert.strictEqual(searchResult?.items[0].simpleName, 'AppTest'); 32 | assert.strictEqual(searchResult?.items[0].fullyQualifiedName, 'junit5.AppTest'); 33 | }); 34 | 35 | test('test go to test subject', async () => { 36 | const filePath: string = path.join(PROJECT_PATH, 'src', 'test', 'java', 'junit5', 'AppTest.java'); 37 | await window.showTextDocument(Uri.file(filePath)); 38 | const uri: Uri = window.activeTextEditor!.document.uri; 39 | const searchResult = await executeJavaLanguageServerCommand( 40 | JavaTestRunnerDelegateCommands.NAVIGATE_TO_TEST_OR_TARGET, uri.toString(), false); 41 | assert.strictEqual(searchResult?.items.length, 1); 42 | assert.strictEqual(searchResult?.items[0].simpleName, 'App'); 43 | assert.strictEqual(searchResult?.items[0].fullyQualifiedName, 'junit.App'); 44 | }); 45 | 46 | test('test find inherited test method location', async () => { 47 | const location: Location | undefined = await findTestLocation("junit@junit4.ExtendedTest#test"); 48 | assert.ok(location?.uri.fsPath.endsWith("BaseTest.java")); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /src/debugger.api.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { CancellationToken, ProgressLocation } from "vscode"; 5 | 6 | export interface IProgressReporter { 7 | /** 8 | * Returns the id of the progress reporter. 9 | */ 10 | getId(): string; 11 | 12 | /** 13 | * Reports a progress message update. 14 | * @param message the message to update 15 | * @param increment use `increment` to report discrete progress. Each call with a `increment` 16 | * value will be summed up and reflected as overall progress until 100% is reached. 17 | * Note that currently only `ProgressLocation.Notification` is capable of showing 18 | * discrete progress. 19 | */ 20 | report(message: string, increment?: number): void; 21 | 22 | /** 23 | * Shows the progress reporter. 24 | */ 25 | show(): void; 26 | 27 | /** 28 | * Hides the progress reporter. 29 | * @param onlyNotifications only hide the progress reporter when it's shown as notification. 30 | */ 31 | hide(onlyNotifications?: boolean): void; 32 | 33 | /** 34 | * Returns whether the progress reporter has been cancelled or completed. 35 | */ 36 | isCancelled(): boolean; 37 | 38 | /** 39 | * Notifies the work is done that is either the task is completed or the user has cancelled it. 40 | */ 41 | done(): void; 42 | 43 | /** 44 | * The CancellationToken to monitor if the progress reporter has been cancelled by the user. 45 | */ 46 | getCancellationToken(): CancellationToken; 47 | 48 | /** 49 | * Disposes the progress reporter if the observed token has been cancelled. 50 | * @param token the cancellation token to observe 51 | */ 52 | observe(token?: CancellationToken): void; 53 | } 54 | 55 | export interface IProgressProvider { 56 | /** 57 | * Creates a progress reporter. 58 | * @param jobName the job name 59 | * @param progressLocation The location at which progress should show 60 | * @param cancellable Controls if a cancel button should show to allow the user 61 | * to cancel the progress reporter. Note that currently only 62 | * `ProgressLocation.Notification` is supporting to show a cancel 63 | * button. 64 | */ 65 | createProgressReporter(jobName: string, progressLocation?: ProgressLocation | { viewId: string }, cancellable?: boolean): IProgressReporter; 66 | 67 | /** 68 | * Returns the progress reporter with the progress id. 69 | * @param progressId the progress id 70 | */ 71 | getProgressReporter(progressId: string): IProgressReporter | undefined; 72 | } 73 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Automatic-Module-Name: com.microsoft.java.test.plugin 4 | Bundle-Name: com.microsoft.java.test.plugin 5 | Bundle-SymbolicName: com.microsoft.java.test.plugin;singleton:=true 6 | Bundle-Version: 0.43.1 7 | Bundle-Activator: com.microsoft.java.test.plugin.util.JUnitPlugin 8 | Bundle-RequiredExecutionEnvironment: JavaSE-17 9 | Import-Package: org.eclipse.jdt.core, 10 | org.eclipse.jdt.launching, 11 | org.osgi.framework;version="1.3.0" 12 | Bundle-ActivationPolicy: lazy 13 | Require-Bundle: org.eclipse.jdt.core, 14 | org.eclipse.lsp4j, 15 | org.eclipse.jdt.launching, 16 | org.eclipse.jdt.ls.core, 17 | org.eclipse.core.runtime, 18 | org.eclipse.core.resources, 19 | org.eclipse.jdt.core.manipulation, 20 | org.eclipse.text, 21 | org.eclipse.ltk.core.refactoring, 22 | org.eclipse.debug.core, 23 | org.eclipse.jdt.junit.core, 24 | org.eclipse.jdt.junit.runtime, 25 | org.eclipse.jdt.junit4.runtime, 26 | org.eclipse.jdt.junit5.runtime, 27 | junit-jupiter-api;bundle-version="5.14.0", 28 | junit-jupiter-engine;bundle-version="5.14.0", 29 | junit-jupiter-migrationsupport;bundle-version="5.14.0", 30 | junit-jupiter-params;bundle-version="5.14.0", 31 | junit-vintage-engine;bundle-version="5.14.0", 32 | junit-platform-commons;bundle-version="1.14.1", 33 | junit-platform-engine;bundle-version="1.14.1", 34 | junit-platform-launcher;bundle-version="1.14.1", 35 | junit-platform-runner;bundle-version="1.14.1", 36 | junit-platform-suite-api;bundle-version="1.14.1", 37 | junit-platform-suite-commons;bundle-version="1.14.1", 38 | junit-platform-suite-engine;bundle-version="1.14.1", 39 | org.eclipse.jdt.junit6.runtime, 40 | junit-jupiter-api;bundle-version="6.0.1", 41 | junit-jupiter-engine;bundle-version="6.0.1", 42 | junit-jupiter-params;bundle-version="6.0.1", 43 | org.opentest4j;bundle-version="1.3.0", 44 | junit-platform-commons;bundle-version="6.0.1", 45 | junit-platform-engine;bundle-version="6.0.1", 46 | junit-platform-launcher;bundle-version="6.0.1", 47 | junit-platform-suite-api;bundle-version="6.0.1", 48 | junit-platform-suite-engine;bundle-version="6.0.1", 49 | org.apiguardian.api;bundle-version="1.0.0", 50 | org.apache.commons.lang3;bundle-version="3.1.0", 51 | com.google.gson;bundle-version="2.7.0", 52 | org.objectweb.asm;bundle-version="[9.9.0,9.10.0)", 53 | org.jacoco.core;bundle-version="0.8.14" 54 | Export-Package: com.microsoft.java.test.plugin.launchers;x-friends:="com.microsoft.java.test.plugin.test", 55 | com.microsoft.java.test.plugin.model;x-friends:="com.microsoft.java.test.plugin.test", 56 | com.microsoft.java.test.plugin.coverage;x-friends:="com.microsoft.java.test.plugin.test", 57 | com.microsoft.java.test.plugin.coverage.model;x-friends:="com.microsoft.java.test.plugin.test" 58 | Bundle-ClassPath: . 59 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/testng/TestNGRunner.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.testng; 13 | 14 | import org.testng.ITestListener; 15 | import org.testng.ITestNGListener; 16 | import org.testng.TestNG; 17 | import org.testng.xml.XmlClass; 18 | import org.testng.xml.XmlInclude; 19 | import org.testng.xml.XmlSuite; 20 | import org.testng.xml.XmlTest; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Collections; 24 | import java.util.List; 25 | import java.util.Map; 26 | import java.util.Map.Entry; 27 | import java.util.UUID; 28 | 29 | public class TestNGRunner { 30 | public void run(Map> map) { 31 | final XmlSuite suite = new XmlSuite(); 32 | createTests(map, suite); 33 | 34 | final TestNG testNG = new TestNG(); 35 | testNG.setUseDefaultListeners(false); 36 | final ITestNGListener listener = new TestNGListener(); 37 | try { 38 | testNG.addListener(listener); 39 | } catch (NoSuchMethodError e) { 40 | // backward compatibility 41 | testNG.addListener((ITestListener) listener); 42 | } 43 | 44 | testNG.setXmlSuites(Collections.singletonList(suite)); 45 | testNG.run(); 46 | } 47 | 48 | private void createTests(Map> map, XmlSuite suite) { 49 | final XmlTest test = new XmlTest(suite); 50 | test.setName("TestNGTest-" + UUID.randomUUID().toString()); 51 | final List classes = new ArrayList<>(); 52 | for (final Entry> entry : map.entrySet()) { 53 | classes.add(createClass(entry.getKey(), entry.getValue())); 54 | } 55 | test.setXmlClasses(classes); 56 | } 57 | 58 | private XmlClass createClass(String clazz, List methods) { 59 | final XmlClass xmlClass = new XmlClass(clazz); 60 | if (methods.size() != 0) { 61 | final List includes = new ArrayList<>(); 62 | for (final String method : methods) { 63 | includes.add(new XmlInclude(method.replaceAll("\\(.*\\)", ""))); 64 | } 65 | xmlClass.setIncludedMethods(includes); 66 | } 67 | return xmlClass; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/testng/TestNGLauncher.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.testng; 13 | 14 | import com.microsoft.java.test.runner.common.ITestLauncher; 15 | import com.microsoft.java.test.runner.common.TestMessageItem; 16 | import com.microsoft.java.test.runner.common.TestOutputStream; 17 | 18 | import java.util.ArrayList; 19 | import java.util.HashMap; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | public class TestNGLauncher implements ITestLauncher { 24 | 25 | @Override 26 | public void execute(String[] args) { 27 | try { 28 | if (args == null || args.length == 0) { 29 | throw new RuntimeException("No test found to run."); 30 | } 31 | final TestNGRunner runner = new TestNGRunner(); 32 | runner.run(parse(args)); 33 | } catch (final ClassNotFoundException ex) { 34 | TestOutputStream.instance().println(new TestMessageItem("Failed to run TestNG tests", ex)); 35 | } 36 | } 37 | 38 | private Map> parse(String[] args) throws ClassNotFoundException { 39 | final Map> classToMethodsMap = new HashMap<>(); 40 | for (final String arg : args) { 41 | if (arg.indexOf("#") >= 0) { 42 | // The test target is a method 43 | classToMethodsMap.computeIfAbsent(getClassNameFromMethod(arg), e -> new ArrayList<>()) 44 | .add(getMethodName(arg)); 45 | } else { 46 | classToMethodsMap.put(getClassName(arg), new ArrayList<>()); 47 | } 48 | } 49 | return classToMethodsMap; 50 | } 51 | 52 | private static String getClassName(String testId) throws ClassNotFoundException { 53 | return Class.forName(testId, false, TestNGLauncher.class.getClassLoader()).getName(); 54 | } 55 | 56 | private static String getClassNameFromMethod(String testId) throws ClassNotFoundException { 57 | return Class.forName(testId.substring(0, testId.lastIndexOf("#")), false, 58 | TestNGLauncher.class.getClassLoader()).getName(); 59 | } 60 | 61 | private static String getMethodName(String testId) { 62 | return testId.substring(testId.lastIndexOf("#") + 1); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/JUnit6TestSearcher.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017-2025 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.searcher; 13 | 14 | import com.microsoft.java.test.plugin.model.TestKind; 15 | 16 | import org.eclipse.core.runtime.CoreException; 17 | import org.eclipse.core.runtime.IProgressMonitor; 18 | import org.eclipse.core.runtime.OperationCanceledException; 19 | import org.eclipse.jdt.core.IJavaElement; 20 | import org.eclipse.jdt.core.IType; 21 | import org.eclipse.jdt.core.JavaModelException; 22 | import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry; 23 | 24 | import java.util.Collections; 25 | import java.util.HashSet; 26 | import java.util.Set; 27 | 28 | /** 29 | * Test searcher for JUnit 6 (Jupiter API 6.x). 30 | * 31 | *

JUnit 6 is an evolutionary release built on top of JUnit 5's Jupiter platform. 32 | * It maintains full backward compatibility with JUnit 5 while adding improvements 33 | * and new features. This class extends JUnit5TestSearcher to inherit all the 34 | * Jupiter test detection logic, only overriding the parts specific to JUnit 6: 35 | *

    36 | *
  • Test kind identification (JUnit6 vs JUnit5)
  • 37 | *
  • Test finder instance (uses JUnit6TestFinder for proper classpath resolution)
  • 38 | *
39 | * 40 | * @see JUnit5TestSearcher 41 | * @see JUnit6TestFinder 42 | */ 43 | public class JUnit6TestSearcher extends JUnit5TestSearcher { 44 | 45 | private static final JUnit6TestFinder JUNIT6_TEST_FINDER = new JUnit6TestFinder(); 46 | 47 | @Override 48 | public TestKind getTestKind() { 49 | return TestKind.JUnit6; 50 | } 51 | 52 | @Override 53 | public String getJdtTestKind() { 54 | return TestKindRegistry.JUNIT6_TEST_KIND_ID; 55 | } 56 | 57 | @Override 58 | public boolean isTestClass(IType type) throws JavaModelException { 59 | return JUNIT6_TEST_FINDER.isTest(type); 60 | } 61 | 62 | @Override 63 | public Set findTestItemsInContainer(IJavaElement element, IProgressMonitor monitor) throws CoreException { 64 | final Set types = new HashSet<>(); 65 | try { 66 | JUNIT6_TEST_FINDER.findTestsInContainer(element, types, monitor); 67 | } catch (OperationCanceledException e) { 68 | return Collections.emptySet(); 69 | } 70 | return types; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/provider/JavaTestCoverageProvider.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import { BranchCoverage, DeclarationCoverage, FileCoverage, FileCoverageDetail, Position, StatementCoverage, TestRun, Uri } from 'vscode'; 5 | import { getJacocoReportBasePath } from '../utils/coverageUtils'; 6 | import { executeJavaLanguageServerCommand } from '../utils/commandUtils'; 7 | import { JavaTestRunnerDelegateCommands } from '../constants'; 8 | 9 | export class JavaTestCoverageProvider { 10 | 11 | private coverageDetails: Map = new Map(); 12 | 13 | public async provideFileCoverage(run: TestRun, projectName: string): Promise { 14 | const sourceFileCoverages: ISourceFileCoverage[] = await executeJavaLanguageServerCommand(JavaTestRunnerDelegateCommands.GET_COVERAGE_DETAIL, 15 | projectName, getJacocoReportBasePath(projectName)) || []; 16 | for (const sourceFileCoverage of sourceFileCoverages) { 17 | const uri: Uri = Uri.parse(sourceFileCoverage.uriString); 18 | const detailedCoverage: FileCoverageDetail[] = []; 19 | for (const lineCoverage of sourceFileCoverage.lineCoverages) { 20 | const branchCoverages: BranchCoverage[] = []; 21 | for (const branchCoverage of lineCoverage.branchCoverages) { 22 | branchCoverages.push(new BranchCoverage(branchCoverage.hit, new Position(lineCoverage.lineNumber - 1, 0))); 23 | } 24 | const statementCoverage: StatementCoverage = new StatementCoverage(lineCoverage.hit, 25 | new Position(lineCoverage.lineNumber - 1, 0), branchCoverages); 26 | detailedCoverage.push(statementCoverage); 27 | } 28 | for (const methodCoverage of sourceFileCoverage.methodCoverages) { 29 | const functionCoverage: DeclarationCoverage = new DeclarationCoverage(methodCoverage.name, methodCoverage.hit, 30 | new Position(methodCoverage.lineNumber - 1, 0)); 31 | detailedCoverage.push(functionCoverage); 32 | } 33 | run.addCoverage(FileCoverage.fromDetails(uri, detailedCoverage)); 34 | this.coverageDetails.set(uri, detailedCoverage); 35 | } 36 | } 37 | 38 | public getCoverageDetails(uri: Uri): FileCoverageDetail[] { 39 | return this.coverageDetails.get(uri) || []; 40 | } 41 | } 42 | 43 | interface ISourceFileCoverage { 44 | uriString: string; 45 | lineCoverages: ILineCoverage[]; 46 | methodCoverages: IMethodCoverages[]; 47 | } 48 | 49 | interface ILineCoverage { 50 | lineNumber: number; 51 | hit: number; 52 | branchCoverages: IBranchCoverage[]; 53 | } 54 | 55 | interface IBranchCoverage { 56 | hit: number; 57 | } 58 | 59 | interface IMethodCoverages { 60 | lineNumber: number; 61 | hit: number; 62 | name: string; 63 | } 64 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/provider/TestKindProvider.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2021 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.provider; 13 | 14 | import com.microsoft.java.test.plugin.model.TestKind; 15 | import com.microsoft.java.test.plugin.util.JUnitPlugin; 16 | 17 | import org.eclipse.jdt.core.IJavaProject; 18 | import org.eclipse.jdt.core.JavaModelException; 19 | import org.eclipse.jdt.internal.junit.util.CoreTestSearchEngine; 20 | 21 | import java.util.HashMap; 22 | import java.util.LinkedList; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | public class TestKindProvider { 27 | private static Map> map = new HashMap<>(); 28 | private static final String JUNIT4_TEST = "org.junit.Test"; 29 | private static final String JUNIT5_TEST = "org.junit.jupiter.api.Test"; 30 | private static final String TESTNG_TEST = "org.testng.annotations.Test"; 31 | 32 | public static void updateTestKinds(IJavaProject javaProject) { 33 | map.put(javaProject, getTestKinds(javaProject)); 34 | } 35 | 36 | public static List getTestKindsFromCache(IJavaProject javaProject) { 37 | List kinds = map.get(javaProject); 38 | if (kinds == null) { 39 | kinds = getTestKinds(javaProject); 40 | map.put(javaProject, kinds); 41 | } 42 | return kinds; 43 | } 44 | 45 | private static List getTestKinds(IJavaProject javaProject) { 46 | final List result = new LinkedList<>(); 47 | try { 48 | // Check for JUnit 6 first using Eclipse JDT's built-in detection 49 | if (CoreTestSearchEngine.hasJUnit6TestAnnotation(javaProject)) { 50 | result.add(TestKind.JUnit6); 51 | } else if (CoreTestSearchEngine.hasJUnit5TestAnnotation(javaProject)) { 52 | result.add(TestKind.JUnit5); 53 | } 54 | 55 | if (javaProject.findType(JUNIT4_TEST) != null) { 56 | result.add(TestKind.JUnit); 57 | } 58 | 59 | if (javaProject.findType(TESTNG_TEST) != null) { 60 | result.add(TestKind.TestNG); 61 | } 62 | } catch (JavaModelException e) { 63 | JUnitPlugin.logError("failed to find the test kinds from project: " + javaProject.getElementName()); 64 | } 65 | return result; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /.azure-pipelines/vscode-java-test-ci.yml: -------------------------------------------------------------------------------- 1 | name: $(Date:yyyyMMdd).$(Rev:r) 2 | variables: 3 | - name: Codeql.Enabled 4 | value: true 5 | resources: 6 | repositories: 7 | - repository: self 8 | type: git 9 | ref: refs/heads/main 10 | - repository: 1esPipelines 11 | type: git 12 | name: 1ESPipelineTemplates/1ESPipelineTemplates 13 | ref: refs/tags/release 14 | trigger: 15 | branches: 16 | include: 17 | - main 18 | extends: 19 | template: v1/1ES.Unofficial.PipelineTemplate.yml@1esPipelines 20 | parameters: 21 | pool: 22 | os: linux 23 | name: 1ES_JavaTooling_Pool 24 | image: 1ES_JavaTooling_Ubuntu-2004 25 | sdl: 26 | sourceAnalysisPool: 27 | name: 1ES_JavaTooling_Pool 28 | image: 1ES_JavaTooling_Windows_2022 29 | os: windows 30 | customBuildTags: 31 | - MigrationTooling-mseng-VSJava-8790-Tool 32 | stages: 33 | - stage: Build 34 | jobs: 35 | - job: Job_1 36 | displayName: VSCode-Test-Runner-CI 37 | templateContext: 38 | outputs: 39 | - output: pipelineArtifact 40 | artifactName: extension 41 | targetPath: $(Build.ArtifactStagingDirectory) 42 | displayName: "Publish Artifact: extension" 43 | steps: 44 | - checkout: self 45 | fetchTags: false 46 | - task: JavaToolInstaller@0 47 | displayName: Use Java 21 48 | inputs: 49 | versionSpec: "21" 50 | jdkArchitectureOption: x64 51 | jdkSourceOption: PreInstalled 52 | - task: Npm@1 53 | displayName: npm install 54 | inputs: 55 | verbose: false 56 | - task: Npm@1 57 | displayName: npm run lint 58 | inputs: 59 | command: custom 60 | verbose: false 61 | customCommand: run lint 62 | - task: Npm@1 63 | displayName: npm run build-plugin 64 | inputs: 65 | command: custom 66 | verbose: false 67 | customCommand: run build-plugin 68 | - task: Npm@1 69 | displayName: npm run vscode:prepublish 70 | inputs: 71 | command: custom 72 | verbose: false 73 | customCommand: run vscode:prepublish 74 | - task: Bash@3 75 | displayName: vsce package 76 | inputs: 77 | targetType: inline 78 | script: npx @vscode/vsce@latest package 79 | - task: CopyFiles@2 80 | displayName: "Copy Files to: $(Build.ArtifactStagingDirectory)" 81 | inputs: 82 | Contents: "*.vsix" 83 | TargetFolder: $(Build.ArtifactStagingDirectory) 84 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/searcher/JUnit4TestSearcher.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2017-2021 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.searcher; 13 | 14 | import com.microsoft.java.test.plugin.model.TestKind; 15 | 16 | import org.eclipse.core.runtime.CoreException; 17 | import org.eclipse.core.runtime.IProgressMonitor; 18 | import org.eclipse.core.runtime.OperationCanceledException; 19 | import org.eclipse.jdt.core.IJavaElement; 20 | import org.eclipse.jdt.core.IType; 21 | import org.eclipse.jdt.core.JavaModelException; 22 | import org.eclipse.jdt.core.dom.IMethodBinding; 23 | import org.eclipse.jdt.core.dom.Modifier; 24 | import org.eclipse.jdt.internal.junit.launcher.JUnit4TestFinder; 25 | import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry; 26 | 27 | import java.util.Collections; 28 | import java.util.HashSet; 29 | import java.util.Set; 30 | 31 | public class JUnit4TestSearcher extends BaseFrameworkSearcher { 32 | 33 | private static final JUnit4TestFinder JUNIT4_TEST_FINDER = new JUnit4TestFinder(); 34 | 35 | public JUnit4TestSearcher() { 36 | super(); 37 | this.testMethodAnnotations = new String[] { "org.junit.Test", "org.junit.experimental.theories.Theory" }; 38 | } 39 | 40 | @Override 41 | public TestKind getTestKind() { 42 | return TestKind.JUnit; 43 | } 44 | 45 | @Override 46 | public String getJdtTestKind() { 47 | return TestKindRegistry.JUNIT4_TEST_KIND_ID; 48 | } 49 | 50 | @Override 51 | public boolean isTestMethod(IMethodBinding methodBinding) { 52 | final int modifiers = methodBinding.getModifiers(); 53 | if (Modifier.isAbstract(modifiers) || Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) { 54 | return false; 55 | } 56 | 57 | if (methodBinding.isConstructor() || !"void".equals(methodBinding.getReturnType().getName())) { 58 | return false; 59 | } 60 | 61 | return this.findAnnotation(methodBinding.getAnnotations(), this.getTestMethodAnnotations()); 62 | } 63 | 64 | @Override 65 | public boolean isTestClass(IType type) throws JavaModelException { 66 | return JUNIT4_TEST_FINDER.isTest(type); 67 | } 68 | 69 | @Override 70 | public Set findTestItemsInContainer(IJavaElement element, IProgressMonitor monitor) throws CoreException { 71 | final Set types = new HashSet<>(); 72 | try { 73 | JUNIT4_TEST_FINDER.findTestsInContainer(element, types, monitor); 74 | } catch (OperationCanceledException e) { 75 | return Collections.emptySet(); 76 | } 77 | 78 | return types; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/common/TestOutputStream.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner.common; 13 | 14 | import com.google.gson.Gson; 15 | import com.google.gson.GsonBuilder; 16 | import com.google.gson.JsonElement; 17 | import com.google.gson.JsonObject; 18 | import com.google.gson.JsonSerializationContext; 19 | import com.google.gson.JsonSerializer; 20 | 21 | import java.io.OutputStream; 22 | import java.io.PrintWriter; 23 | import java.lang.reflect.Type; 24 | 25 | public class TestOutputStream implements TestStream { 26 | 27 | private PrintWriter out; 28 | 29 | private static final JsonSerializer serializer = new JsonSerializer() { 30 | @Override 31 | public JsonElement serialize(TestMessageItem item, Type typeOfSrc, JsonSerializationContext context) { 32 | final JsonObject jsonMsgItem = new JsonObject(); 33 | jsonMsgItem.addProperty("name", item.name); 34 | if (item.attributes != null) { 35 | final JsonObject jsonAttributes = new JsonObject(); 36 | for (final Pair pair : item.attributes) { 37 | jsonAttributes.addProperty(pair.first, pair.second); 38 | } 39 | jsonMsgItem.add("attributes", jsonAttributes); 40 | } 41 | return jsonMsgItem; 42 | } 43 | }; 44 | 45 | private TestOutputStream() { } 46 | 47 | public void initialize(OutputStream outputStream) { 48 | if (out == null) { 49 | out = new PrintWriter(outputStream, true); 50 | } 51 | } 52 | 53 | private static class SingletonHelper { 54 | private static final TestOutputStream INSTANCE = new TestOutputStream(); 55 | } 56 | 57 | public static TestOutputStream instance() { 58 | return SingletonHelper.INSTANCE; 59 | } 60 | 61 | @Override 62 | public void println(TestMessageItem item) { 63 | final String content = toJson(item); 64 | out.println(content); 65 | out.println(); 66 | } 67 | 68 | @Override 69 | public void close() { 70 | out.close(); 71 | } 72 | 73 | private static String toJson(TestMessageItem item) { 74 | final GsonBuilder gsonBuilder = new GsonBuilder(); 75 | gsonBuilder.registerTypeAdapter(TestMessageItem.class, serializer); 76 | final Gson customGson = gsonBuilder.create(); 77 | 78 | final StringBuilder builder = new StringBuilder("@@"); 81 | return builder.toString(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/commands/projectExplorerCommands.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as path from 'path'; 5 | import { TestItem, TestRunRequest, Uri } from 'vscode'; 6 | import { sendError } from 'vscode-extension-telemetry-wrapper'; 7 | import { loadChildren, runTests, testController } from '../controller/testController'; 8 | import { loadJavaProjects, updateItemForDocument } from '../controller/utils'; 9 | import { IProgressReporter } from '../debugger.api'; 10 | import { progressProvider } from '../extension'; 11 | import { TestLevel } from '../java-test-runner.api'; 12 | 13 | export async function runTestsFromJavaProjectExplorer(node: any, isDebug: boolean): Promise { 14 | const testLevel: TestLevel = getTestLevel(node._nodeData); 15 | const isHierarchicalMode: boolean = isHierarchical(node._nodeData); 16 | const progressReporter: IProgressReporter | undefined = progressProvider?.createProgressReporter(isDebug ? 'Debug Test' : 'Run Test'); 17 | progressReporter?.report('Searching tests...'); 18 | const tests: TestItem[] = []; 19 | if (testLevel === TestLevel.Class) { 20 | tests.push(...await updateItemForDocument(node._nodeData.uri)); 21 | } else if (testLevel === TestLevel.Package) { 22 | if (!testController?.items.size) { 23 | await loadJavaProjects(); 24 | } 25 | const projectName: string = node._project.name; 26 | const projectItem: TestItem | undefined = testController!.items.get(projectName); 27 | if (!projectItem) { 28 | sendError(new Error('The project name of the node in java project explorer cannot be found in test explorer')); 29 | return; 30 | } 31 | await loadChildren(projectItem); 32 | const nodeFsPath: string = Uri.parse(node._nodeData.uri).fsPath; 33 | projectItem.children.forEach((child: TestItem) => { 34 | const itemPath: string = child.uri?.fsPath || ''; 35 | if (isHierarchicalMode || node._nodeData.kind === 3 /* packageRoot */) { 36 | // if the selected node is a package root or the view is in hierarchical mode, 37 | // all the test items whose path start from the path of the selected node will be added 38 | if (itemPath.startsWith(nodeFsPath)) { 39 | tests.push(child); 40 | } 41 | } else { 42 | // in flat mode, we require the paths exact match 43 | if (path.relative(itemPath, nodeFsPath) === '') { 44 | tests.push(child); 45 | } 46 | } 47 | }); 48 | } 49 | 50 | const request: TestRunRequest = new TestRunRequest(tests, undefined); 51 | 52 | await runTests(request, { progressReporter, isDebug }); 53 | } 54 | 55 | function getTestLevel(nodeData: any): TestLevel { 56 | // The command will only register on the class/package/packageRoot 57 | // nodes of the Java Project explorer 58 | if (nodeData.kind === 5 /* PrimaryType */) { 59 | return TestLevel.Class; 60 | } else { 61 | return TestLevel.Package; 62 | } 63 | } 64 | 65 | function isHierarchical(nodeData: any): boolean { 66 | return !!nodeData.isPackage; 67 | } 68 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/handler/ClasspathUpdateHandler.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2021 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.handler; 13 | 14 | import com.microsoft.java.test.plugin.provider.TestKindProvider; 15 | 16 | import org.eclipse.jdt.core.ElementChangedEvent; 17 | import org.eclipse.jdt.core.IElementChangedListener; 18 | import org.eclipse.jdt.core.IJavaElement; 19 | import org.eclipse.jdt.core.IJavaElementDelta; 20 | import org.eclipse.jdt.core.IJavaProject; 21 | import org.eclipse.jdt.core.JavaCore; 22 | 23 | import java.util.HashSet; 24 | import java.util.Set; 25 | 26 | public class ClasspathUpdateHandler implements IElementChangedListener { 27 | 28 | @Override 29 | public void elementChanged(ElementChangedEvent event) { 30 | // Collect project names which have classpath changed. 31 | final Set projects = processDelta(event.getDelta(), null); 32 | if (projects != null && projects != null) { 33 | for (final IJavaProject project : projects) { 34 | TestKindProvider.updateTestKinds(project); 35 | } 36 | } 37 | } 38 | 39 | public void addElementChangeListener() { 40 | JavaCore.addElementChangedListener(this); 41 | } 42 | 43 | public void removeElementChangeListener() { 44 | JavaCore.removeElementChangedListener(this); 45 | } 46 | 47 | private Set processDeltaChildren(IJavaElementDelta delta, Set projects) { 48 | for (final IJavaElementDelta c : delta.getAffectedChildren()) { 49 | projects = processDelta(c, projects); 50 | } 51 | return projects; 52 | } 53 | 54 | private Set processDelta(IJavaElementDelta delta, Set projects) { 55 | final IJavaElement element = delta.getElement(); 56 | switch (element.getElementType()) { 57 | case IJavaElement.JAVA_MODEL: 58 | projects = processDeltaChildren(delta, projects); 59 | break; 60 | case IJavaElement.JAVA_PROJECT: 61 | if (isClasspathChanged(delta.getFlags())) { 62 | if (projects == null) { 63 | projects = new HashSet(); 64 | } 65 | projects.add((IJavaProject) element); 66 | } 67 | break; 68 | default: 69 | break; 70 | } 71 | return projects; 72 | } 73 | 74 | private boolean isClasspathChanged(int flags) { 75 | return 0 != (flags & (IJavaElementDelta.F_CLASSPATH_CHANGED | IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED | 76 | IJavaElementDelta.F_CLOSED | IJavaElementDelta.F_OPENED)); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.plugin/src/main/java/com/microsoft/java/test/plugin/util/TestItemUtils.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018-2022 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.plugin.util; 13 | 14 | import com.microsoft.java.test.plugin.model.TestKind; 15 | import com.microsoft.java.test.plugin.model.TestLevel; 16 | import org.eclipse.jdt.core.IJavaElement; 17 | import org.eclipse.jdt.core.IMethod; 18 | import org.eclipse.jdt.core.ISourceRange; 19 | import org.eclipse.jdt.core.ISourceReference; 20 | import org.eclipse.jdt.core.IType; 21 | import org.eclipse.jdt.core.JavaModelException; 22 | import org.eclipse.jdt.core.SourceRange; 23 | import org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore; 24 | import org.eclipse.jdt.ls.core.internal.JDTUtils; 25 | import org.eclipse.lsp4j.Range; 26 | 27 | @SuppressWarnings("restriction") 28 | public class TestItemUtils { 29 | 30 | public static Range parseTestItemRange(IJavaElement element) throws JavaModelException { 31 | if (element instanceof ISourceReference) { 32 | final ISourceRange sourceRange = ((ISourceReference) element).getSourceRange(); 33 | final ISourceRange nameRange = ((ISourceReference) element).getNameRange(); 34 | // get the code range excluding the comment part 35 | if (SourceRange.isAvailable(sourceRange) && SourceRange.isAvailable(nameRange)) { 36 | return JDTUtils.toRange(element.getOpenable(), nameRange.getOffset(), 37 | sourceRange.getLength() - nameRange.getOffset() + sourceRange.getOffset()); 38 | } 39 | } 40 | return null; 41 | } 42 | 43 | public static String parseFullName(IJavaElement element, TestLevel level, TestKind kind) { 44 | switch (level) { 45 | case CLASS: 46 | final IType type = (IType) element; 47 | return type.getFullyQualifiedName(); 48 | case METHOD: 49 | final IMethod method = (IMethod) element; 50 | if (kind == TestKind.JUnit5 || kind == TestKind.JUnit6 || kind == TestKind.TestNG) { 51 | final String className = method.getDeclaringType().getFullyQualifiedName(); 52 | // Generics don't come through in the test results, so we need to strip 53 | // them out now. 54 | final String methodName = JavaElementLabelsCore.getElementLabel(element, 55 | JavaElementLabelsCore.ALL_DEFAULT) 56 | .replaceAll("<.*?>", ""); 57 | return className + "#" + methodName; 58 | } else { 59 | return method.getDeclaringType().getFullyQualifiedName() + "#" + method.getElementName(); 60 | } 61 | default: 62 | return element.getElementName(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | linux: 11 | name: Linux 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 30 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Setup Build Environment 18 | run: | 19 | sudo apt-get update 20 | sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 21 | sudo /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & 22 | sleep 3 23 | 24 | - name: Set up JDK 21 25 | uses: actions/setup-java@v1 26 | with: 27 | java-version: '21' 28 | 29 | - name: Setup Node.js environment 30 | uses: actions/setup-node@v2 31 | with: 32 | node-version: 20 33 | 34 | - name: Install Node.js modules 35 | run: npm install 36 | 37 | - name: Lint 38 | run: npm run lint 39 | 40 | - name: Build OSGi bundle 41 | run: npm run build-plugin 42 | 43 | - name: prepublish 44 | run: npm run vscode:prepublish 45 | 46 | - name: Test extension 47 | run: DISPLAY=:99 npm test 48 | 49 | - name: Print language server Log if job failed 50 | if: ${{ failure() }} 51 | run: find $HOME/.config/Code/User/workspaceStorage/*/redhat.java/jdt_ws/.metadata/.log -print -exec cat '{}' \;; 52 | 53 | windows: 54 | name: Windows 55 | runs-on: windows-latest 56 | timeout-minutes: 30 57 | steps: 58 | - uses: actions/checkout@v2 59 | 60 | - name: Set up JDK 21 61 | uses: actions/setup-java@v1 62 | with: 63 | java-version: '21' 64 | 65 | - name: Setup Node.js environment 66 | uses: actions/setup-node@v2 67 | with: 68 | node-version: 20 69 | 70 | - name: Install Node.js modules 71 | run: npm install 72 | 73 | - name: Lint 74 | run: npm run lint 75 | 76 | - name: Build OSGi bundle 77 | run: npm run build-plugin 78 | 79 | - name: prepublish 80 | run: npm run vscode:prepublish 81 | 82 | - name: Test extension 83 | run: npm test 84 | 85 | - name: Print language server Log if job failed 86 | if: ${{ failure() }} 87 | run: Get-ChildItem -Path $env:APPDATA/Code/User/workspaceStorage/*/redhat.java/jdt_ws/.metadata/.log | cat 88 | 89 | darwin: 90 | name: macOS 91 | runs-on: macos-latest 92 | timeout-minutes: 30 93 | steps: 94 | - uses: actions/checkout@v2 95 | 96 | - name: Set up JDK 21 97 | uses: actions/setup-java@v1 98 | with: 99 | java-version: '21' 100 | 101 | - name: Setup Node.js environment 102 | uses: actions/setup-node@v2 103 | with: 104 | node-version: 20 105 | 106 | - name: Install Node.js modules 107 | run: npm install 108 | 109 | - name: Lint 110 | run: npm run lint 111 | 112 | - name: Build OSGi bundle 113 | run: npm run build-plugin 114 | 115 | - name: prepublish 116 | run: npm run vscode:prepublish 117 | 118 | - name: Test extension 119 | run: npm test 120 | 121 | - name: Print language server Log if job failed 122 | if: ${{ failure() }} 123 | run: find $HOME/Library/Application\ Support/Code/User/workspaceStorage/*/redhat.java/jdt_ws/.metadata/.log -print -exec cat '{}' \;; 124 | -------------------------------------------------------------------------------- /java-extension/com.microsoft.java.test.runner/src/main/java/com/microsoft/java/test/runner/Launcher.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Microsoft Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Microsoft Corporation - initial API and implementation 10 | *******************************************************************************/ 11 | 12 | package com.microsoft.java.test.runner; 13 | 14 | import com.microsoft.java.test.runner.common.ITestLauncher; 15 | import com.microsoft.java.test.runner.common.TestMessageItem; 16 | import com.microsoft.java.test.runner.common.TestOutputStream; 17 | import com.microsoft.java.test.runner.exceptions.ParameterException; 18 | import com.microsoft.java.test.runner.testng.TestNGLauncher; 19 | 20 | import java.io.IOException; 21 | import java.net.Socket; 22 | import java.util.Arrays; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | 26 | public class Launcher { 27 | private static final String TESTNG = "testng"; 28 | private static final String LOCAL_HOST = "127.0.0.1"; 29 | 30 | private static final Map launcherMap; 31 | 32 | static { 33 | launcherMap = new HashMap<>(); 34 | launcherMap.put(TESTNG, new TestNGLauncher()); 35 | } 36 | 37 | private static final int EXIT_WITH_INVALID_INPUT_CODE = -1; 38 | private static final int EXIT_WITH_UNKNOWN_EXCEPTION = -2; 39 | 40 | public static void main(String[] args) { 41 | int exitStatus = 0; 42 | Socket clientSocket = null; 43 | try { 44 | if (args == null || args.length == 0) { 45 | throw new ParameterException("No arguments provided."); 46 | } 47 | 48 | final int portNumber = Integer.parseInt(args[0]); 49 | clientSocket = new Socket(LOCAL_HOST, portNumber); 50 | TestOutputStream.instance().initialize(clientSocket.getOutputStream()); 51 | final ITestLauncher launcher = launcherMap.get(args[1]); 52 | if (launcher == null) { 53 | throw new ParameterException("Unsupported runner type: " + args[1] + "."); 54 | } 55 | 56 | final String[] params = Arrays.copyOfRange(args, 2, args.length); 57 | launcher.execute(params); 58 | } catch (final ParameterException e) { 59 | exitStatus = EXIT_WITH_INVALID_INPUT_CODE; 60 | logError("Invalid Parameter.", e); 61 | } catch (final Throwable e) { 62 | exitStatus = EXIT_WITH_UNKNOWN_EXCEPTION; 63 | logError("Exception occured while running tests.", e); 64 | } finally { 65 | TestOutputStream.instance().close(); 66 | try { 67 | if (clientSocket != null) { 68 | clientSocket.close(); 69 | } 70 | } catch (IOException e) { 71 | // Do nothing 72 | } 73 | System.exit(exitStatus); 74 | } 75 | } 76 | 77 | private static void logError(String message, Throwable ex) { 78 | System.err.println(message); 79 | ex.printStackTrace(); 80 | TestOutputStream.instance().println(new TestMessageItem(message, ex)); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/provider/testSourceProvider.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as path from 'path'; 5 | import { RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode'; 6 | import { JavaTestRunnerDelegateCommands } from '../constants'; 7 | import { executeJavaLanguageServerCommand } from '../utils/commandUtils'; 8 | 9 | class TestSourcePathProvider { 10 | private testSourceMapping: Map = new Map(); 11 | 12 | public async getTestSourcePattern(workspaceFolder: WorkspaceFolder, containsGeneral: boolean = true): Promise { 13 | const patterns: RelativePattern[] = []; 14 | const sourcePaths: string[] = await testSourceProvider.getTestSourcePath(workspaceFolder, containsGeneral); 15 | for (const sourcePath of sourcePaths) { 16 | const normalizedPath: string = Uri.file(sourcePath).fsPath; 17 | const pattern: RelativePattern = new RelativePattern(normalizedPath, '**/*.java'); 18 | patterns.push(pattern); 19 | } 20 | return patterns; 21 | } 22 | 23 | public async getTestSourcePath(workspaceFolder: WorkspaceFolder, containsGeneral: boolean = true): Promise { 24 | const testPaths: ITestSourcePath[] = await this.getTestPaths(workspaceFolder); 25 | 26 | if (containsGeneral) { 27 | return testPaths.map((s: ITestSourcePath) => s.testSourcePath); 28 | } 29 | 30 | return testPaths.filter((s: ITestSourcePath) => s.isStrict) 31 | .map((s: ITestSourcePath) => s.testSourcePath); 32 | } 33 | 34 | public async isOnTestSourcePath(uri: Uri): Promise { 35 | const workspaceFolder: WorkspaceFolder | undefined = workspace.getWorkspaceFolder(uri); 36 | if (!workspaceFolder) { 37 | return false; 38 | } 39 | const testPaths: ITestSourcePath[] = await this.getTestPaths(workspaceFolder); 40 | const fsPath: string = uri.fsPath; 41 | for (const testPath of testPaths) { 42 | const relativePath: string = path.relative(testPath.testSourcePath, fsPath); 43 | if (!relativePath.startsWith('..')) { 44 | return true; 45 | } 46 | } 47 | return false; 48 | } 49 | 50 | public clear(): void { 51 | this.testSourceMapping.clear(); 52 | } 53 | 54 | public delete(workspaceUri: Uri): boolean { 55 | return this.testSourceMapping.delete(workspaceUri); 56 | } 57 | 58 | private async getTestPaths(workspaceFolder: WorkspaceFolder): Promise { 59 | let testPaths: ITestSourcePath[] | undefined = this.testSourceMapping.get(workspaceFolder.uri); 60 | if (!testPaths) { 61 | testPaths = await getTestSourcePaths([workspaceFolder.uri.toString()]); 62 | this.testSourceMapping.set(workspaceFolder.uri, testPaths); 63 | } 64 | return testPaths; 65 | } 66 | } 67 | 68 | async function getTestSourcePaths(uri: string[]): Promise { 69 | return await executeJavaLanguageServerCommand( 70 | JavaTestRunnerDelegateCommands.GET_TEST_SOURCE_PATH, uri) || []; 71 | } 72 | 73 | interface ITestSourcePath { 74 | testSourcePath: string; 75 | /** 76 | * All the source paths from eclipse and invisible project will be treated as test source 77 | * even they are not marked as test in the classpath entry, in that case, this field will be false. 78 | */ 79 | isStrict: boolean; 80 | } 81 | 82 | export const testSourceProvider: TestSourcePathProvider = new TestSourcePathProvider(); 83 | --------------------------------------------------------------------------------