diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e09867b..ce05376 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,10 +13,12 @@ junit-jupiter = "5.11.4" slf4j-api = "1.7.36" xerces = "2.12.2" awaitility = "4.2.2" +classgraph = "4.8.162" [libraries] sonar-plugin-api = { group = "org.sonarsource.api.plugin", name = "sonar-plugin-api", version.ref = "plugin-api" } sonar-analyzer-commons = { group = "org.sonarsource.analyzer-commons", name = "sonar-analyzer-commons", version.ref = "analyzer-commons" } +sonar-analyzer-test-commons = { group = "org.sonarsource.analyzer-commons", name = "sonar-analyzer-test-commons", version.ref = "analyzer-commons" } slang-api = { group = "org.sonarsource.slang", name = "slang-api", version.ref = "slang-dependencies" } slang-checks = { group = "org.sonarsource.slang", name = "slang-checks", version.ref = "slang-dependencies" } slang-plugin = { group = "org.sonarsource.slang", name = "slang-plugin", version.ref = "slang-dependencies" } @@ -29,15 +31,14 @@ sonarlint-core = { group = "org.sonarsource.sonarlint.core", name = "sonarlint-c sonar-lint-rpc-java-client = { module = "org.sonarsource.sonarlint.core:sonarlint-rpc-java-client", version.ref = "sonarlint" } sonar-lint-rpc-impl = { module = "org.sonarsource.sonarlint.core:sonarlint-rpc-impl", version.ref = "sonarlint" } sonar-ws = { group = "org.sonarsource.sonarqube", name = "sonar-ws", version.ref = "sonarqube" } -slang-antlr = { group = "org.sonarsource.slang", name = "slang-antlr", version.ref = "slang-dependencies" } -slang-testing = { group = "org.sonarsource.slang", name = "slang-testing", version.ref = "slang-dependencies" } mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockito-core" } assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertj-core" } junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit-jupiter" } junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit-jupiter" } slf4j-api = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j-api" } xerces = { group = "xerces", name = "xercesImpl", version.ref = "xerces" } -awaitility = { module = "org.awaitility:awaitility", version.ref = "awaitility"} +awaitility = { group = "org.awaitility", name = "awaitility", version.ref = "awaitility"} +classgraph = { group = "io.github.classgraph", name = "classgraph", version.ref = "classgraph"} [plugins] shadow = { id = "com.gradleup.shadow", version = "8.3.5" } diff --git a/sonar-go-plugin/build.gradle.kts b/sonar-go-plugin/build.gradle.kts index 3e387f4..59e883d 100644 --- a/sonar-go-plugin/build.gradle.kts +++ b/sonar-go-plugin/build.gradle.kts @@ -43,10 +43,10 @@ dependencies { runtimeOnly(files(project.project(":sonar-go-to-slang").buildDir)) - testImplementation(libs.slang.antlr) testImplementation(libs.assertj.core) testImplementation(libs.mockito.core) - testImplementation(libs.slang.testing) + testImplementation(libs.sonar.analyzer.test.commons) + testImplementation(libs.classgraph) testImplementation(libs.junit.jupiter.api) testImplementation(libs.sonar.plugin.api.impl) testImplementation(libs.sonar.plugin.api.test.fixtures) diff --git a/sonar-go-plugin/src/test/java/org/sonar/go/checks/GoVerifier.java b/sonar-go-plugin/src/test/java/org/sonar/go/checks/GoVerifier.java index f16b12e..45d5203 100644 --- a/sonar-go-plugin/src/test/java/org/sonar/go/checks/GoVerifier.java +++ b/sonar-go-plugin/src/test/java/org/sonar/go/checks/GoVerifier.java @@ -16,17 +16,156 @@ */ package org.sonar.go.checks; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.function.BiConsumer; +import javax.annotation.Nullable; import org.sonar.go.converter.GoConverter; +import org.sonarsource.analyzer.commons.checks.verifier.SingleFileVerifier; import org.sonarsource.slang.api.ASTConverter; +import org.sonarsource.slang.api.HasTextRange; +import org.sonarsource.slang.api.TextPointer; +import org.sonarsource.slang.api.TextRange; +import org.sonarsource.slang.api.TopLevelTree; +import org.sonarsource.slang.api.Tree; +import org.sonarsource.slang.checks.api.CheckContext; +import org.sonarsource.slang.checks.api.InitContext; +import org.sonarsource.slang.checks.api.SecondaryLocation; import org.sonarsource.slang.checks.api.SlangCheck; +import org.sonarsource.slang.visitors.TreeContext; +import org.sonarsource.slang.visitors.TreeVisitor; + +import static java.nio.charset.StandardCharsets.UTF_8; public class GoVerifier { private static final Path BASE_DIR = Paths.get("src", "test", "resources", "checks"); private static final ASTConverter CONVERTER = new GoConverter(Paths.get("build", "tmp").toFile()); public static void verify(String fileName, SlangCheck check) { - org.sonarsource.slang.testing.Verifier.verify(CONVERTER, BASE_DIR.resolve(fileName), check); + verify(CONVERTER, BASE_DIR.resolve(fileName), check); + } + + public static void verify(ASTConverter converter, Path path, SlangCheck check) { + createVerifier(converter, path, check).assertOneOrMoreIssues(); + } + + public static void verifyNoIssue(ASTConverter converter, Path path, SlangCheck check) { + createVerifier(converter, path, check).assertNoIssues(); + } + + private static SingleFileVerifier createVerifier(ASTConverter converter, Path path, SlangCheck check) { + + SingleFileVerifier verifier = SingleFileVerifier.create(path, UTF_8); + + String testFileContent = readFile(path); + Tree root = converter.parse(testFileContent, null); + + ((TopLevelTree) root).allComments() + .forEach(comment -> { + TextPointer start = comment.textRange().start(); + verifier.addComment(start.line(), start.lineOffset() + 1, comment.text(), 2, 0); + }); + + TestContext ctx = new TestContext(verifier, path.getFileName().toString(), testFileContent); + check.initialize(ctx); + ctx.scan(root); + + return verifier; + } + + private static String readFile(Path path) { + try { + return new String(Files.readAllBytes(path), UTF_8); + } catch (IOException e) { + throw new IllegalStateException("Cannot read " + path, e); + } + } + + private static class TestContext extends TreeContext implements InitContext, CheckContext { + + private final TreeVisitor visitor; + private final SingleFileVerifier verifier; + private final String filename; + private String testFileContent; + + public TestContext(SingleFileVerifier verifier, String filename, String testFileContent) { + this.verifier = verifier; + this.filename = filename; + this.testFileContent = testFileContent; + visitor = new TreeVisitor<>(); + } + + public void scan(@Nullable Tree root) { + visitor.scan(this, root); + } + + @Override + public void register(Class cls, BiConsumer consumer) { + visitor.register(cls, (ctx, node) -> consumer.accept(this, node)); + } + + @Override + public void reportIssue(HasTextRange toHighlight, String message) { + reportIssue(toHighlight, message, Collections.emptyList()); + } + + @Override + public void reportIssue(HasTextRange toHighlight, String message, SecondaryLocation secondaryLocation) { + reportIssue(toHighlight, message, Collections.singletonList(secondaryLocation)); + } + + @Override + public String filename() { + return filename; + } + + @Override + public String fileContent() { + return testFileContent; + } + + @Override + public void reportIssue(TextRange textRange, String message) { + reportIssue(textRange, message, Collections.emptyList(), null); + } + + @Override + public void reportIssue(HasTextRange toHighlight, String message, List secondaryLocations) { + reportIssue(toHighlight, message, secondaryLocations, null); + } + + @Override + public void reportIssue(HasTextRange toHighlight, String message, List secondaryLocations, @Nullable Double gap) { + reportIssue(toHighlight.textRange(), message, secondaryLocations, gap); + } + + public void reportFileIssue(String message) { + reportFileIssue(message, null); + } + + @Override + public void reportFileIssue(String message, @Nullable Double gap) { + verifier.reportIssue(message).onFile().withGap(gap); + } + + private void reportIssue(TextRange textRange, String message, List secondaryLocations, @Nullable Double gap) { + TextPointer start = textRange.start(); + TextPointer end = textRange.end(); + SingleFileVerifier.Issue issue = verifier + .reportIssue(message) + .onRange(start.line(), start.lineOffset() + 1, end.line(), end.lineOffset()) + .withGap(gap); + secondaryLocations.forEach(secondary -> issue.addSecondary( + secondary.textRange.start().line(), + secondary.textRange.start().lineOffset() + 1, + secondary.textRange.end().line(), + secondary.textRange.end().lineOffset(), + secondary.message)); + } + } } diff --git a/sonar-go-plugin/src/test/java/org/sonar/go/coverage/GoCoverSensorTest.java b/sonar-go-plugin/src/test/java/org/sonar/go/coverage/GoCoverSensorTest.java index e3ad06e..c1b1dc4 100644 --- a/sonar-go-plugin/src/test/java/org/sonar/go/coverage/GoCoverSensorTest.java +++ b/sonar-go-plugin/src/test/java/org/sonar/go/coverage/GoCoverSensorTest.java @@ -34,11 +34,11 @@ import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; import org.sonar.api.batch.sensor.internal.SensorContextTester; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.testfixtures.log.LogTesterJUnit5; import org.sonar.go.coverage.GoCoverSensor.Coverage; import org.sonar.go.coverage.GoCoverSensor.CoverageStat; import org.sonar.go.coverage.GoCoverSensor.FileCoverage; import org.sonar.go.coverage.GoCoverSensor.LineCoverage; -import org.sonarsource.slang.testing.ThreadLocalLogTester; import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; @@ -49,7 +49,7 @@ class GoCoverSensorTest { static final Path COVERAGE_DIR = Paths.get("src", "test", "resources", "coverage"); @RegisterExtension - public ThreadLocalLogTester logTester = new ThreadLocalLogTester(); + public LogTesterJUnit5 logTester = new LogTesterJUnit5().setLevel(Level.DEBUG); @Test void test_descriptor() { diff --git a/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/AbstractReportSensorTest.java b/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/AbstractReportSensorTest.java index a53873e..5118d49 100644 --- a/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/AbstractReportSensorTest.java +++ b/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/AbstractReportSensorTest.java @@ -23,7 +23,7 @@ import org.slf4j.event.Level; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.notifications.AnalysisWarnings; -import org.sonarsource.slang.testing.ThreadLocalLogTester; +import org.sonar.api.testfixtures.log.LogTesterJUnit5; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -31,7 +31,7 @@ class AbstractReportSensorTest { @RegisterExtension - public ThreadLocalLogTester logTester = new ThreadLocalLogTester(); + public LogTesterJUnit5 logTester = new LogTesterJUnit5().setLevel(Level.DEBUG); @Test void report_consumer_logs_io_exception() { diff --git a/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoLintReportSensorTest.java b/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoLintReportSensorTest.java index 3089b70..3548a6b 100644 --- a/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoLintReportSensorTest.java +++ b/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoLintReportSensorTest.java @@ -29,7 +29,7 @@ import org.sonar.api.batch.sensor.internal.SensorContextTester; import org.sonar.api.batch.sensor.issue.ExternalIssue; import org.sonar.api.rules.RuleType; -import org.sonarsource.slang.testing.ThreadLocalLogTester; +import org.sonar.api.testfixtures.log.LogTesterJUnit5; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.go.externalreport.AbstractReportSensor.GENERIC_ISSUE_KEY; @@ -45,7 +45,7 @@ void setup() { } @RegisterExtension - public ThreadLocalLogTester logTester = new ThreadLocalLogTester(); + public LogTesterJUnit5 logTester = new LogTesterJUnit5().setLevel(Level.DEBUG); @Test void test_descriptor() { diff --git a/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoMetaLinterReportSensorTest.java b/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoMetaLinterReportSensorTest.java index cae0e24..171e468 100644 --- a/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoMetaLinterReportSensorTest.java +++ b/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoMetaLinterReportSensorTest.java @@ -28,7 +28,7 @@ import org.sonar.api.batch.sensor.internal.SensorContextTester; import org.sonar.api.batch.sensor.issue.ExternalIssue; import org.sonar.api.rules.RuleType; -import org.sonarsource.slang.testing.ThreadLocalLogTester; +import org.sonar.api.testfixtures.log.LogTesterJUnit5; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.go.externalreport.AbstractReportSensor.GENERIC_ISSUE_KEY; @@ -44,7 +44,7 @@ void setup() { } @RegisterExtension - public ThreadLocalLogTester logTester = new ThreadLocalLogTester(); + public LogTesterJUnit5 logTester = new LogTesterJUnit5().setLevel(Level.DEBUG); @Test void test_descriptor() { diff --git a/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoVetReportSensorTest.java b/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoVetReportSensorTest.java index 8cd0ce4..cbeb5f8 100644 --- a/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoVetReportSensorTest.java +++ b/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GoVetReportSensorTest.java @@ -29,7 +29,7 @@ import org.sonar.api.batch.sensor.internal.SensorContextTester; import org.sonar.api.batch.sensor.issue.ExternalIssue; import org.sonar.api.rules.RuleType; -import org.sonarsource.slang.testing.ThreadLocalLogTester; +import org.sonar.api.testfixtures.log.LogTesterJUnit5; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.go.externalreport.AbstractReportSensor.GENERIC_ISSUE_KEY; @@ -39,14 +39,14 @@ class GoVetReportSensorTest { private final List analysisWarnings = new ArrayList<>(); + @RegisterExtension + public LogTesterJUnit5 logTester = new LogTesterJUnit5().setLevel(Level.DEBUG); + @BeforeEach void setup() { analysisWarnings.clear(); } - @RegisterExtension - public ThreadLocalLogTester logTester = new ThreadLocalLogTester(); - @Test void test_descriptor() { DefaultSensorDescriptor sensorDescriptor = new DefaultSensorDescriptor(); diff --git a/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GolangCILintReportSensorTest.java b/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GolangCILintReportSensorTest.java index 96cde50..20a9f4b 100644 --- a/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GolangCILintReportSensorTest.java +++ b/sonar-go-plugin/src/test/java/org/sonar/go/externalreport/GolangCILintReportSensorTest.java @@ -28,7 +28,7 @@ import org.sonar.api.batch.sensor.internal.SensorContextTester; import org.sonar.api.batch.sensor.issue.ExternalIssue; import org.sonar.api.rules.RuleType; -import org.sonarsource.slang.testing.ThreadLocalLogTester; +import org.sonar.api.testfixtures.log.LogTesterJUnit5; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.go.externalreport.ExternalLinterSensorHelper.REPORT_BASE_PATH; @@ -37,14 +37,14 @@ class GolangCILintReportSensorTest { private final List analysisWarnings = new ArrayList<>(); + @RegisterExtension + public LogTesterJUnit5 logTester = new LogTesterJUnit5().setLevel(Level.DEBUG); + @BeforeEach void setup() { analysisWarnings.clear(); } - @RegisterExtension - public ThreadLocalLogTester logTester = new ThreadLocalLogTester(); - @Test void test_descriptor() { DefaultSensorDescriptor sensorDescriptor = new DefaultSensorDescriptor(); diff --git a/sonar-go-plugin/src/test/java/org/sonar/go/plugin/GoCheckListTest.java b/sonar-go-plugin/src/test/java/org/sonar/go/plugin/GoCheckListTest.java index a8b01d1..69b24aa 100644 --- a/sonar-go-plugin/src/test/java/org/sonar/go/plugin/GoCheckListTest.java +++ b/sonar-go-plugin/src/test/java/org/sonar/go/plugin/GoCheckListTest.java @@ -16,13 +16,17 @@ */ package org.sonar.go.plugin; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import org.sonarsource.slang.testing.PackageScanner; -import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; class GoCheckListTest { @@ -36,7 +40,7 @@ void go_checks_size() { @Test void go_specific_checks_are_added_to_check_list() { List checkListNames = GoCheckList.checks().stream().map(Class::getName).collect(Collectors.toList()); - List languageImplementation = PackageScanner.findSlangChecksInPackage(GO_CHECKS_PACKAGE); + List languageImplementation = findSlangChecksInPackage(GO_CHECKS_PACKAGE); for (String languageCheck : languageImplementation) { assertThat(checkListNames).contains(languageCheck); assertThat(languageCheck).endsWith("GoCheck"); @@ -50,4 +54,24 @@ void go_excluded_not_present() { assertThat(checks).doesNotContain(excluded); } } + + /** + * Returns the fully qualified names (FQNs) of the classes inside @packageName implementing SlangCheck. + * @param packageName Used to filter classes - the FQN of a class contains the package name. + * @return A list of slang checks (FQNs). + */ + private static List findSlangChecksInPackage(String packageName) { + try (ScanResult scanResult = new ClassGraph().enableAllInfo().acceptPackages(packageName).scan()) { + Map allClasses = scanResult.getAllClassesAsMap(); + List testClassesInPackage = new ArrayList<>(); + for (Map.Entry classInfoEntry : allClasses.entrySet()) { + String name = classInfoEntry.getKey(); + ClassInfo classInfo = classInfoEntry.getValue(); + if (name.startsWith(packageName) && classInfo.getInterfaces().stream().anyMatch(i -> i.getSimpleName().equals("SlangCheck"))) { + testClassesInPackage.add(classInfo.getName()); + } + } + return testClassesInPackage; + } + } } diff --git a/sonar-go-plugin/src/test/java/org/sonar/go/plugin/GoSensorTest.java b/sonar-go-plugin/src/test/java/org/sonar/go/plugin/GoSensorTest.java index 85a33e2..12daef1 100644 --- a/sonar-go-plugin/src/test/java/org/sonar/go/plugin/GoSensorTest.java +++ b/sonar-go-plugin/src/test/java/org/sonar/go/plugin/GoSensorTest.java @@ -31,6 +31,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.slf4j.event.Level; +import org.sonar.api.SonarEdition; +import org.sonar.api.SonarQubeSide; +import org.sonar.api.SonarRuntime; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.batch.rule.ActiveRules; @@ -43,14 +46,15 @@ import org.sonar.api.batch.sensor.internal.SensorContextTester; import org.sonar.api.batch.sensor.issue.internal.DefaultNoSonarFilter; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.FileLinesContext; import org.sonar.api.measures.FileLinesContextFactory; import org.sonar.api.rule.RuleKey; +import org.sonar.api.testfixtures.log.LogTesterJUnit5; +import org.sonar.api.utils.Version; import org.sonar.go.converter.GoConverter; import org.sonarsource.slang.checks.api.SlangCheck; -import org.sonarsource.slang.testing.AbstractSensorTest; -import org.sonarsource.slang.testing.ThreadLocalLogTester; import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; @@ -62,6 +66,7 @@ class GoSensorTest { + private static final SonarRuntime SQ_LTS_RUNTIME = SonarRuntimeImpl.forSonarQube(Version.create(8, 9), SonarQubeSide.SCANNER, SonarEdition.DEVELOPER); private Path workDir; private GoConverter singleInstanceGoConverter; private Path projectDir; @@ -70,7 +75,7 @@ class GoSensorTest { private FileLinesContextTester fileLinesContext; @RegisterExtension - public ThreadLocalLogTester logTester = new ThreadLocalLogTester(); + public LogTesterJUnit5 logTester = new LogTesterJUnit5().setLevel(Level.DEBUG); @BeforeEach void setUp() throws IOException { @@ -365,8 +370,8 @@ private GoSensor getSensor(String... activeRuleArray) { ActiveRules activeRules = rulesBuilder.build(); CheckFactory checkFactory = new CheckFactory(activeRules); Checks checks = checkFactory.create(GoRulesDefinition.REPOSITORY_KEY); - checks.addAnnotatedChecks((Iterable) ruleClasses); - return new GoSensor(AbstractSensorTest.SQ_LTS_RUNTIME, checkFactory, fileLinesContextFactory, new DefaultNoSonarFilter(), + checks.addAnnotatedChecks(ruleClasses); + return new GoSensor(SQ_LTS_RUNTIME, checkFactory, fileLinesContextFactory, new DefaultNoSonarFilter(), new GoLanguage(new MapSettings().asConfig()), singleInstanceGoConverter); } diff --git a/sonar-go-plugin/src/test/java/org/sonar/go/testreport/GoTestSensorTest.java b/sonar-go-plugin/src/test/java/org/sonar/go/testreport/GoTestSensorTest.java index 29c2630..4181137 100644 --- a/sonar-go-plugin/src/test/java/org/sonar/go/testreport/GoTestSensorTest.java +++ b/sonar-go-plugin/src/test/java/org/sonar/go/testreport/GoTestSensorTest.java @@ -33,16 +33,16 @@ import org.sonar.api.batch.sensor.internal.SensorContextTester; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.testfixtures.log.LogTesterJUnit5; import org.sonar.go.coverage.GoPathContext; import org.sonar.go.testreport.GoTestSensor.TestInfo; -import org.sonarsource.slang.testing.ThreadLocalLogTester; import static org.assertj.core.api.Assertions.assertThat; class GoTestSensorTest { @RegisterExtension - public ThreadLocalLogTester logTester = new ThreadLocalLogTester(); + public LogTesterJUnit5 logTester = new LogTesterJUnit5().setLevel(Level.DEBUG); private final Path goPath = Paths.get("src", "test", "resources", "testReportGoPath").toAbsolutePath(); private final Path packagePath = Paths.get("github.com", "myOrg", "myProject");