diff --git a/cli-messaging/build.gradle.kts b/cli-messaging/build.gradle.kts index 5062ba8ac..48a495006 100644 --- a/cli-messaging/build.gradle.kts +++ b/cli-messaging/build.gradle.kts @@ -1,5 +1,8 @@ +import java.awt.Desktop + plugins { java + jacoco } version = "1.0" @@ -16,16 +19,45 @@ dependencies { } implementation("com.google.code.gson:gson:2.10.1") implementation("com.google.guava:guava:31.1-jre") + testImplementation("org.hamcrest:hamcrest:2.2") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.2") testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.2") } -tasks.getByName("test") { +tasks.test { + // Use JUnit 5 useJUnitPlatform() testLogging { events("passed", "skipped", "failed") } + // Run tests in multiple threads + maxParallelForks = Runtime.getRuntime().availableProcessors()/2 + 1 + + // Report is always generated after test runs + finalizedBy(tasks.jacocoTestReport) +} + +tasks.jacocoTestReport { + dependsOn(tasks.test) +} + +tasks.register("showCoverageReport") { + group = "verification" + dependsOn(tasks.jacocoTestReport) + doLast { + Desktop.getDesktop().browse(File("$buildDir/reports/jacoco/test/html/index.html").toURI()) + } +} + +tasks.jacocoTestCoverageVerification { + violationRules { + rule { + limit { + minimum = BigDecimal("0.70") // TODO: We should aim to increase this + } + } + } } diff --git a/package.json b/package.json index cde6d73e4..455b8a29a 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "lint-typescript": "eslint ./src --ext .ts --max-warnings 0", "test": "./gradlew test jacocoTestCoverageVerification && nyc mocha --timeout 10000 --retries 5 \"./test/**/*.test.ts\"", "test-quiet": "cross-env SFGE_LOGGING=false ./gradlew test jacocoTestCoverageVerification && nyc mocha --timeout 10000 --retries 5 \"./test/**/*.test.ts\"", - "test-cli-messaging": "./gradlew cli-messaging:test", + "test-cli-messaging": "./gradlew cli-messaging:test cli-messaging:jacocoTestCoverageVerification", "test-pmd-cataloger": "./gradlew pmd-cataloger:test pmd-cataloger:jacocoTestCoverageVerification", "test-sfge": "./gradlew sfge:test sfge:jacocoTestCoverageVerification", "test-sfge-quiet": "cross-env SFGE_LOGGING=false ./gradlew sfge:test sfge:jacocoTestCoverageVerification", diff --git a/pmd-cataloger/build.gradle.kts b/pmd-cataloger/build.gradle.kts index d30476ce9..fe579c7fe 100644 --- a/pmd-cataloger/build.gradle.kts +++ b/pmd-cataloger/build.gradle.kts @@ -1,3 +1,5 @@ +import java.awt.Desktop + plugins { java application @@ -58,21 +60,23 @@ dependencies { implementation ("com.googlecode.json-simple:json-simple:1.1.1") { exclude("junit") } - implementation("com.google.code.gson:gson:2.3") - implementation("com.google.guava:guava:28.0-jre") - testImplementation("org.mockito:mockito-core:1.+") - testImplementation("junit", "junit", "4.12") - testImplementation("org.hamcrest:hamcrest:2.1") + implementation("com.google.code.gson:gson:2.10.1") + implementation("com.google.guava:guava:31.1-jre") + + testImplementation("org.mockito:mockito-core:5.2.0") + testImplementation("org.hamcrest:hamcrest:2.2") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") + testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.2") + testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.2") + // Used in unit tests testImplementation(files("$buildDir/../../test/test-jars/apex/testjar-categories-and-rulesets-1.jar")) } -configure { - sourceCompatibility = JavaVersion.VERSION_1_8 -} +java.sourceCompatibility = JavaVersion.VERSION_1_8 application { - mainClassName = "sfdc.sfdx.scanner.pmd.Main" + mainClass.set("sfdc.sfdx.scanner.pmd.Main"); } // Running the cli locally needs the dist exploded, so just do that @@ -87,18 +91,37 @@ tasks.named("assemble") { } tasks.test { - finalizedBy(tasks.jacocoTestReport) // Report is always generated after test runs. + // Use JUnit 5 + useJUnitPlatform() + + testLogging { + events("passed", "skipped", "failed") + } + + // Run tests in multiple threads + maxParallelForks = Runtime.getRuntime().availableProcessors()/2 + 1 + + // Report is always generated after test runs + finalizedBy(tasks.jacocoTestReport) } tasks.jacocoTestReport { dependsOn(tasks.test) } +tasks.register("showCoverageReport") { + group = "verification" + dependsOn(tasks.jacocoTestReport) + doLast { + Desktop.getDesktop().browse(File("$buildDir/reports/jacoco/test/html/index.html").toURI()) + } +} + tasks.jacocoTestCoverageVerification { violationRules { rule { limit { - minimum = "0.80".toBigDecimal() + minimum = BigDecimal("0.80") } } } diff --git a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/LanguageXmlFileMappingTest.java b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/LanguageXmlFileMappingTest.java index 9a1bf818a..6da1c4631 100644 --- a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/LanguageXmlFileMappingTest.java +++ b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/LanguageXmlFileMappingTest.java @@ -1,32 +1,31 @@ package sfdc.sfdx.scanner.pmd; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.assertThat; -import static sfdc.sfdx.scanner.TestConstants.*; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static sfdc.sfdx.scanner.TestConstants.APEX; +import static sfdc.sfdx.scanner.TestConstants.JAVA; +import static sfdc.sfdx.scanner.TestConstants.SOMECAT_XML_FILE; import java.util.Arrays; import java.util.Map; import java.util.Set; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - import com.salesforce.messaging.EventKey; +import com.salesforce.messaging.MessagePassableException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * Unit test for {@link LanguageXmlFileMapping} */ public class LanguageXmlFileMappingTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - private LanguageXmlFileMapping languageXmlFileMapping; - @Before + @BeforeEach public void setup() { languageXmlFileMapping = new LanguageXmlFileMapping(); } @@ -122,10 +121,9 @@ private void testCollision(String collidingPath) { languageXmlFileMapping.addPathsForLanguage(Arrays.asList(xmlContainer1), APEX); - thrown.expect(new MessagePassableExceptionMatcher(EventKey.ERROR_EXTERNAL_DUPLICATE_XML_PATH, - new String[] { collidingPath, jar2, jar1 })); - - languageXmlFileMapping.addPathsForLanguage(Arrays.asList(xmlContainer2), APEX); + MessagePassableException ex = assertThrows(MessagePassableException.class, () -> languageXmlFileMapping.addPathsForLanguage(Arrays.asList(xmlContainer2), APEX)); + assertThat(ex.getEventKey(), is(EventKey.ERROR_EXTERNAL_DUPLICATE_XML_PATH)); + assertThat(ex.getArgs(), is(new String[] { collidingPath, jar2, jar1 })); } private void setupCategoriesAndRulesets() { diff --git a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MainArgsHandlingTest.java b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MainArgsHandlingTest.java index 5f9dc54b8..9768d55a2 100644 --- a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MainArgsHandlingTest.java +++ b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MainArgsHandlingTest.java @@ -1,14 +1,16 @@ package sfdc.sfdx.scanner.pmd; -import static org.junit.Assert.*; - -import org.junit.Test; -import com.salesforce.messaging.MessagePassableException; -import com.salesforce.messaging.EventKey; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.util.List; import java.util.Map; +import com.salesforce.messaging.EventKey; +import com.salesforce.messaging.MessagePassableException; +import org.junit.jupiter.api.Test; + public class MainArgsHandlingTest { final Main main = new Main(); @@ -24,13 +26,13 @@ public void verifyHappyCase() { final Map> stringListMap = main.parseArguments(args); // Validate - assertEquals("Unexpected number of items in parsed map", 1, stringListMap.size()); - assertTrue("Language not found in parsed map", stringListMap.containsKey(language)); + assertEquals(1, stringListMap.size(), "Unexpected number of items in parsed map"); + assertTrue(stringListMap.containsKey(language), "Language not found in parsed map"); final List parsedPaths = stringListMap.get(language); - assertEquals("Unexpected number of paths in parsed map", paths.length, parsedPaths.size()); + assertEquals(paths.length, parsedPaths.size(), "Unexpected number of paths in parsed map"); for (String path : paths) { - assertTrue("Path not found in parsed map: " + path, parsedPaths.contains(path)); + assertTrue(parsedPaths.contains(path), "Path not found in parsed map: " + path); } } @@ -73,8 +75,8 @@ private void testParseArgForErrorHandling(String[] args, String expectedArgForMe main.parseArguments(args); fail(failureMessage); } catch (MessagePassableException e) { - assertEquals("Unexpected eventKey on exception", EventKey.ERROR_INTERNAL_MAIN_INVALID_ARGUMENT, e.getEventKey()); - assertEquals("Unexpected arg list on exception", expectedArgForMessage, e.getArgs()[0]); + assertEquals(EventKey.ERROR_INTERNAL_MAIN_INVALID_ARGUMENT, e.getEventKey(), "Unexpected eventKey on exception"); + assertEquals(expectedArgForMessage, e.getArgs()[0], "Unexpected arg list on exception"); } } } diff --git a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MainMessagesTest.java b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MainMessagesTest.java index f6f67fa6f..459b977ca 100644 --- a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MainMessagesTest.java +++ b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MainMessagesTest.java @@ -1,25 +1,29 @@ package sfdc.sfdx.scanner.pmd; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; + +import java.util.List; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import com.salesforce.messaging.CliMessager; import com.salesforce.messaging.EventKey; -import com.salesforce.messaging.MessagePassableException; import com.salesforce.messaging.Message; -import com.salesforce.messaging.CliMessager; - -import java.util.List; - -import static org.mockito.Mockito.*; +import com.salesforce.messaging.MessagePassableException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class MainMessagesTest { - @Before - @After + @BeforeEach + @AfterEach public void clearMessages() { CliMessager.getInstance().resetMessages(); } @@ -38,12 +42,12 @@ public void verifySfdxScannerExceptionsToMessages() { // Validate final List messages = getMessages(); - assertEquals("Unexpected count of messages", 1, messages.size()); + assertEquals(1, messages.size(), "Unexpected count of messages"); final Message actualMessage = messages.get(0); // Validate message - assertEquals("Unexpected eventKey in message", expectedEventKey.getMessageKey(), actualMessage.getMessageKey()); - assertEquals("Unexpected args in message", actualMessage.getArgs().get(0), expectedArgs[0]); + assertEquals(expectedEventKey.getMessageKey(), actualMessage.getMessageKey(), "Unexpected eventKey in message"); + assertEquals(actualMessage.getArgs().get(0), expectedArgs[0], "Unexpected args in message"); } @Test @@ -56,13 +60,13 @@ public void verifyAnyThrowableAddedToMessages() { // Validate List messages = getMessages(); - assertEquals("Unexpected count of messages", 1, messages.size()); + assertEquals(1, messages.size(), "Unexpected count of messages"); final Message actualMessage = messages.get(0); // Validate message - assertEquals("Unexpected eventKey in message when handling uncaught exception", EventKey.ERROR_INTERNAL_UNEXPECTED.getMessageKey(), actualMessage.getMessageKey()); + assertEquals(EventKey.ERROR_INTERNAL_UNEXPECTED.getMessageKey(), actualMessage.getMessageKey(), "Unexpected eventKey in message when handling uncaught exception"); final String actualLog = actualMessage.getInternalLog(); - assertTrue("log field of message should contain message from actual exception", actualLog.contains(exception.getMessage())); + assertTrue(actualLog.contains(exception.getMessage()), "log field of message should contain message from actual exception"); } private Main.Dependencies setupMockToThrowException(Exception exception) { diff --git a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MessagePassableExceptionMatcher.java b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MessagePassableExceptionMatcher.java deleted file mode 100644 index d5d606484..000000000 --- a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/MessagePassableExceptionMatcher.java +++ /dev/null @@ -1,50 +0,0 @@ -package sfdc.sfdx.scanner.pmd; - -import java.util.Arrays; -import java.util.Optional; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeMatcher; - -import com.salesforce.messaging.EventKey; -import com.salesforce.messaging.MessagePassableException; - -/** - * Custom matcher that can be used with - * {@link org.junit.rules.ExpectedException#expect(org.hamcrest.Matcher)} - * - *
- * // Example Usage
- * thrown.expect(new MessagePassableExceptionMatcher(EventKey.WARNING_INVALID_CAT_SKIPPED,
- * 		new String[] { "InventoryName" }));
- * 
- */ -public class MessagePassableExceptionMatcher extends TypeSafeMatcher { - private final EventKey expectedEventKey; - private final String[] expectedArgs; - - public MessagePassableExceptionMatcher(EventKey expectedEventKey, String[] expectedArgs) { - this.expectedEventKey = expectedEventKey; - this.expectedArgs = nullToEmpty(expectedArgs); - } - - @Override - protected boolean matchesSafely(MessagePassableException item) { - String[] actualArgs = nullToEmpty(item.getArgs()); - return expectedEventKey.equals(item.getEventKey()) && - Arrays.equals(expectedArgs, actualArgs); - } - - @Override - public void describeTo(Description description) { - description.appendText("EventKey=").appendValue(expectedEventKey.name()).appendText(", Args=") - .appendValue(expectedArgs); - } - - /** - * Convert a null array to empty array. The are equivalent for our purposes. - */ - private String[] nullToEmpty(String[] array) { - return Optional.ofNullable(array).orElseGet(() -> new String[] {}); - } -} diff --git a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/Pmd7CompatibilityCheckerTest.java b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/Pmd7CompatibilityCheckerTest.java index 2478238aa..24a101597 100644 --- a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/Pmd7CompatibilityCheckerTest.java +++ b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/Pmd7CompatibilityCheckerTest.java @@ -1,27 +1,30 @@ package sfdc.sfdx.scanner.pmd; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.StringReader; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.salesforce.messaging.CliMessager; import com.salesforce.messaging.Message; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.InputSource; import sfdc.sfdx.scanner.pmd.catalog.PmdCatalogCategory; import sfdc.sfdx.scanner.pmd.catalog.PmdCatalogRule; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.io.StringReader; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import static org.junit.Assert.*; - public class Pmd7CompatibilityCheckerTest { private static final String STANDARD_JAR = "/Users/me/sfdx-scanner/dist/pmd/lib/pmd-apex-6.55.0.jar"; @@ -32,8 +35,8 @@ public class Pmd7CompatibilityCheckerTest { /** * Before and after each test, reset the CLI messages. */ - @Before - @After + @BeforeEach + @AfterEach public void clearMessages() { CliMessager.getInstance().resetMessages(); } diff --git a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/PmdRuleCatalogerTest.java b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/PmdRuleCatalogerTest.java index b42a8c848..7b7214fdd 100644 --- a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/PmdRuleCatalogerTest.java +++ b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/PmdRuleCatalogerTest.java @@ -1,35 +1,31 @@ package sfdc.sfdx.scanner.pmd; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; import static sfdc.sfdx.scanner.TestConstants.*; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collections; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; +import java.util.*; import com.salesforce.messaging.CliMessager; +import com.salesforce.messaging.EventKey; +import com.salesforce.messaging.MessagePassableException; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; - -import com.salesforce.messaging.EventKey; import sfdc.sfdx.scanner.pmd.catalog.PmdCatalogJson; /** @@ -38,21 +34,19 @@ public class PmdRuleCatalogerTest { private static final String TEST_CATALOG_DIR = "./test/path/to/a/directory"; private static final String TEST_CATALOG_FILE = "PmdCatalog.json"; - @Rule - public ExpectedException thrown = ExpectedException.none(); public ArgumentCaptor jsonContentsCaptor; public ArgumentCaptor directoryPathCaptor; public ArgumentCaptor fileNameCaptor; - @Before + @BeforeEach public void setup() { System.setProperty("catalogHome", TEST_CATALOG_DIR); System.setProperty("catalogName", TEST_CATALOG_FILE); CliMessager.getInstance().resetMessages(); } - @After + @AfterEach public void teardown() { System.clearProperty("catalogHome"); System.clearProperty("catalogName"); @@ -152,10 +146,13 @@ public void testExceptionIsThrownWhenCollisionOccurs() { COLLISION_JAR_2.toAbsolutePath().toString())); PmdRuleCataloger pmdRuleCataloger = new PmdRuleCataloger(rulePathEntries); - thrown.expect(new MessagePassableExceptionMatcher(EventKey.ERROR_EXTERNAL_DUPLICATE_XML_PATH, - new String[] { "category/joshapex/somecat.xml", COLLISION_JAR_2.toAbsolutePath().toString(), - COLLISION_JAR_1.toAbsolutePath().toString() })); - - pmdRuleCataloger.catalogRules(); + MessagePassableException ex = assertThrows(MessagePassableException.class, + () -> pmdRuleCataloger.catalogRules()); + assertThat(ex.getEventKey(), is(EventKey.ERROR_EXTERNAL_DUPLICATE_XML_PATH)); + assertThat(ex.getArgs(), is(new String[] { + "category/joshapex/somecat.xml", + COLLISION_JAR_2.toAbsolutePath().toString(), + COLLISION_JAR_1.toAbsolutePath().toString() } + )); } } diff --git a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/XmlFileFinderTest.java b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/XmlFileFinderTest.java index fe77b6dac..0f7c5cff6 100644 --- a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/XmlFileFinderTest.java +++ b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/XmlFileFinderTest.java @@ -1,28 +1,24 @@ package sfdc.sfdx.scanner.pmd; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItems; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static sfdc.sfdx.scanner.TestConstants.*; import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; import com.salesforce.messaging.EventKey; +import com.salesforce.messaging.MessagePassableException; +import org.junit.jupiter.api.Test; /** * Unit tests for {@link XmlFileFinder} */ public class XmlFileFinderTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void testAllJarsInDiretory() { XmlFileFinder xmlFileFinder = new XmlFileFinder(); @@ -103,8 +99,10 @@ private String getSingleFile(List xmlContainers, Str @Test public void testFindingNonExistentFile_ExpectError() { XmlFileFinder xmlFileFinder = new XmlFileFinder(); - thrown.expect(new MessagePassableExceptionMatcher(EventKey.ERROR_INTERNAL_CLASSPATH_DOES_NOT_EXIST, new String[]{"nonexistentfile.xml"})); - List xmlContainers = xmlFileFinder.findXmlFilesInPath("nonexistentfile.xml"); + MessagePassableException ex = assertThrows(MessagePassableException.class, + () -> xmlFileFinder.findXmlFilesInPath("nonexistentfile.xml")); + assertThat(ex.getEventKey(), is(EventKey.ERROR_INTERNAL_CLASSPATH_DOES_NOT_EXIST)); + assertThat(ex.getArgs(), is(new String[]{"nonexistentfile.xml"})); } } diff --git a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/catalog/PmdCatalogJsonTest.java b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/catalog/PmdCatalogJsonTest.java index c5cf94f4f..3e7fdfb69 100644 --- a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/catalog/PmdCatalogJsonTest.java +++ b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/catalog/PmdCatalogJsonTest.java @@ -1,75 +1,75 @@ package sfdc.sfdx.scanner.pmd.catalog; -import org.json.simple.JSONObject; - -import static org.junit.Assert.*; - -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import java.util.ArrayList; import java.util.List; -import static org.mockito.Mockito.*; +import org.json.simple.JSONObject; +import org.junit.jupiter.api.Test; public class PmdCatalogJsonTest { - private static final String RULE_NAME = "rule name"; - private static final String RULE_PATH = "rule path"; - private static final String CATEGORY_NAME = "category name"; - private static final String CATEGORY_PATH = "category path"; + private static final String RULE_NAME = "rule name"; + private static final String RULE_PATH = "rule path"; + private static final String CATEGORY_NAME = "category name"; + private static final String CATEGORY_PATH = "category path"; - @Test - public void testConstructJson() { + @Test + public void testConstructJson() { - final List rules = new ArrayList<>(); - final List categories = new ArrayList<>(); - final List rulesets = new ArrayList<>(); - rules.add(getPmdCatalogRuleMock()); - categories.add(getPmdCatalogCategoryMock(CATEGORY_NAME, CATEGORY_PATH)); - rulesets.add(getPmdCatalogRulesetMock(RULE_NAME, RULE_PATH)); + final List rules = new ArrayList<>(); + final List categories = new ArrayList<>(); + final List rulesets = new ArrayList<>(); + rules.add(getPmdCatalogRuleMock()); + categories.add(getPmdCatalogCategoryMock(CATEGORY_NAME, CATEGORY_PATH)); + rulesets.add(getPmdCatalogRulesetMock(RULE_NAME, RULE_PATH)); - final PmdCatalogJson catalogJson = new PmdCatalogJson(rules, categories, rulesets); + final PmdCatalogJson catalogJson = new PmdCatalogJson(rules, categories, rulesets); - // Execute - final JSONObject jsonObject = catalogJson.constructJson(); + // Execute + final JSONObject jsonObject = catalogJson.constructJson(); - // Verify - //[{"paths":["rule path"],"name":"rule name"}] - final String expectedRulesetJson = String.format("[{\"engine\":\"%s\",\"paths\":[\"%s\"],\"name\":\"%s\"}]", - PmdCatalogJson.PMD_ENGINE_NAME, RULE_PATH, RULE_NAME); - assertEquals(expectedRulesetJson, jsonObject.get(PmdCatalogJson.JSON_RULESETS).toString()); + // Verify + //[{"paths":["rule path"],"name":"rule name"}] + final String expectedRulesetJson = String.format("[{\"engine\":\"%s\",\"paths\":[\"%s\"],\"name\":\"%s\"}]", + PmdCatalogJson.PMD_ENGINE_NAME, RULE_PATH, RULE_NAME); + assertEquals(expectedRulesetJson, jsonObject.get(PmdCatalogJson.JSON_RULESETS).toString()); - final String expectedCategoryJson = String.format("[{\"engine\":\"%s\",\"paths\":[\"%s\"],\"name\":\"%s\"}]", - PmdCatalogJson.PMD_ENGINE_NAME, CATEGORY_PATH, CATEGORY_NAME); - assertEquals(expectedCategoryJson, jsonObject.get(PmdCatalogJson.JSON_CATEGORIES).toString()); + final String expectedCategoryJson = String.format("[{\"engine\":\"%s\",\"paths\":[\"%s\"],\"name\":\"%s\"}]", + PmdCatalogJson.PMD_ENGINE_NAME, CATEGORY_PATH, CATEGORY_NAME); + assertEquals(expectedCategoryJson, jsonObject.get(PmdCatalogJson.JSON_CATEGORIES).toString()); - // Rules json has its own test where we verify the Json contents. Here, we only confirm that it exists - assertTrue("JSON should contain 'rules' element", jsonObject.containsKey(PmdCatalogJson.JSON_RULES)); - } + // Rules json has its own test where we verify the Json contents. Here, we only confirm that it exists + assertTrue(jsonObject.containsKey(PmdCatalogJson.JSON_RULES), "JSON should contain 'rules' element"); + } - private PmdCatalogRule getPmdCatalogRuleMock() { - final PmdCatalogRule catalogRule = mock(PmdCatalogRule.class); - final JSONObject jsonObject = mock(JSONObject.class); + private PmdCatalogRule getPmdCatalogRuleMock() { + final PmdCatalogRule catalogRule = mock(PmdCatalogRule.class); + final JSONObject jsonObject = mock(JSONObject.class); - doReturn(jsonObject).when(catalogRule).toJson(); + doReturn(jsonObject).when(catalogRule).toJson(); - return catalogRule; - } + return catalogRule; + } - private PmdCatalogCategory getPmdCatalogCategoryMock(String name, String path) { - final PmdCatalogCategory category = mock(PmdCatalogCategory.class); + private PmdCatalogCategory getPmdCatalogCategoryMock(String name, String path) { + final PmdCatalogCategory category = mock(PmdCatalogCategory.class); - doReturn(name).when(category).getName(); - doReturn(path).when(category).getPath(); + doReturn(name).when(category).getName(); + doReturn(path).when(category).getPath(); - return category; - } + return category; + } - private PmdCatalogRuleset getPmdCatalogRulesetMock(String name, String path) { - final PmdCatalogRuleset ruleset = mock(PmdCatalogRuleset.class); + private PmdCatalogRuleset getPmdCatalogRulesetMock(String name, String path) { + final PmdCatalogRuleset ruleset = mock(PmdCatalogRuleset.class); - doReturn(name).when(ruleset).getName(); - doReturn(path).when(ruleset).getPath(); + doReturn(name).when(ruleset).getName(); + doReturn(path).when(ruleset).getPath(); - return ruleset; - } + return ruleset; + } } diff --git a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/catalog/PmdCatalogRuleTest.java b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/catalog/PmdCatalogRuleTest.java index 45abd4071..bf800e5cb 100644 --- a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/catalog/PmdCatalogRuleTest.java +++ b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/pmd/catalog/PmdCatalogRuleTest.java @@ -1,30 +1,26 @@ package sfdc.sfdx.scanner.pmd.catalog; -import com.salesforce.messaging.EventKey; -import org.json.simple.JSONObject; - -import static org.junit.Assert.*; - -import org.junit.Rule; -import org.junit.Test; - -import static org.mockito.Mockito.*; - -import org.junit.rules.ExpectedException; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import sfdc.sfdx.scanner.pmd.MessagePassableExceptionMatcher; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import com.salesforce.messaging.EventKey; +import com.salesforce.messaging.MessagePassableException; +import org.json.simple.JSONObject; +import org.junit.jupiter.api.Test; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; -public class PmdCatalogRuleTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); +public class PmdCatalogRuleTest { private static final String NAME = "Name"; private static final String MESSAGE = "Some message"; @@ -47,17 +43,17 @@ public void testCatalogRuleJsonConversion() { // Validate - assertEquals("Unexpected name on JSON", NAME, jsonObject.get(PmdCatalogJson.JSON_NAME)); + assertEquals(NAME, jsonObject.get(PmdCatalogJson.JSON_NAME), "Unexpected name on JSON"); - assertEquals("Unexpected message", MESSAGE, jsonObject.get(PmdCatalogJson.JSON_MESSAGE)); + assertEquals(MESSAGE, jsonObject.get(PmdCatalogJson.JSON_MESSAGE), "Unexpected message"); final List expectedLanguages = new ArrayList<>(); expectedLanguages.add(LANGUAGE); - assertEquals("Unexpected language", expectedLanguages, (List) jsonObject.get(PmdCatalogJson.JSON_LANGUAGES)); + assertEquals(expectedLanguages, (List) jsonObject.get(PmdCatalogJson.JSON_LANGUAGES), "Unexpected language"); final List expectedCategoryNames = new ArrayList<>(); expectedCategoryNames.add(CATEGORY_NAME); - assertEquals("Unexpected categories", expectedCategoryNames, jsonObject.get(PmdCatalogJson.JSON_CATEGORIES)); + assertEquals(expectedCategoryNames, jsonObject.get(PmdCatalogJson.JSON_CATEGORIES), "Unexpected categories"); } @@ -74,7 +70,7 @@ public void testCatalogRuleNoDescription() { final JSONObject jsonObject = catalogRule.toJson(); // Validate - assertEquals("Unexpected description", emptyDescription, jsonObject.get(PmdCatalogJson.JSON_DESCRIPTION)); + assertEquals(emptyDescription, jsonObject.get(PmdCatalogJson.JSON_DESCRIPTION), "Unexpected description"); } @Test @@ -89,7 +85,7 @@ public void testCatalogRuleJsonWithDescription() { final JSONObject jsonObject = catalogRule.toJson(); // Validate - assertEquals("Unexpected description", description, jsonObject.get(PmdCatalogJson.JSON_DESCRIPTION)); + assertEquals(description, jsonObject.get(PmdCatalogJson.JSON_DESCRIPTION), "Unexpected description"); } @Test @@ -99,11 +95,11 @@ public void testCatalogRuleJsonWithMultipleDescriptions_expectException() { // Setup mock final Element elementMock = getElementMock(Arrays.asList(description1, description2)); - thrown.expect(new MessagePassableExceptionMatcher(EventKey.ERROR_EXTERNAL_MULTIPLE_RULE_DESC, - new String[]{CATEGORY.getPath() + "/" + NAME, "2"} - )); - // Even initializing the object should be enough to trigger the expected exception. - final PmdCatalogRule catalogRule = new PmdCatalogRule(elementMock, CATEGORY, LANGUAGE); + + // Even initializing the object should be enough to trigger the expected exception. + MessagePassableException ex = assertThrows(MessagePassableException.class, () -> new PmdCatalogRule(elementMock, CATEGORY, LANGUAGE)); + assertThat(ex.getEventKey(), is(EventKey.ERROR_EXTERNAL_MULTIPLE_RULE_DESC)); + assertThat(ex.getArgs(), is(new String[]{CATEGORY.getPath() + "/" + NAME, "2"})); } private Element getElementMock(List descriptions) { diff --git a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/xml/XmlReaderTest.java b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/xml/XmlReaderTest.java index 27aee6029..092e2a61f 100644 --- a/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/xml/XmlReaderTest.java +++ b/pmd-cataloger/src/test/java/sfdc/sfdx/scanner/xml/XmlReaderTest.java @@ -1,11 +1,11 @@ package sfdc.sfdx.scanner.xml; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static sfdc.sfdx.scanner.TestConstants.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static sfdc.sfdx.scanner.TestConstants.SOMECAT_XML_FILE; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.w3c.dom.Document; /** @@ -14,7 +14,7 @@ public class XmlReaderTest { private XmlReader xmlReader; - @Before + @BeforeEach public void setup() { xmlReader = new XmlReader(); } diff --git a/sfge/build.gradle.kts b/sfge/build.gradle.kts index 45d0a1b66..0f7d36a78 100644 --- a/sfge/build.gradle.kts +++ b/sfge/build.gradle.kts @@ -1,3 +1,5 @@ +import java.awt.Desktop + plugins { java application @@ -18,18 +20,19 @@ dependencies { implementation("org.antlr:antlr-runtime:3.5.2") implementation("org.apache.logging.log4j:log4j-api:2.17.1") implementation("org.apache.logging.log4j:log4j-core:2.17.1") - implementation("com.google.code.gson:gson:2.8.8") + implementation("com.google.code.gson:gson:2.10.1") implementation("com.google.guava:guava:26.0-jre") implementation("com.google.code.findbugs:jsr305:3.0.2") implementation("org.reflections:reflections:0.9.12") implementation("org.ow2.asm:asm:9.2") implementation(files("lib/apex-jorje-lsp-sfge.jar")) + testImplementation("org.hamcrest:hamcrest:2.2") - testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.2") - testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.2") - testImplementation("org.junit.jupiter:junit-jupiter-params:5.7.2") - testImplementation("org.mockito:mockito-core:2.21.0") - testImplementation("org.mockito:mockito-junit-jupiter:2.23.0") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") + testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.2") + testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.2") + testImplementation("org.mockito:mockito-core:5.2.0") + testImplementation("org.mockito:mockito-junit-jupiter:5.2.0") } group = "com.salesforce.apex" @@ -68,9 +71,12 @@ tasks.build { } tasks.test { + // Use JUnit 5 useJUnitPlatform() + // Enables SfgeTestExtension systemProperty("junit.jupiter.extensions.autodetection.enabled", true) + testLogging { events("passed", "skipped", "failed") // Show log4j output during tests, unless env-var to disable them is set. @@ -78,8 +84,11 @@ tasks.test { // Show extra expected info when there is a failure exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL } + // Run tests in multiple threads maxParallelForks = Runtime.getRuntime().availableProcessors()/2 + 1 + + // Report is always generated after test runs finalizedBy(tasks.jacocoTestReport) } @@ -87,11 +96,19 @@ tasks.jacocoTestReport { dependsOn(tasks.test) } +tasks.register("showCoverageReport") { + group = "verification" + dependsOn(tasks.jacocoTestReport) + doLast { + Desktop.getDesktop().browse(File("$buildDir/reports/jacoco/test/html/index.html").toURI()) + } +} + tasks.jacocoTestCoverageVerification { violationRules { rule { limit { - minimum = "0.80".toBigDecimal() + minimum = BigDecimal("0.80") } } }