diff options
author | Antoine Vinot <antoine.vinot@sonarsource.com> | 2022-09-29 10:11:41 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-09-29 20:03:15 +0000 |
commit | 6f85804537da5fb66a091458dfdef4bd12da2572 (patch) | |
tree | 19de443b1783f1a9a7a92f7b19c73a40d5435e51 /server | |
parent | 29868c3beba7895a71597532b727d213e6320ad0 (diff) | |
download | sonarqube-6f85804537da5fb66a091458dfdef4bd12da2572.tar.gz sonarqube-6f85804537da5fb66a091458dfdef4bd12da2572.zip |
SONAR-17389 - Prevent project creation with existing key but different case
Diffstat (limited to 'server')
12 files changed, 128 insertions, 29 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java index afaba3af0e2..b11d2801afd 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java @@ -241,6 +241,10 @@ public class ComponentDao implements Dao { return Optional.ofNullable(mapper(session).selectByKey(key)); } + public Optional<ComponentDto> selectByKeyCaseInsensitive(DbSession session, String key) { + return Optional.ofNullable(mapper(session).selectByKeyCaseInsensitive(key)); + } + public Optional<ComponentDto> selectByKeyAndBranch(DbSession session, String key, String branch) { return Optional.ofNullable(mapper(session).selectBranchByKeyAndBranchKey(key, generateBranchKey(key, branch), branch)); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java index 2d827bee828..e62a69a23b7 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java @@ -31,7 +31,10 @@ import org.apache.ibatis.session.RowBounds; public interface ComponentMapper { @CheckForNull - ComponentDto selectByKey(String key); + ComponentDto selectByKey(@Param("key") String key); + + @CheckForNull + ComponentDto selectByKeyCaseInsensitive(@Param("key") String key); @CheckForNull ComponentDto selectBranchByKeyAndBranchKey(@Param("key") String key, @Param("dbKey") String dbKey, @Param("branch") String branch); @@ -40,7 +43,7 @@ public interface ComponentMapper { ComponentDto selectPrByKeyAndBranchKey(@Param("key") String key, @Param("dbKey") String dbKey, @Param("branch") String branch); @CheckForNull - ComponentDto selectByUuid(String uuid); + ComponentDto selectByUuid(@Param("uuid") String uuid); /** * Return sub project of component keys diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml index 05d2e777fe1..aed19c345e9 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml @@ -32,6 +32,14 @@ p.kee=#{key,jdbcType=VARCHAR} </select> + <select id="selectByKeyCaseInsensitive" parameterType="String" resultType="Component"> + SELECT + <include refid="componentColumns"/> + FROM components p + where + lower(p.kee)=lower(#{key,jdbcType=VARCHAR}) + </select> + <select id="selectBranchByKeyAndBranchKey" parameterType="String" resultType="Component"> select <include refid="componentColumns"/> diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java index c7c7d77f643..0996f6a56ff 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java @@ -1979,6 +1979,27 @@ public class ComponentDaoTest { verifyNoInteractions(auditPersister); } + @Test + public void selectByKeyCaseInsensitive_shouldFindProject_whenCaseIsDifferent() { + String projectKey = randomAlphabetic(5).toLowerCase(); + db.components().insertPrivateProject(c -> c.setDbKey(projectKey)); + + ComponentDto result = underTest.selectByKeyCaseInsensitive(db.getSession(), projectKey.toUpperCase()).orElse(null); + + assertThat(result).isNotNull(); + assertThat(result.getKey()).isEqualTo(projectKey); + } + + @Test + public void selectByKeyCaseInsensitive_shouldNotFindProject_whenKeyIsDifferent() { + String projectKey = randomAlphabetic(5).toLowerCase(); + db.components().insertPrivateProject(c -> c.setDbKey(projectKey)); + + Optional<ComponentDto> result = underTest.selectByKeyCaseInsensitive(db.getSession(), projectKey + randomAlphabetic(1)); + + assertThat(result).isEmpty(); + } + private boolean privateFlagOfUuid(String uuid) { return underTest.selectByUuid(db.getSession(), uuid).get().isPrivate(); } diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/exceptions/BadRequestException.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/exceptions/BadRequestException.java index 00f08d4b0bd..fdf94a4c2d8 100644 --- a/server/sonar-webserver-api/src/main/java/org/sonar/server/exceptions/BadRequestException.java +++ b/server/sonar-webserver-api/src/main/java/org/sonar/server/exceptions/BadRequestException.java @@ -51,16 +51,20 @@ public class BadRequestException extends ServerException { } } - public static BadRequestException create(List<String> errorMessages) { - checkArgument(!errorMessages.isEmpty(), "At least one error message is required"); - checkArgument(errorMessages.stream().noneMatch(message -> message == null || message.isEmpty()), "Message cannot be empty"); - return new BadRequestException(errorMessages); + public static void throwBadRequestException(String message, Object... messageArguments) { + throw create(format(message, messageArguments)); } public static BadRequestException create(String... errorMessages) { return create(asList(errorMessages)); } + public static BadRequestException create(List<String> errorMessages) { + checkArgument(!errorMessages.isEmpty(), "At least one error message is required"); + checkArgument(errorMessages.stream().noneMatch(message -> message == null || message.isEmpty()), "Message cannot be empty"); + return new BadRequestException(errorMessages); + } + public List<String> errors() { return errors; } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java index 0a1ff5347ba..55c76cf9789 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java @@ -19,7 +19,6 @@ */ package org.sonar.server.component; -import com.google.common.collect.ImmutableSet; import java.util.Date; import java.util.Locale; import java.util.Optional; @@ -49,10 +48,13 @@ import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.core.component.ComponentKeys.ALLOWED_CHARACTERS_MESSAGE; import static org.sonar.core.component.ComponentKeys.isValidProjectKey; import static org.sonar.server.exceptions.BadRequestException.checkRequest; +import static org.sonar.server.exceptions.BadRequestException.throwBadRequestException; public class ComponentUpdater { - private static final Set<String> MAIN_BRANCH_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.APP); + private static final Set<String> MAIN_BRANCH_QUALIFIERS = Set.of(Qualifiers.PROJECT, Qualifiers.APP); + private static final String KEY_ALREADY_EXISTS_ERROR = "Could not create %s with key: \"%s\". A similar key already exists: \"%s\""; + private static final String MALFORMED_KEY_ERROR = "Malformed key for %s: '%s'. %s."; private final DbClient dbClient; private final I18n i18n; @@ -87,6 +89,10 @@ public class ComponentUpdater { return componentDto; } + public void commitAndIndex(DbSession dbSession, ComponentDto componentDto) { + projectIndexers.commitAndIndexComponents(dbSession, singletonList(componentDto), Cause.PROJECT_CREATION); + } + /** * Create component without committing. * Don't forget to call commitAndIndex(...) when ready to commit. @@ -104,6 +110,8 @@ public class ComponentUpdater { @Nullable String userUuid, @Nullable String userLogin, @Nullable String mainBranchName, Consumer<ComponentDto> componentModifier) { checkKeyFormat(newComponent.qualifier(), newComponent.key()); + checkKeyAlreadyExists(dbSession, newComponent); + ComponentDto componentDto = createRootComponent(dbSession, newComponent, componentModifier); if (isRootProject(componentDto)) { createMainBranch(dbSession, componentDto.uuid(), mainBranchName); @@ -112,14 +120,20 @@ public class ComponentUpdater { return componentDto; } - public void commitAndIndex(DbSession dbSession, ComponentDto componentDto) { - projectIndexers.commitAndIndexComponents(dbSession, singletonList(componentDto), Cause.PROJECT_CREATION); + private void checkKeyFormat(String qualifier, String key) { + checkRequest(isValidProjectKey(key), MALFORMED_KEY_ERROR, getQualifierToDisplay(qualifier), key, ALLOWED_CHARACTERS_MESSAGE); } - private ComponentDto createRootComponent(DbSession session, NewComponent newComponent, Consumer<ComponentDto> componentModifier) { - checkRequest(!dbClient.componentDao().selectByKey(session, newComponent.key()).isPresent(), - "Could not create %s, key already exists: %s", getQualifierToDisplay(newComponent.qualifier()), newComponent.key()); + private void checkKeyAlreadyExists(DbSession dbSession, NewComponent newComponent) { + Optional<ComponentDto> componentDto = newComponent.isProject() + ? dbClient.componentDao().selectByKeyCaseInsensitive(dbSession, newComponent.key()) + : dbClient.componentDao().selectByKey(dbSession, newComponent.key()); + + componentDto.map(ComponentDto::getKey) + .ifPresent(existingKey -> throwBadRequestException(KEY_ALREADY_EXISTS_ERROR, getQualifierToDisplay(newComponent.qualifier()), newComponent.key(), existingKey)); + } + private ComponentDto createRootComponent(DbSession session, NewComponent newComponent, Consumer<ComponentDto> componentModifier) { long now = system2.now(); String uuid = uuidFactory.create(); @@ -209,10 +223,6 @@ public class ComponentUpdater { } } - private void checkKeyFormat(String qualifier, String key) { - checkRequest(isValidProjectKey(key), "Malformed key for %s: '%s'. %s.", getQualifierToDisplay(qualifier), key, ALLOWED_CHARACTERS_MESSAGE); - } - private String getQualifierToDisplay(String qualifier) { return i18n.message(Locale.getDefault(), "qualifier." + qualifier, "Project"); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/NewComponent.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/NewComponent.java index 1710458e32d..b68a9a12e9e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/NewComponent.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/NewComponent.java @@ -69,6 +69,10 @@ public class NewComponent { return description; } + public boolean isProject() { + return PROJECT.equals(qualifier); + } + public static class Builder { private String description; private String key; diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java index 6b5d25f5ca8..ca76ed7b740 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/azure/ImportAzureProjectActionTest.java @@ -29,7 +29,6 @@ import org.sonar.alm.client.azure.GsonAzureRepo; import org.sonar.api.config.internal.Encryption; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; -import org.sonar.core.i18n.I18n; import org.sonar.core.util.SequenceUuidFactory; import org.sonar.db.DbTester; import org.sonar.db.alm.pat.AlmPatDto; @@ -47,6 +46,7 @@ import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.favorite.FavoriteUpdater; +import org.sonar.server.l18n.I18nRule; import org.sonar.server.permission.PermissionTemplateService; import org.sonar.server.project.ProjectDefaultVisibility; import org.sonar.server.project.Visibility; @@ -74,10 +74,12 @@ public class ImportAzureProjectActionTest { public UserSessionRule userSession = UserSessionRule.standalone(); @Rule public DbTester db = DbTester.create(); + @Rule + public final I18nRule i18n = new I18nRule(); private final AzureDevOpsHttpClient azureDevOpsHttpClient = mock(AzureDevOpsHttpClient.class); - private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), System2.INSTANCE, + private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE, mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory()); private final Encryption encryption = mock(Encryption.class); @@ -252,7 +254,7 @@ public class ImportAzureProjectActionTest { assertThatThrownBy(request::execute) .isInstanceOf(BadRequestException.class) - .hasMessage("Could not create null, key already exists: " + GENERATED_PROJECT_KEY); + .hasMessage("Could not create Project with key: \"%s\". A similar key already exists: \"%s\"", GENERATED_PROJECT_KEY, GENERATED_PROJECT_KEY); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionTest.java index 6e50410f731..574859d8c9f 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketcloud/ImportBitbucketCloudRepoActionTest.java @@ -29,7 +29,6 @@ import org.sonar.alm.client.bitbucket.bitbucketcloud.Project; import org.sonar.alm.client.bitbucket.bitbucketcloud.Repository; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; -import org.sonar.core.i18n.I18n; import org.sonar.core.util.SequenceUuidFactory; import org.sonar.db.DbTester; import org.sonar.db.alm.pat.AlmPatDto; @@ -47,6 +46,7 @@ import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.favorite.FavoriteUpdater; +import org.sonar.server.l18n.I18nRule; import org.sonar.server.permission.PermissionTemplateService; import org.sonar.server.project.ProjectDefaultVisibility; import org.sonar.server.project.Visibility; @@ -75,11 +75,13 @@ public class ImportBitbucketCloudRepoActionTest { public UserSessionRule userSession = UserSessionRule.standalone(); @Rule public DbTester db = DbTester.create(); + @Rule + public final I18nRule i18n = new I18nRule(); private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class); private final BitbucketCloudRestClient bitbucketCloudRestClient = mock(BitbucketCloudRestClient.class); - private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), System2.INSTANCE, + private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE, mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory()); private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); @@ -146,7 +148,7 @@ public class ImportBitbucketCloudRepoActionTest { assertThatThrownBy(request::execute) .isInstanceOf(BadRequestException.class) - .hasMessageContaining("Could not create null, key already exists: " + GENERATED_PROJECT_KEY); + .hasMessage("Could not create Project with key: \"%s\". A similar key already exists: \"%s\"", GENERATED_PROJECT_KEY, GENERATED_PROJECT_KEY); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionTest.java index ea7af30e4e8..97aa3145370 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/bitbucketserver/ImportBitbucketServerProjectActionTest.java @@ -35,7 +35,6 @@ import org.sonar.alm.client.bitbucketserver.Project; import org.sonar.alm.client.bitbucketserver.Repository; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; -import org.sonar.core.i18n.I18n; import org.sonar.core.util.SequenceUuidFactory; import org.sonar.db.DbTester; import org.sonar.db.alm.pat.AlmPatDto; @@ -52,6 +51,7 @@ import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.favorite.FavoriteUpdater; +import org.sonar.server.l18n.I18nRule; import org.sonar.server.permission.PermissionTemplateService; import org.sonar.server.project.ProjectDefaultVisibility; import org.sonar.server.project.Visibility; @@ -80,11 +80,13 @@ public class ImportBitbucketServerProjectActionTest { public UserSessionRule userSession = UserSessionRule.standalone(); @Rule public DbTester db = DbTester.create(); + @Rule + public final I18nRule i18n = new I18nRule(); private final ProjectDefaultVisibility projectDefaultVisibility = mock(ProjectDefaultVisibility.class); private final BitbucketServerRestClient bitbucketServerRestClient = mock(BitbucketServerRestClient.class); - private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), System2.INSTANCE, + private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), i18n, System2.INSTANCE, mock(PermissionTemplateService.class), new FavoriteUpdater(db.getDbClient()), new TestProjectIndexers(), new SequenceUuidFactory()); private final ImportHelper importHelper = new ImportHelper(db.getDbClient(), userSession); @@ -160,7 +162,7 @@ public class ImportBitbucketServerProjectActionTest { .execute(); }) .isInstanceOf(BadRequestException.class) - .hasMessage("Could not create null, key already exists: " + GENERATED_PROJECT_KEY); + .hasMessage("Could not create Project with key: \"%s\". A similar key already exists: \"%s\"", GENERATED_PROJECT_KEY, GENERATED_PROJECT_KEY); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java index bb794c4c130..35b27f35e02 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ComponentUpdaterTest.java @@ -40,6 +40,7 @@ import org.sonar.server.l18n.I18nRule; import org.sonar.server.permission.PermissionTemplateService; import static java.util.stream.IntStream.rangeClosed; +import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; @@ -65,7 +66,7 @@ public class ComponentUpdaterTest { private final TestProjectIndexers projectIndexers = new TestProjectIndexers(); private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class); - private ComponentUpdater underTest = new ComponentUpdater(db.getDbClient(), i18n, system2, + private final ComponentUpdater underTest = new ComponentUpdater(db.getDbClient(), i18n, system2, permissionTemplateService, new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory()); @@ -252,7 +253,7 @@ public class ComponentUpdaterTest { .build(); assertThatThrownBy(() -> underTest.create(session, newComponent, null, null)) .isInstanceOf(BadRequestException.class) - .hasMessage("Could not create Project, key already exists: " + existing.getDbKey()); + .hasMessage("Could not create Project with key: \"%s\". A similar key already exists: \"%s\"", existing.getDbKey(), existing.getDbKey()); } @Test @@ -278,4 +279,21 @@ public class ComponentUpdaterTest { .isInstanceOf(BadRequestException.class) .hasMessageContaining("Malformed key for Project: 'roject%Key'"); } + + @Test + public void create_shouldFail_whenCreatingProjectWithExistingKeyButDifferentCase() { + String existingKey = randomAlphabetic(5).toUpperCase(); + db.components().insertPrivateProject(component -> component.setDbKey(existingKey)); + String newKey = existingKey.toLowerCase(); + + NewComponent newComponent = NewComponent.newComponentBuilder() + .setKey(newKey) + .setName(DEFAULT_PROJECT_NAME) + .build(); + + DbSession dbSession = db.getSession(); + assertThatThrownBy(() -> underTest.create(dbSession, newComponent, null, null)) + .isInstanceOf(BadRequestException.class) + .hasMessage("Could not create Project with key: \"%s\". A similar key already exists: \"%s\"", newKey, existingKey); + } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/NewComponentTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/NewComponentTest.java index f0d10e6027e..5e0b7890b65 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/NewComponentTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/NewComponentTest.java @@ -22,6 +22,7 @@ package org.sonar.server.component; import org.junit.Test; import static com.google.common.base.Strings.repeat; +import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.sonar.api.resources.Qualifiers.PROJECT; @@ -120,8 +121,28 @@ public class NewComponentTest { assertThat(newComponent.qualifier()).isEqualTo(PROJECT); } + @Test + public void isProject_shouldReturnTrue_whenQualifierIsProject() { + NewComponent newComponent = underTest.setKey(KEY) + .setName(NAME) + .setQualifier(PROJECT) + .build(); + + assertThat(newComponent.isProject()).isTrue(); + } + + @Test + public void isProject_shouldReturnFalse_whenQualifierIsNotProject() { + NewComponent newComponent = underTest.setKey(KEY) + .setName(NAME) + .setQualifier(randomAlphabetic(4)) + .build(); + + assertThat(newComponent.isProject()).isFalse(); + } + private void expectBuildException(Class<? extends Exception> expectedExceptionType, String expectedMessage) { - assertThatThrownBy(() -> underTest.build()) + assertThatThrownBy(underTest::build) .isInstanceOf(expectedExceptionType) .hasMessageContaining(expectedMessage); } |