diff --git a/src/main/java/net/dv8tion/jda/api/JDABuilder.java b/src/main/java/net/dv8tion/jda/api/JDABuilder.java index deceb43870..85ec2396f2 100644 --- a/src/main/java/net/dv8tion/jda/api/JDABuilder.java +++ b/src/main/java/net/dv8tion/jda/api/JDABuilder.java @@ -98,7 +98,7 @@ public class JDABuilder protected GatewayEncoding encoding = GatewayEncoding.JSON; protected RestConfig restConfig = new RestConfig(); - private JDABuilder(@Nullable String token, int intents) + protected JDABuilder(@Nullable String token, int intents) { this.token = token; this.intents = 1 | intents; @@ -212,7 +212,7 @@ public static JDABuilder createDefault(@Nullable String token, @Nonnull Collecti return create(token, intents).applyDefault(); } - private JDABuilder applyDefault() + protected JDABuilder applyDefault() { return this.setMemberCachePolicy(MemberCachePolicy.DEFAULT) .setChunkingFilter(ChunkingFilter.NONE) @@ -322,7 +322,7 @@ public static JDABuilder createLight(@Nullable String token, @Nonnull Collection return create(token, intents).applyLight(); } - private JDABuilder applyLight() + protected JDABuilder applyLight() { return this.setMemberCachePolicy(MemberCachePolicy.NONE) .setChunkingFilter(ChunkingFilter.NONE) @@ -464,7 +464,7 @@ public static JDABuilder create(@Nullable String token, @Nonnull Collection disabledCache = EnumSet.allOf(CacheFlag.class); for (CacheFlag flag : CacheFlag.values()) @@ -1859,7 +1859,7 @@ private JDABuilder setFlag(ConfigFlag flag, boolean enable) return this; } - private void checkIntents() + protected void checkIntents() { boolean membersIntent = (intents & GatewayIntent.GUILD_MEMBERS.getRawValue()) != 0; if (!membersIntent && memberCachePolicy == MemberCachePolicy.ALL) diff --git a/src/test/java/net/dv8tion/jda/test/JDABuilderTest.java b/src/test/java/net/dv8tion/jda/test/JDABuilderTest.java new file mode 100644 index 0000000000..3bf2a7d194 --- /dev/null +++ b/src/test/java/net/dv8tion/jda/test/JDABuilderTest.java @@ -0,0 +1,211 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.test; + +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.requests.GatewayIntent; +import net.dv8tion.jda.api.utils.ChunkingFilter; +import net.dv8tion.jda.api.utils.cache.CacheFlag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import java.util.EnumSet; +import java.util.List; +import java.util.stream.Collectors; + +import static net.dv8tion.jda.api.requests.GatewayIntent.ALL_INTENTS; +import static net.dv8tion.jda.test.TestHelper.captureLogging; +import static org.assertj.core.api.Assertions.*; + +public class JDABuilderTest +{ + private static final String TOKEN = "invalid.token.here"; + + @Test + void testCreateWithAllIntents() + { + TestJDABuilder builder = new TestJDABuilder(ALL_INTENTS); + builder.applyIntents(); + + List logs = captureLogging(builder::checkIntents); + assertThat(logs).isEmpty(); + } + + @Test + void testCreateWithMinimalIntents() + { + TestJDABuilder builder = new TestJDABuilder(0); + builder.applyIntents(); + + List logs = captureLogging(builder::checkIntents); + + EnumSet flags = EnumSet.allOf(CacheFlag.class); + flags.removeIf(flag -> flag.getRequiredIntent() == null); + checkMissingIntentWarnings(logs, flags); + } + + @Test + void testCreateWithAllCacheAllIntents() + { + TestJDABuilder builder = new TestJDABuilder(ALL_INTENTS); + builder.applyIntents(); + builder.enableCache(EnumSet.allOf(CacheFlag.class)); + + List logs = captureLogging(builder::checkIntents); + assertThat(logs).isEmpty(); + } + + @Test + void testCreateWithAllCacheNoIntents() + { + TestJDABuilder builder = new TestJDABuilder(0); + builder.applyIntents(); + builder.enableCache(EnumSet.allOf(CacheFlag.class)); + + assertThatIllegalArgumentException() + .isThrownBy(builder::checkIntents) + .withMessage("Cannot use CacheFlag.ACTIVITY without GatewayIntent.GUILD_PRESENCES!"); + } + + @ParameterizedTest + @EnumSource(CacheFlag.class) + void testRequiredIntentForCacheFlagMissing(CacheFlag cacheFlag) + { + TestJDABuilder builder = new TestJDABuilder(0); + builder.applyIntents(); + builder.enableCache(cacheFlag); + + if (cacheFlag.getRequiredIntent() != null) + { + assertThatIllegalArgumentException() + .isThrownBy(builder::checkIntents) + .withMessage(String.format("Cannot use CacheFlag.%s without GatewayIntent.%s!", cacheFlag, cacheFlag.getRequiredIntent())); + } + else + { + assertThatNoException().isThrownBy(builder::checkIntents); + } + } + + + @ParameterizedTest + @EnumSource(CacheFlag.class) + void testRequiredIntentForCacheFlagEnabled(CacheFlag cacheFlag) + { + GatewayIntent requiredIntent = cacheFlag.getRequiredIntent(); + TestJDABuilder builder = new TestJDABuilder(requiredIntent != null ? requiredIntent.getRawValue() : 0); + builder.applyIntents(); + builder.enableCache(cacheFlag); + + assertThatNoException().isThrownBy(builder::checkIntents); + } + + @Test + void testDefaultMinimal() + { + TestJDABuilder builder = new TestJDABuilder(0); + builder.applyIntents(); + builder.applyDefault(); + + EnumSet defaultDisabled = CacheFlag.getPrivileged(); + EnumSet flags = EnumSet.allOf(CacheFlag.class); + flags.removeIf(flag -> flag.getRequiredIntent() == null || defaultDisabled.contains(flag)); + + List logs = captureLogging(builder::checkIntents); + checkMissingIntentWarnings(logs, flags); + } + + @Test + void testChunkingWithMissingIntent() + { + TestJDABuilder builder = new TestJDABuilder(0); + builder.applyIntents(); + builder.setChunkingFilter(ChunkingFilter.ALL); + + List logs = captureLogging(builder::checkIntents); + assertThat(logs).contains("Member chunking is disabled due to missing GUILD_MEMBERS intent."); + } + + @Test + @SuppressWarnings("deprecation") + void testDeprecatedIntentDoesNotDisableCache() + { + TestJDABuilder builder = new TestJDABuilder(GatewayIntent.GUILD_EMOJIS_AND_STICKERS.getRawValue()); + builder.applyIntents(); + + List logs = captureLogging(() -> + assertThatNoException().isThrownBy(builder::checkIntents) + ); + + assertThat(logs) + .isNotEmpty() + .noneMatch(log -> log.contains("CacheFlag." + CacheFlag.EMOJI)) + .noneMatch(log -> log.contains("CacheFlag." + CacheFlag.STICKER)); + } + + private void checkMissingIntentWarnings(List logs, EnumSet cacheFlagsWithMissingIntents) + { + String commaSeparatedList = cacheFlagsWithMissingIntents.stream() + .map(CacheFlag::name) + .map(name -> "CacheFlag." + name) + .collect(Collectors.joining(", ")); + + String listOfWarnings = cacheFlagsWithMissingIntents.stream() + .map(flag -> String.format("Disabled CacheFlag.%s (missing GatewayIntent.%s)", flag.name(), flag.getRequiredIntent().name())) + .collect(Collectors.joining("\n")); + + assertThat(String.join("\n", logs)) + .isEqualToIgnoringWhitespace( + "Automatically disabled CacheFlags due to missing intents\n" + + listOfWarnings + "\n" + + "You can manually disable these flags to remove this warning by using disableCache(" + commaSeparatedList + ") on your JDABuilder" + ); + } + + static class TestJDABuilder extends JDABuilder + { + public TestJDABuilder(int intents) + { + super(TOKEN, intents); + } + + @Override + public JDABuilder applyDefault() + { + return super.applyDefault(); + } + + @Override + public JDABuilder applyLight() + { + return super.applyLight(); + } + + @Override + public JDABuilder applyIntents() + { + return super.applyIntents(); + } + + @Override + public void checkIntents() + { + super.checkIntents(); + } + } +} diff --git a/src/test/java/net/dv8tion/jda/test/TestHelper.java b/src/test/java/net/dv8tion/jda/test/TestHelper.java new file mode 100644 index 0000000000..06a815eb47 --- /dev/null +++ b/src/test/java/net/dv8tion/jda/test/TestHelper.java @@ -0,0 +1,57 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.test; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestHelper +{ + public static List captureLogging(Runnable task) + { + return captureLogging(LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME), task); + } + + public static List captureLogging(Logger logger, Runnable task) + { + assertThat(logger).isInstanceOf(ch.qos.logback.classic.Logger.class); + ch.qos.logback.classic.Logger logbackLogger = (ch.qos.logback.classic.Logger) logger; + + ListAppender listAppender = new ListAppender<>(); + listAppender.start(); + logbackLogger.addAppender(listAppender); + try + { + task.run(); + return listAppender.list + .stream().map(ILoggingEvent::getFormattedMessage) + .collect(Collectors.toList()); + } + finally + { + logbackLogger.detachAppender(listAppender); + listAppender.stop(); + } + } +}