Пример #1
0
 //TODO 切换CardManager状态
 private void SwitchState()
 {
     if (currentState == CardManagerState.Init)
     {
         currentState = CardManagerState.Run;
     }
     else if (currentState == CardManagerState.Run)
     {
         currentState = CardManagerState.Init;
     }
 }
        public async Task TestUnsaveActivityAsync()
        {
            const string ACTIVITYID1 = "activity ID 1";
            const string ACTIVITYID2 = "activity ID 2";

            var manager     = CreateManager();
            var turnContext = CreateTurnContext();
            var state       = new CardManagerState();
            var activity1   = new Activity(id: ACTIVITYID1);
            var activity2   = new Activity(id: ACTIVITYID2);
            var activity3   = new Activity(id: ACTIVITYID2);

            await manager.StateAccessor.SetAsync(turnContext, state);

            await manager.UnsaveActivityAsync(turnContext, ACTIVITYID1);

            Assert.AreEqual(0, state.SavedActivities.Count);

            state.SavedActivities.Add(activity1);
            state.SavedActivities.Add(activity2);
            state.SavedActivities.Add(activity3);

            Assert.AreEqual(3, state.SavedActivities.Count);

            await manager.UnsaveActivityAsync(turnContext, ACTIVITYID1);

            Assert.AreEqual(2, state.SavedActivities.Count, "Did not remove one activity");

            await manager.UnsaveActivityAsync(turnContext, ACTIVITYID2);

            Assert.AreEqual(0, state.SavedActivities.Count, "Did not remove two activities");

            await Assert.ThrowsExceptionAsync <ArgumentNullException>(async() => await manager.UnsaveActivityAsync(turnContext, null));

            await Assert.ThrowsExceptionAsync <ArgumentNullException>(async() => await manager.UnsaveActivityAsync(null, "ID"));
        }
        public async Task TestDeleteAsync()
        {
            const string ACTIONID1     = "action ID 1";
            const string ACTIONID2     = "action ID 2";
            const string ACTIONID3     = "action ID 3";
            const string ACTIONID4     = "action ID 4";
            const string ACTIONID5     = "action ID 5";
            const string ACTIONID6     = "action ID 6";
            const string CARDID        = "card ID";
            const string CAROUSELID    = "carousel ID";
            const string BATCHID       = "batch ID";
            const string CHOICEINPUTID = "choice set input ID";
            const string DATEINPUTID   = "date input ID";

            var manager      = CreateManager();
            var turnContext  = CreateTurnContext();
            var state        = new CardManagerState();
            var updated      = false;
            var deletedCount = 0;

            var activity1 = new Activity
            {
                Id          = "activity ID 1",
                Attachments = new List <Attachment>
                {
                    // This attachment should be deleted after both actions in the actions property are deleted
                    // despite having a select action
                    new Attachment
                    {
                        Name        = "0,0",
                        ContentType = AdaptiveCard.ContentType,
                        Content     = new AdaptiveCard("1.0")
                        {
                            Actions = new List <AdaptiveAction>
                            {
                                new AdaptiveSubmitAction
                                {
                                    Data = new Dictionary <string, string>
                                    {
                                        { DataIdScopes.Action, ACTIONID1 },
                                    }.WrapLibraryData(),
                                },
                                new AdaptiveSubmitAction
                                {
                                    Data = new Dictionary <string, string>
                                    {
                                        { DataIdScopes.Action, ACTIONID2 },
                                    }.WrapLibraryData(),
                                },
                            },
                            SelectAction = new AdaptiveSubmitAction
                            {
                                Data = new Dictionary <string, string>
                                {
                                    { DataIdScopes.Action, "Irrelevant action ID" },
                                }.WrapLibraryData(),
                            },
                        },
                    },

                    // When this attachment is deleted, the whole activity should be deleted
                    new Attachment
                    {
                        Name        = "0,1",
                        ContentType = HeroCard.ContentType,
                        Content     = new HeroCard(buttons: new List <CardAction>
                        {
                            new CardAction(ActionTypes.PostBack, value: new Dictionary <string, string>
                            {
                                { DataIdScopes.Action, ACTIONID3 },
                            }.WrapLibraryData()),
                            new CardAction(ActionTypes.MessageBack, value: new Dictionary <string, string>
                            {
                                { DataIdScopes.Action, ACTIONID4 },
                            }.WrapLibraryData()),
                        }),
                    },
                }
            };

            var activity2 = new Activity
            {
                Id          = "activity ID 2",
                Attachments = new List <Attachment>
                {
                    // This attachment shouldn't be deleted because of its body
                    new Attachment
                    {
                        Name        = "1,0",
                        ContentType = AdaptiveCard.ContentType,
                        Content     = new AdaptiveCard("1.2")
                        {
                            Body = new List <AdaptiveElement>
                            {
                                new AdaptiveChoiceSetInput
                                {
                                    Id = CHOICEINPUTID,
                                },
                            },
                            Actions = new List <AdaptiveAction>
                            {
                                new AdaptiveSubmitAction
                                {
                                    Data = new Dictionary <string, string>
                                    {
                                        { DataIdScopes.Action, ACTIONID5 },
                                    }.WrapLibraryData(),
                                },
                            },
                        },
                    },

                    // This attachment shouldn't be deleted because of its title
                    new Attachment
                    {
                        Name        = "1,1",
                        ContentType = HeroCard.ContentType,
                        Content     = new HeroCard(title: "Irrelevant title", buttons: new List <CardAction>
                        {
                            new CardAction(ActionTypes.PostBack, value: new Dictionary <string, string>
                            {
                                { DataIdScopes.Action, ACTIONID6 },
                            }.WrapLibraryData()),
                        }),
                    },
                },
            };

            var activity3 = new Activity
            {
                Id          = "activity ID 3",
                Attachments = new List <Attachment>
                {
                    // When this attachment is deleted, the activity won't be deleted
                    // but it should be removed from state
                    new Attachment
                    {
                        Name        = "2,0",
                        ContentType = AdaptiveCard.ContentType,
                        Content     = new AdaptiveCard("1.1")
                        {
                            Body = new List <AdaptiveElement>
                            {
                                new AdaptiveDateInput
                                {
                                    Id = DATEINPUTID,
                                },
                            },
                            Actions = new List <AdaptiveAction>
                            {
                                new AdaptiveSubmitAction
                                {
                                    Data = new Dictionary <string, string>
                                    {
                                        // Even though a carousel ID is used to identify an activity,
                                        // it can still be used to delete a single attachment
                                        { DataIdScopes.Carousel, CAROUSELID },
                                    }.WrapLibraryData(),
                                },
                            },
                        },
                    },

                    new Attachment
                    {
                        Name = "2,1",
                    },
                },
            };

            var activity4 = new Activity
            {
                Id          = "activity ID 4",
                Attachments = new List <Attachment>
                {
                    new Attachment
                    {
                        Name        = "3,0",
                        ContentType = HeroCard.ContentType,
                        Content     = new HeroCard(title: "Irrelevant title", buttons: new List <CardAction>
                        {
                            new CardAction(ActionTypes.MessageBack, value: new Dictionary <string, string>
                            {
                                // Even though a card ID is used to identify a single attachment,
                                // it can still be used to delete an activity
                                { DataIdScopes.Card, CARDID },
                            }.WrapLibraryData()),
                        }),
                    },
                    new Attachment
                    {
                        Name = "3,1",
                    },
                },
            };

            var activity5 = new Activity
            {
                Id          = "activity ID 5",
                Attachments = new List <Attachment>
                {
                    new Attachment
                    {
                        Name        = "4,0",
                        ContentType = HeroCard.ContentType,
                        Content     = new HeroCard(title: "Irrelevant title", buttons: new List <CardAction>
                        {
                            new CardAction(ActionTypes.PostBack, value: new Dictionary <string, string>
                            {
                                { DataIdScopes.Batch, BATCHID },
                            }.WrapLibraryData()),
                        }),
                    },
                    new Attachment
                    {
                        Name        = "4,1",
                        ContentType = AdaptiveCard.ContentType,
                        Content     = new AdaptiveCard("1.0")
                        {
                            Actions = new List <AdaptiveAction>
                            {
                                new AdaptiveSubmitAction
                                {
                                    Data = new Dictionary <string, string>
                                    {
                                        { DataIdScopes.Action, "Another irrelevant action ID" },
                                        { DataIdScopes.Card, "Irrelevant card ID" },
                                        { DataIdScopes.Carousel, "Irrelevant carousel ID" },
                                        { DataIdScopes.Batch, BATCHID },
                                    }.WrapLibraryData(),
                                },
                            },
                        },
                    },
                },
            };

            var activity6 = new Activity
            {
                Id          = "activity ID 6",
                Attachments = new List <Attachment>
                {
                    // Not all attachments need to have the batch ID
                    new Attachment
                    {
                        Name        = "5,0",
                        ContentType = AdaptiveCard.ContentType,
                        Content     = new AdaptiveCard("1.1")
                        {
                            Actions = new List <AdaptiveAction>
                            {
                                new AdaptiveSubmitAction
                                {
                                    Data = new Dictionary <string, string>
                                    {
                                        { DataIdScopes.Action, "Yet another irrelevant action ID" },
                                    }.WrapLibraryData(),
                                },
                            },
                        },
                    },

                    // As long as one attachment contains the batch ID,
                    // the activity will be included in the batch
                    new Attachment
                    {
                        Name        = "5,1",
                        ContentType = HeroCard.ContentType,
                        Content     = new HeroCard(title: "Irrelevant title", buttons: new List <CardAction>
                        {
                            new CardAction(ActionTypes.MessageBack, value: new Dictionary <string, string>
                            {
                                { DataIdScopes.Batch, BATCHID },
                            }.WrapLibraryData()),
                        }),
                    },
                },
            };

            var activity7 = new Activity
            {
                Id          = "activity ID 7",
                Attachments = new List <Attachment>
                {
                    new Attachment
                    {
                        Name        = "6,0",
                        ContentType = HeroCard.ContentType,
                        Content     = new HeroCard(buttons: new List <CardAction>
                        {
                            new CardAction(ActionTypes.PostBack, value: new Dictionary <string, string>
                            {
                                { DataIdScopes.Batch, "Irrelevant batch ID" },
                            }.WrapLibraryData()),
                        }),
                    },
                },
            };

            var activity8 = new Activity
            {
                Id = "Irrelevant activity ID",
            };

            // We need to use the active queue or else the test adapter will remove the ID
            // of each activity not in the queue when it tries to update them
            var queue = ((TestAdapter)turnContext.Adapter).ActiveQueue;

            queue.Enqueue(activity1);
            queue.Enqueue(activity2);
            queue.Enqueue(activity3);
            queue.Enqueue(activity4);
            queue.Enqueue(activity5);
            queue.Enqueue(activity6);
            queue.Enqueue(activity7);

            // The first 7 activities should be saved in state as well as the active queue
            state.SavedActivities.UnionWith(queue);

            // But this one shouldn't be
            queue.Enqueue(activity8);

            var expectedActivities = new[] { activity1 };

            turnContext.OnUpdateActivity((turnContext, activity, next) =>
            {
                Assert.AreSame(expectedActivities.Single(), activity);
                Assert.IsFalse(updated, "UpdateActivityAsync was called an extra time");

                updated = true;

                return(next());
            });

            turnContext.OnDeleteActivity((turnContext, reference, next) =>
            {
                Assert.IsTrue(expectedActivities.Any(activity => activity.Id == reference.ActivityId));

                deletedCount++;

                return(next());
            });

            turnContext.Activity.Value = new Dictionary <string, object>
            {
                // This shouldn't match any action data
                { DataIdScopes.Card, ACTIONID1 },
            }.WrapLibraryData();

            await manager.StateAccessor.SetAsync(turnContext, state);

            await manager.DeleteActionSourceAsync(turnContext, DataIdScopes.Action);

            Assert.IsFalse(updated);
            Assert.AreEqual(0, deletedCount);
            Assert.IsFalse(state.SavedActivities.Contains(activity8));
            Assert.AreEqual(7, state.SavedActivities.Count);
            Assert.IsTrue(queue.Contains(activity8));
            Assert.AreEqual(8, queue.Count());

            turnContext.Activity.Value = new Dictionary <string, object>
            {
                { DataIdScopes.Action, ACTIONID1 },
            }.WrapLibraryData();

            await manager.DeleteActionSourceAsync(turnContext, DataIdScopes.Action);

            var actionId = ((JObject)((AdaptiveSubmitAction)((AdaptiveCard)activity1.Attachments[0].Content)
                                      .Actions.Single()).Data).GetIdFromActionData(DataIdScopes.Action);

            Assert.IsTrue(updated);
            Assert.AreEqual(0, deletedCount);
            Assert.AreEqual(ACTIONID2, actionId, "Wrong action was deleted");
            Assert.AreEqual(7, state.SavedActivities.Count);
            Assert.AreEqual(8, queue.Count());

            updated = false;

            turnContext.Activity.Value = new Dictionary <string, object>
            {
                { DataIdScopes.Action, ACTIONID2 },
            }.WrapLibraryData();

            await manager.DeleteActionSourceAsync(turnContext, DataIdScopes.Action);

            Assert.IsTrue(updated);
            Assert.AreEqual(0, deletedCount);
            Assert.IsInstanceOfType(activity1.Attachments.Single().Content, typeof(HeroCard), "Card wasn't deleted");
            Assert.AreEqual(7, state.SavedActivities.Count);
            Assert.AreEqual(8, queue.Count());

            updated = false;

            turnContext.Activity.Value = new Dictionary <string, object>
            {
                { DataIdScopes.Action, ACTIONID3 },
            }.WrapLibraryData();

            await manager.DeleteActionSourceAsync(turnContext, DataIdScopes.Action);

            actionId = ((Dictionary <string, string>)((Dictionary <string, object>)((HeroCard)activity1.Attachments.Single().Content)
                                                      .Buttons.Single().Value)[PropertyNames.LibraryData])[DataIdScopes.Action];

            Assert.IsTrue(updated);
            Assert.AreEqual(0, deletedCount);
            Assert.AreEqual(ACTIONID4, actionId, "Wrong action was deleted");
            Assert.AreEqual(7, state.SavedActivities.Count);
            Assert.AreEqual(8, queue.Count());

            updated = false;

            turnContext.Activity.Value = new Dictionary <string, object>
            {
                { DataIdScopes.Action, ACTIONID4 },
            }.WrapLibraryData();

            await manager.DeleteActionSourceAsync(turnContext, DataIdScopes.Action);

            Assert.IsFalse(updated);
            Assert.AreEqual(1, deletedCount, "Activity wasn't deleted even though it was empty");
            Assert.IsFalse(state.SavedActivities.Contains(activity1), "Activity wasn't removed from state");
            Assert.AreEqual(6, state.SavedActivities.Count);
            Assert.IsFalse(queue.Contains(activity1), "Deleted activity not removed from the queue");
            Assert.AreEqual(7, queue.Count(), "Deleted activity not removed from the queue");

            deletedCount       = 0;
            expectedActivities = new[] { activity2 };

            turnContext.Activity.Value = new Dictionary <string, object>
            {
                { CHOICEINPUTID, "User-entered choice" },
                {
                    PropertyNames.LibraryData,
                    new Dictionary <string, string>
                    {
                        { DataIdScopes.Action, ACTIONID5 },
                    }
                },
            };

            await manager.DeleteActionSourceAsync(turnContext, DataIdScopes.Action);

            Assert.IsTrue(updated);
            Assert.AreEqual(0, deletedCount);
            Assert.IsFalse(((AdaptiveCard)activity2.Attachments[0].Content).Actions.Any(), "Action wasn't deleted");
            Assert.AreEqual(6, state.SavedActivities.Count);
            Assert.AreEqual(7, queue.Count());

            updated = false;

            turnContext.Activity.Value = new Dictionary <string, object>
            {
                { DataIdScopes.Action, ACTIONID6 },
            }.WrapLibraryData();

            await manager.DeleteActionSourceAsync(turnContext, DataIdScopes.Action);

            Assert.IsTrue(updated);
            Assert.AreEqual(0, deletedCount, "Activity was deleted even though it still had attachments");
            Assert.IsFalse(((AdaptiveCard)activity2.Attachments[0].Content).Actions.Any(), "Action wasn't deleted");
            Assert.IsFalse(state.SavedActivities.Contains(activity2), "Activity wasn't removed from state");
            Assert.AreEqual(5, state.SavedActivities.Count, "Saved activities weren't cleaned correctly");
            Assert.IsTrue(queue.Contains(activity2), "Cleaned activity removed from the queue");
            Assert.AreEqual(7, queue.Count(), "Cleaned activity removed from the queue");

            updated            = false;
            expectedActivities = new[] { activity3 };

            turnContext.Activity.Value = new Dictionary <string, object>
            {
                { DATEINPUTID, "User-entered date" },
                {
                    PropertyNames.LibraryData,
                    new Dictionary <string, string>
                    {
                        { DataIdScopes.Carousel, CAROUSELID },
                    }
                },
            };

            // We are deleting the card using a carousel ID
            await manager.DeleteActionSourceAsync(turnContext, DataIdScopes.Card);

            Assert.IsTrue(updated);
            Assert.AreEqual(0, deletedCount, "Activity was deleted even though it still had attachments");
            Assert.AreEqual(1, activity3.Attachments.Count(), "Attachment wasn't deleted");
            Assert.IsFalse(state.SavedActivities.Contains(activity3), "Activity wasn't removed from state");
            Assert.AreEqual(4, state.SavedActivities.Count, "Saved activities weren't cleaned correctly");
            Assert.IsTrue(queue.Contains(activity3), "Cleaned activity removed from the queue");
            Assert.AreEqual(7, queue.Count(), "Cleaned activity removed from the queue");

            updated            = false;
            expectedActivities = new[] { activity4 };

            turnContext.Activity.Value = new Dictionary <string, object>
            {
                { DataIdScopes.Card, CARDID },
            }.WrapLibraryData();

            // We are deleting the carousel using a card ID
            await manager.DeleteActionSourceAsync(turnContext, DataIdScopes.Carousel);

            Assert.IsFalse(updated);
            Assert.AreEqual(1, deletedCount);
            Assert.IsFalse(state.SavedActivities.Contains(activity4), "Activity wasn't removed from state");
            Assert.AreEqual(3, state.SavedActivities.Count, "Saved activities weren't cleaned correctly");
            Assert.IsFalse(queue.Contains(activity4), "Deleted activity not removed from the queue");
            Assert.AreEqual(6, queue.Count(), "Deleted activity not removed from the queue");

            deletedCount       = 0;
            expectedActivities = new[] { activity5, activity6 };

            turnContext.Activity.Value = new Dictionary <string, object>
            {
                { DataIdScopes.Batch, BATCHID },
            }.WrapLibraryData();

            // We are deleting the carousel using a card ID
            await manager.DeleteActionSourceAsync(turnContext, DataIdScopes.Batch);

            Assert.IsFalse(updated);
            Assert.AreEqual(2, deletedCount);
            Assert.AreEqual(activity7, state.SavedActivities.Single(), "Saved activities weren't cleaned correctly");
            Assert.IsFalse(queue.Contains(activity5), "Activity 5 not removed from the queue");
            Assert.IsFalse(queue.Contains(activity6), "Activity 6 activity not removed from the queue");
            Assert.AreEqual(4, queue.Count(), "Deleted activities not removed from the queue");

            await Assert.ThrowsExceptionAsync <ArgumentNullException>(async() => await manager.DeleteActionSourceAsync(null, DataIdScopes.Action));

            await Assert.ThrowsExceptionAsync <ArgumentNullException>(async() => await manager.DeleteActionSourceAsync(turnContext, string.Empty));
        }