From 0169d28ffd9587764139d54c4ec0cffc0929f8f1 Mon Sep 17 00:00:00 2001 From: Davide Polonio Date: Thu, 11 May 2023 12:13:34 +0200 Subject: [PATCH] test: add test for createCampaign command. Still wip --- .../polpetta/mezzotre/orm/model/Campaign.java | 12 +- .../mezzotre/orm/telegram/ChatUtil.java | 1 + .../telegram/command/CreateCampaign.java | 4 +- src/main/resources/i18n/message.properties | 8 + .../resources/i18n/message_en_US.properties | 8 + .../template/telegram/createCampaign.0.vm | 6 +- .../template/telegram/createCampaign.1.vm | 2 +- .../template/telegram/createCampaign.2.vm | 8 +- .../mezzotre/orm/telegram/ChatUtilTest.java | 23 ++ .../CreateCampaignIntegrationTest.java | 273 +++++++++++++++++ .../telegram/command/CreateCampaignTest.java | 276 +++++++++++++++++- 11 files changed, 606 insertions(+), 15 deletions(-) create mode 100644 src/test/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaignIntegrationTest.java diff --git a/src/main/java/com/github/polpetta/mezzotre/orm/model/Campaign.java b/src/main/java/com/github/polpetta/mezzotre/orm/model/Campaign.java index c5267b7..aab035e 100644 --- a/src/main/java/com/github/polpetta/mezzotre/orm/model/Campaign.java +++ b/src/main/java/com/github/polpetta/mezzotre/orm/model/Campaign.java @@ -16,7 +16,7 @@ public class Campaign extends Base { @Length(256) @NotNull - private String campaignName; + private String name; @Nullable @Null private String description; @@ -25,7 +25,7 @@ public class Campaign extends Base { public Campaign(String id, String campaignName, @Nullable String description) { this.id = id; - this.campaignName = campaignName; + this.name = campaignName; this.description = description; } @@ -33,12 +33,12 @@ public class Campaign extends Base { return id; } - public String getCampaignName() { - return campaignName; + public String getName() { + return name; } - public void setCampaignName(String campaignName) { - this.campaignName = campaignName; + public void setName(String name) { + this.name = name; } @Nullable diff --git a/src/main/java/com/github/polpetta/mezzotre/orm/telegram/ChatUtil.java b/src/main/java/com/github/polpetta/mezzotre/orm/telegram/ChatUtil.java index 47dd423..f568052 100644 --- a/src/main/java/com/github/polpetta/mezzotre/orm/telegram/ChatUtil.java +++ b/src/main/java/com/github/polpetta/mezzotre/orm/telegram/ChatUtil.java @@ -47,6 +47,7 @@ public class ChatUtil { chatContext.setStage(stageName); chatContext.setStep(stepNumber); chatContext.setPreviousMessageUnixTimestampInSeconds(clock.now()); + chatContext.getAdditionalProperties().clear(); additionalFields.forEach(chatContext::setAdditionalProperty); chat.setChatContext(chatContext); diff --git a/src/main/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaign.java b/src/main/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaign.java index 651e090..e1be4c8 100644 --- a/src/main/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaign.java +++ b/src/main/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaign.java @@ -109,7 +109,7 @@ public class CreateCampaign implements Processor { return templateContentGenerator.mergeTemplate( ctx -> ctx.put(CAMPAIGN_NAME_TEMPLATE_CTX_FIELD, campaignName), chat.getLocale(), - "template/telegram/createCampaign.2.vm"); + "template/telegram/createCampaign.1.vm"); }) // We don't update the context here on purpose. If the user wants to try another // campaign name is free to do so! @@ -159,7 +159,7 @@ public class CreateCampaign implements Processor { chatUtil.updateChatContext( chat, TRIGGERING_KEYWORD, 3, Collections.emptyMap()); return templateContentGenerator.mergeTemplate( - ctx -> {}, chat.getLocale(), "template/telegram/createCampaign.3.vm"); + ctx -> {}, chat.getLocale(), "template/telegram/createCampaign.2.vm"); }) .orElseGet( () -> diff --git a/src/main/resources/i18n/message.properties b/src/main/resources/i18n/message.properties index f8458cd..607c273 100644 --- a/src/main/resources/i18n/message.properties +++ b/src/main/resources/i18n/message.properties @@ -21,3 +21,11 @@ help.buttonsToo=You can do the same operations you''d do with the commands afore help.cmdDescription=Print the help message notfound.description=Mmm I''m not able to find command {0}, are you sure to have it typed correctly? notfound.howToHelp=Let me show you what I can do by typing /help in the chat! +createCampaign.letsStartName=Very well, give me a second that I go grab some scroll, ink and quill... +createCampaign.pickUpAction=*Searches frenetically in the desk between piles of books and written scrolls for a free piece of scroll* +createCampaign.readyPromptName=Here we are! Please, tell me, how would you like to call your new campaign? +createCampaign.optionalDescription=Uhmm yes, {0}... Very well, great name choice by the way! Now, would you like to give me a short description of your campaign? You can skip this step if you don''t want, otherwise just reply with the description +createCampaign.creationDone=All done! I have successfully added your campaign to my archives! Let me store it properly... +createCampaign.finalCreationAction=*Finishes to write down on the scroll the last details* +createCampaign.lookToPileAction=*Moves the scroll into a pile of other, disorganized, scrolls* +createCampaign.shareCampaign=Now, if you want, you can share this campaign to other players so that they can join! To do this, just click on the button below and then select the user or the group you want to share this campaign with! They will be able to add their characters and see the other characters in this campaign diff --git a/src/main/resources/i18n/message_en_US.properties b/src/main/resources/i18n/message_en_US.properties index f8458cd..607c273 100644 --- a/src/main/resources/i18n/message_en_US.properties +++ b/src/main/resources/i18n/message_en_US.properties @@ -21,3 +21,11 @@ help.buttonsToo=You can do the same operations you''d do with the commands afore help.cmdDescription=Print the help message notfound.description=Mmm I''m not able to find command {0}, are you sure to have it typed correctly? notfound.howToHelp=Let me show you what I can do by typing /help in the chat! +createCampaign.letsStartName=Very well, give me a second that I go grab some scroll, ink and quill... +createCampaign.pickUpAction=*Searches frenetically in the desk between piles of books and written scrolls for a free piece of scroll* +createCampaign.readyPromptName=Here we are! Please, tell me, how would you like to call your new campaign? +createCampaign.optionalDescription=Uhmm yes, {0}... Very well, great name choice by the way! Now, would you like to give me a short description of your campaign? You can skip this step if you don''t want, otherwise just reply with the description +createCampaign.creationDone=All done! I have successfully added your campaign to my archives! Let me store it properly... +createCampaign.finalCreationAction=*Finishes to write down on the scroll the last details* +createCampaign.lookToPileAction=*Moves the scroll into a pile of other, disorganized, scrolls* +createCampaign.shareCampaign=Now, if you want, you can share this campaign to other players so that they can join! To do this, just click on the button below and then select the user or the group you want to share this campaign with! They will be able to add their characters and see the other characters in this campaign diff --git a/src/main/resources/template/telegram/createCampaign.0.vm b/src/main/resources/template/telegram/createCampaign.0.vm index 5752667..8740183 100644 --- a/src/main/resources/template/telegram/createCampaign.0.vm +++ b/src/main/resources/template/telegram/createCampaign.0.vm @@ -1 +1,5 @@ -${i18n.createCampaign.letsStartName} \ No newline at end of file +${i18n.createCampaign.letsStartName} + +_${i18n.createCampaign.pickUpAction}_ + +${i18n.createCampaign.readyPromptName} \ No newline at end of file diff --git a/src/main/resources/template/telegram/createCampaign.1.vm b/src/main/resources/template/telegram/createCampaign.1.vm index e529009..e55cdf0 100644 --- a/src/main/resources/template/telegram/createCampaign.1.vm +++ b/src/main/resources/template/telegram/createCampaign.1.vm @@ -1 +1 @@ -${i18n.createCampaign.optionalDescription} \ No newline at end of file +${i18n.createCampaign.optionalDescription.insert(${campaignName})} \ No newline at end of file diff --git a/src/main/resources/template/telegram/createCampaign.2.vm b/src/main/resources/template/telegram/createCampaign.2.vm index d337feb..0ff854a 100644 --- a/src/main/resources/template/telegram/createCampaign.2.vm +++ b/src/main/resources/template/telegram/createCampaign.2.vm @@ -1 +1,7 @@ -${i18n.createCampaign.done} \ No newline at end of file +_${i18n.createCampaign.finalCreationAction}_ + +${i18n.createCampaign.creationDone} + +_${i18n.createCampaign.lookToPileAction}_ + +${i18n.createCampaign.shareCampaign} \ No newline at end of file diff --git a/src/test/java/com/github/polpetta/mezzotre/orm/telegram/ChatUtilTest.java b/src/test/java/com/github/polpetta/mezzotre/orm/telegram/ChatUtilTest.java index 7de3fc5..35cd4f9 100644 --- a/src/test/java/com/github/polpetta/mezzotre/orm/telegram/ChatUtilTest.java +++ b/src/test/java/com/github/polpetta/mezzotre/orm/telegram/ChatUtilTest.java @@ -67,4 +67,27 @@ class ChatUtilTest { assertEquals(obj1, gotAdditionalProperties.get("field1")); assertEquals(obj2, gotAdditionalProperties.get("field2")); } + + @Test + void shouldEmptyAdditionalElementsIfEmptyMapIsPassed() { + final TgChat fakeTgChat = mock(TgChat.class); + final ChatContext chatContext = new ChatContext(); + chatContext.setAdditionalProperty("en example", "a value"); + when(fakeTgChat.getChatContext()).thenReturn(chatContext); + when(fakeClock.now()).thenReturn(69420L); + + chatUtil.updateChatContext(fakeTgChat, "/test1", 42, Collections.emptyMap()); + + verify(fakeTgChat, times(1)).getChatContext(); + final ArgumentCaptor chatContextArgumentCaptor = + ArgumentCaptor.forClass(ChatContext.class); + verify(fakeTgChat, times(1)).setChatContext(chatContextArgumentCaptor.capture()); + final ChatContext capturedChatContextValue = chatContextArgumentCaptor.getValue(); + final Map gotAdditionalProperties = + capturedChatContextValue.getAdditionalProperties(); + assertEquals( + 0, + gotAdditionalProperties.size(), + "The map should be empty in this case, but some elements where found"); + } } diff --git a/src/test/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaignIntegrationTest.java b/src/test/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaignIntegrationTest.java new file mode 100644 index 0000000..d7ad6ef --- /dev/null +++ b/src/test/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaignIntegrationTest.java @@ -0,0 +1,273 @@ +package com.github.polpetta.mezzotre.telegram.command; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.github.polpetta.mezzotre.helper.Loader; +import com.github.polpetta.mezzotre.helper.TestConfig; +import com.github.polpetta.mezzotre.i18n.LocalizedMessageFactory; +import com.github.polpetta.mezzotre.i18n.TemplateContentGenerator; +import com.github.polpetta.mezzotre.orm.model.Campaign; +import com.github.polpetta.mezzotre.orm.model.TgChat; +import com.github.polpetta.mezzotre.orm.model.query.QCampaign; +import com.github.polpetta.mezzotre.orm.model.query.QTgChat; +import com.github.polpetta.mezzotre.orm.telegram.CampaignUtil; +import com.github.polpetta.mezzotre.orm.telegram.ChatUtil; +import com.github.polpetta.mezzotre.util.Clock; +import com.github.polpetta.mezzotre.util.UUIDGenerator; +import com.github.polpetta.types.json.ChatContext; +import com.google.gson.Gson; +import com.pengrad.telegrambot.model.Update; +import com.pengrad.telegrambot.request.BaseRequest; +import com.pengrad.telegrambot.request.SendMessage; +import io.ebean.Database; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.velocity.app.VelocityEngine; +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +@Tag("slow") +@Tag("database") +@Tag("velocity") +@Testcontainers +class CreateCampaignIntegrationTest { + + private static Gson gson; + + @Container + private final PostgreSQLContainer postgresServer = + new PostgreSQLContainer<>(TestConfig.POSTGRES_DOCKER_IMAGE); + + private VelocityEngine velocityEngine; + private Database database; + private UUIDGenerator fakeUUIDGenerator; + private Clock fakeClock; + private ChatUtil chatUtil; + private CampaignUtil campaignUtil; + private CreateCampaign createCampaign; + + @BeforeAll + static void beforeAll() { + gson = new Gson(); + } + + @BeforeEach + void setUp() throws Exception { + database = + Loader.connectToDatabase(Loader.loadDefaultEbeanConfigWithPostgresSettings(postgresServer)); + velocityEngine = Loader.defaultVelocityEngine(); + + fakeClock = mock(Clock.class); + fakeUUIDGenerator = mock(UUIDGenerator.class); + + chatUtil = new ChatUtil(fakeClock); + campaignUtil = new CampaignUtil(fakeUUIDGenerator); + + createCampaign = + new CreateCampaign( + new TemplateContentGenerator(new LocalizedMessageFactory(velocityEngine)), + Executors.newSingleThreadExecutor(), + fakeUUIDGenerator, + chatUtil, + campaignUtil); + } + + static Stream getValidCampaignEntries() { + return Stream.of( + Arguments.of("a simple name", "a simple description"), + Arguments.of("a simple name", "a simple\nmultiline\n description"), + Arguments.of( + "an \uD83E\uDD21 emoji \uD83D\uDCAF name \uD83D\uDD25", + "a very \uD83E\uDDE8 campaign description \uD83E\uDD16"), + Arguments.of("一个简单的名字", "一个简单的描述")); + } + + @ParameterizedTest + @MethodSource("getValidCampaignEntries") + @Timeout(value = 1, unit = TimeUnit.MINUTES) + void shouldCreateANewCampaign(String name, String description) throws Exception { + when(fakeUUIDGenerator.generateAsString()).thenReturn("64b483b4-7de8-4632-9117-927756d26210"); + final TgChat chat = + new TgChat( + 42L, new ChatContext(), "en-US", true // doesn't really matter + ); + chat.save(); + + { + final Update firstMessage = + gson.fromJson( + "{\n" + + "\"update_id\":10000,\n" + + "\"message\":{\n" + + " \"date\":1441645532,\n" + + " \"chat\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":42,\n" + + " \"type\": \"private\",\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"message_id\":1365,\n" + + " \"from\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"text\":\"/createCampaign\"\n" + + "}\n" + + "}", + Update.class); + + final CompletableFuture>> got = + createCampaign.process(chat, firstMessage); + final Optional> baseRequestOptional = got.get(); + final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); + assertEquals( + "Very well, give me a second that I go grab some scroll, ink and quill...\n" + + "\n" + + "_*Searches frenetically in the desk between piles of books and written scrolls for" + + " a free piece of scroll*_\n" + + "\n" + + "Here we are! Please, tell me, how would you like to call your new campaign?", + gotResponse.getParameters().get("text")); + + final ChatContext retrievedChatContext = + Objects.requireNonNull(new QTgChat().id.eq(42L).findOne()).getChatContext(); + assertEquals(1, retrievedChatContext.getStep()); + assertEquals("/createCampaign", retrievedChatContext.getStage()); + } + + { + final Update secondMessageName = + gson.fromJson( + "{\n" + + "\"update_id\":10000,\n" + + "\"message\":{\n" + + " \"date\":1441645532,\n" + + " \"chat\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"type\": \"private\",\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"message_id\":1365,\n" + + " \"from\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"text\":\"" + + name + + "\"\n" + + "}\n" + + "}", + Update.class); + + final CompletableFuture>> got = + createCampaign.process(chat, secondMessageName); + final Optional> baseRequestOptional = got.get(); + final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); + assertEquals( + "Uhmm yes, " + + name + + "... Very well, great name choice by the way! Now, would you like to give me a" + + " short description of your campaign? You can skip this step if you don't want," + + " otherwise just reply with the description", + gotResponse.getParameters().get("text")); + + final ChatContext retrievedChatContext = + Objects.requireNonNull(new QTgChat().id.eq(42L).findOne()).getChatContext(); + assertEquals(2, retrievedChatContext.getStep()); + assertEquals("/createCampaign", retrievedChatContext.getStage()); + assertEquals(name, retrievedChatContext.getAdditionalProperties().get("campaign_name")); + } + + { + final Update thirdMessageDescription = + gson.fromJson( + "{\n" + + "\"update_id\":10000,\n" + + "\"message\":{\n" + + " \"date\":1441645532,\n" + + " \"chat\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"type\": \"private\",\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"message_id\":1365,\n" + + " \"from\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"text\":\"" + + description + + "\"\n" + + "}\n" + + "}", + Update.class); + + final CompletableFuture>> got = + createCampaign.process(chat, thirdMessageDescription); + final Optional> baseRequestOptional = got.get(); + final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); + assertEquals( + "_*Finishes to write down on the scroll the last details*_\n" + + "\n" + + "All done! I have successfully added your campaign to my archives! Let me store it" + + " properly...\n" + + "\n" + + "_*Moves the scroll into a pile of other, disorganized, scrolls*_\n" + + "\n" + + "Now, if you want, you can share this campaign to other players so that they can" + + " join! To do this, just click on the button below and then select the user or the" + + " group you want to share this campaign with! They will be able to add their" + + " characters and see the other characters in this campaign", + gotResponse.getParameters().get("text")); + + final ChatContext retrievedChatContext = + Objects.requireNonNull(new QTgChat().id.eq(42L).findOne()).getChatContext(); + assertEquals(3, retrievedChatContext.getStep()); + assertEquals("/createCampaign", retrievedChatContext.getStage()); + assertEquals( + 0, + retrievedChatContext.getAdditionalProperties().size(), + () -> + "Additional Properties should be empty, instead got: \n" + + retrievedChatContext.getAdditionalProperties().entrySet().stream() + .map(e -> "key: " + e.getKey() + " -> value: " + e.getValue()) + .collect(Collectors.joining("\n"))); + } + + final Campaign gotCampaign = + new QCampaign().name.eq(name).id.eq("64b483b4-7de8-4632-9117-927756d26210").findOne(); + assertNotNull(gotCampaign); + // First two assertions kinda pointless btw + assertEquals("64b483b4-7de8-4632-9117-927756d26210", gotCampaign.getId()); + assertEquals(name, gotCampaign.getName()); + assertEquals(description, gotCampaign.getDescription()); + } + + // TODO add invalid name tests, add InlineButtonTests too +} diff --git a/src/test/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaignTest.java b/src/test/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaignTest.java index c0ca1e2..920a85d 100644 --- a/src/test/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaignTest.java +++ b/src/test/java/com/github/polpetta/mezzotre/telegram/command/CreateCampaignTest.java @@ -13,6 +13,7 @@ import com.github.polpetta.types.json.ChatContext; import com.google.gson.Gson; import com.pengrad.telegrambot.model.Update; import com.pengrad.telegrambot.request.BaseRequest; +import com.pengrad.telegrambot.request.SendMessage; import java.util.Collections; import java.util.Map; import java.util.Optional; @@ -62,7 +63,7 @@ class CreateCampaignTest { fakeCampaignUtil); } - public static Stream getMultipleValidCampaignEntries() { + static Stream getValidCampaignEntries() { return Stream.of( Arguments.of("a simple name", "a simple description"), Arguments.of("a simple name", "a simple\nmultiline\n description"), @@ -73,7 +74,7 @@ class CreateCampaignTest { } @ParameterizedTest - @MethodSource("getMultipleValidCampaignEntries") + @MethodSource("getValidCampaignEntries") @Timeout(value = 1, unit = TimeUnit.MINUTES) void shouldGenerateANewCampaign(String name, String description) throws Exception { @@ -116,6 +117,7 @@ class CreateCampaignTest { createCampaign.process(fakeTgChat, firstMessage); final Optional> baseRequestOptional = got.get(); final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); assertEquals("a string", gotResponse.getParameters().get("text")); verify(fakeChatUtil, times(1)) @@ -124,7 +126,7 @@ class CreateCampaignTest { { when(fakeTemplateContentGenerator.mergeTemplate( - any(), eq("en-US"), eq("template/telegram/createCampaign.2.vm"))) + any(), eq("en-US"), eq("template/telegram/createCampaign.1.vm"))) .thenReturn("a second string"); final ChatContext chatContext = new ChatContext(); chatContext.setStep(1); @@ -161,6 +163,7 @@ class CreateCampaignTest { createCampaign.process(fakeTgChat, secondMessageName); final Optional> baseRequestOptional = got.get(); final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); assertEquals("a second string", gotResponse.getParameters().get("text")); final ArgumentCaptor> capturedChatCtx = @@ -175,7 +178,7 @@ class CreateCampaignTest { { when(fakeTemplateContentGenerator.mergeTemplate( - any(), eq("en-US"), eq("template/telegram/createCampaign.3.vm"))) + any(), eq("en-US"), eq("template/telegram/createCampaign.2.vm"))) .thenReturn("a third string"); final ChatContext chatContext = new ChatContext(); chatContext.setStep(2); @@ -213,6 +216,7 @@ class CreateCampaignTest { createCampaign.process(fakeTgChat, thirdMessageDescription); final Optional> baseRequestOptional = got.get(); final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); assertEquals("a third string", gotResponse.getParameters().get("text")); verify(fakeCampaignUtil, times(1)).insertNewCampaign(name, description); @@ -222,4 +226,268 @@ class CreateCampaignTest { } // TODO test failures, check InlineButtons too + + static Stream getInvalidCampaignNameEntries() { + // In the future we can add more invalid test cases + return Stream.of( + Arguments.of( + "jDjonwP0iRSDGwRfUbdwOoF9iq478mRvMjaFCB9mtwKHyymOp0neEj3XU5aOafffyFeKyJS0sFuleeYVHDavMeoZf6ozM86MfB82K0ONtBztEiWy35gWmxefTfLf6xyhXdI8Monev9F6J68lqgedHYGuzORvMbfMiAu673v7tv5ZNkaoBko3q4aiI4zDL1IWZx1drucRc4puZq9XUeNEyw9Fahpn33nCt15CzC9YTVqNDGu6vR3P52GUZKlv8hRv33nCt15CzC9YTVqNDGu6vR3P52GUZKlv8hRv")); + } + + @ParameterizedTest + @Timeout(value = 1, unit = TimeUnit.MINUTES) + @MethodSource("getInvalidCampaignNameEntries") + void shouldNotPassNameValidation(String name) throws Exception { + final TgChat fakeTgChat = mock(TgChat.class); + final ChatContext initialChatContext = new ChatContext(); + initialChatContext.setStep(0); // implicit but better specify just for clarity + when(fakeTgChat.getChatContext()).thenReturn(initialChatContext); + when(fakeTgChat.getLocale()).thenReturn("en-US"); + + { + when(fakeTemplateContentGenerator.mergeTemplate( + any(), eq("en-US"), eq("template/telegram/createCampaign.0.vm"))) + .thenReturn("a string"); + final Update firstMessage = + gson.fromJson( + "{\n" + + "\"update_id\":10000,\n" + + "\"message\":{\n" + + " \"date\":1441645532,\n" + + " \"chat\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"type\": \"private\",\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"message_id\":1365,\n" + + " \"from\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"text\":\"/createCampaign\"\n" + + "}\n" + + "}", + Update.class); + + final CompletableFuture>> got = + createCampaign.process(fakeTgChat, firstMessage); + final Optional> baseRequestOptional = got.get(); + final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); + assertEquals("a string", gotResponse.getParameters().get("text")); + + verify(fakeChatUtil, times(1)) + .updateChatContext(fakeTgChat, "/createCampaign", 1, Collections.emptyMap()); + } + + { + when(fakeTemplateContentGenerator.mergeTemplate( + any(), eq("en-US"), eq("template/telegram/createCampaign.nameNotValid.vm"))) + .thenReturn("an error message"); + final ChatContext chatContext = new ChatContext(); + chatContext.setStep(1); + when(fakeTgChat.getChatContext()).thenReturn(chatContext); + + final Update secondMessageName = + gson.fromJson( + "{\n" + + "\"update_id\":10000,\n" + + "\"message\":{\n" + + " \"date\":1441645532,\n" + + " \"chat\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"type\": \"private\",\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"message_id\":1365,\n" + + " \"from\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"text\":\"" + + name + + "\"\n" + + "}\n" + + "}", + Update.class); + + final CompletableFuture>> got = + createCampaign.process(fakeTgChat, secondMessageName); + final Optional> baseRequestOptional = got.get(); + final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); + assertEquals("an error message", gotResponse.getParameters().get("text")); + + verify(fakeChatUtil, times(0)) + .updateChatContext(eq(fakeTgChat), eq("/createCampaign"), eq(2), any()); + } + } + + static Stream getInvalidCampaignDescriptionEntries() { + // In the future we can add more invalid test cases + return Stream.of( + Arguments.of( + "a campaign name", + "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")); + } + + @ParameterizedTest + @Timeout(value = 1, unit = TimeUnit.MINUTES) + @MethodSource("getInvalidCampaignDescriptionEntries") + void shouldNotPassDescriptionValidation(String name, String description) throws Exception { + + final TgChat fakeTgChat = mock(TgChat.class); + final ChatContext initialChatContext = new ChatContext(); + initialChatContext.setStep(0); // implicit but better specify just for clarity + when(fakeTgChat.getChatContext()).thenReturn(initialChatContext); + when(fakeTgChat.getLocale()).thenReturn("en-US"); + + { + when(fakeTemplateContentGenerator.mergeTemplate( + any(), eq("en-US"), eq("template/telegram/createCampaign.0.vm"))) + .thenReturn("a string"); + final Update firstMessage = + gson.fromJson( + "{\n" + + "\"update_id\":10000,\n" + + "\"message\":{\n" + + " \"date\":1441645532,\n" + + " \"chat\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"type\": \"private\",\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"message_id\":1365,\n" + + " \"from\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"text\":\"/createCampaign\"\n" + + "}\n" + + "}", + Update.class); + + final CompletableFuture>> got = + createCampaign.process(fakeTgChat, firstMessage); + final Optional> baseRequestOptional = got.get(); + final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); + assertEquals("a string", gotResponse.getParameters().get("text")); + + verify(fakeChatUtil, times(1)) + .updateChatContext(fakeTgChat, "/createCampaign", 1, Collections.emptyMap()); + } + + { + when(fakeTemplateContentGenerator.mergeTemplate( + any(), eq("en-US"), eq("template/telegram/createCampaign.1.vm"))) + .thenReturn("a second string"); + final ChatContext chatContext = new ChatContext(); + chatContext.setStep(1); + when(fakeTgChat.getChatContext()).thenReturn(chatContext); + + final Update secondMessageName = + gson.fromJson( + "{\n" + + "\"update_id\":10000,\n" + + "\"message\":{\n" + + " \"date\":1441645532,\n" + + " \"chat\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"type\": \"private\",\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"message_id\":1365,\n" + + " \"from\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"text\":\"" + + name + + "\"\n" + + "}\n" + + "}", + Update.class); + + final CompletableFuture>> got = + createCampaign.process(fakeTgChat, secondMessageName); + final Optional> baseRequestOptional = got.get(); + final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); + assertEquals("a second string", gotResponse.getParameters().get("text")); + + final ArgumentCaptor> capturedChatCtx = + ArgumentCaptor.forClass(Map.class); + verify(fakeChatUtil, times(1)) + .updateChatContext( + eq(fakeTgChat), eq("/createCampaign"), eq(2), capturedChatCtx.capture()); + + final Map chatCtxValue = capturedChatCtx.getValue(); + assertEquals(name, chatCtxValue.get("campaign_name")); + } + + { + when(fakeTemplateContentGenerator.mergeTemplate( + any(), eq("en-US"), eq("template/telegram/createCampaign.descriptionNotValid.vm"))) + .thenReturn("an error message"); + final ChatContext chatContext = new ChatContext(); + chatContext.setStep(2); + chatContext.setAdditionalProperty("campaign_name", name); + when(fakeTgChat.getChatContext()).thenReturn(chatContext); + + final Update thirdMessageDescription = + gson.fromJson( + "{\n" + + "\"update_id\":10000,\n" + + "\"message\":{\n" + + " \"date\":1441645532,\n" + + " \"chat\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"type\": \"private\",\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"message_id\":1365,\n" + + " \"from\":{\n" + + " \"last_name\":\"Test Lastname\",\n" + + " \"id\":1111111,\n" + + " \"first_name\":\"Test Firstname\",\n" + + " \"username\":\"Testusername\"\n" + + " },\n" + + " \"text\":\"" + + description + + "\"\n" + + "}\n" + + "}", + Update.class); + + final CompletableFuture>> got = + createCampaign.process(fakeTgChat, thirdMessageDescription); + final Optional> baseRequestOptional = got.get(); + final BaseRequest gotResponse = baseRequestOptional.get(); + assertInstanceOf(SendMessage.class, gotResponse); + assertEquals("an error message", gotResponse.getParameters().get("text")); + + verify(fakeCampaignUtil, times(1)).insertNewCampaign(name, description); + verify(fakeChatUtil, times(1)) + .updateChatContext(fakeTgChat, "/createCampaign", 3, Collections.emptyMap()); + } + } }