public async Task ContentChangedNotification()
        {
            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test"
            };
            var attr2 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test"
            };

            try {
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(TestExtension <Test1>));
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr2, typeof(TestExtension <Test2>));

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.test", null, null));

                    TestExtension <Test1> .ResetCounters();

                    TestExtension <Test2> .ResetCounters();

                    controller.NotifyContentChanged();

                    Assert.AreEqual(1, TestExtension <Test1> .ContentChangedCount);
                    Assert.AreEqual(1, TestExtension <Test2> .ContentChangedCount);
                }
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr2);
            }
        }
        public async Task OwnerActivationDeactivation()
        {
            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test"
            };

            try {
                ProducerExtension.ResetCounters();
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(OwnerConditionedExtension));

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.test", null, new MyWorkspaceObject()));

                    Assert.IsNotNull(controller.GetContent <OwnerConditionedExtension> ());
                    Assert.AreEqual(1, OwnerConditionedExtension.LiveExtensions.Count);

                    controller.Owner = null;

                    Assert.IsNull(controller.GetContent <OwnerConditionedExtension> ());
                    Assert.AreEqual(0, OwnerConditionedExtension.LiveExtensions.Count);

                    controller.Owner = new MyWorkspaceObject();

                    Assert.IsNotNull(controller.GetContent <OwnerConditionedExtension> ());
                    Assert.AreEqual(1, OwnerConditionedExtension.LiveExtensions.Count);
                }
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
            }
        }
        public async Task OwnerChangedNotification()
        {
            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test"
            };

            try {
                ProducerExtension.ResetCounters();
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(ProducerExtension));

                using (var controller = new TestControllerWithExtension()) {
                    var owner = new MyWorkspaceObject();
                    await controller.Initialize(new FileDescriptor ("foo.test", null, owner));

                    var ext = controller.GetContent <ProducerExtension> ();
                    Assert.IsNotNull(ext);
                    Assert.AreSame(owner, ext.KnownOwner);

                    var owner2 = new MyWorkspaceObject();
                    controller.Owner = owner2;
                    Assert.AreSame(owner2, ext.KnownOwner);
                }
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
            }
        }
        public async Task GetContent(Type type, bool found)
        {
            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test"
            };

            try {
                ProducerExtension.ResetCounters();
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(ProducerExtension));

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.test", null, null));

                    if (found)
                    {
                        Assert.IsNotNull(controller.GetContent(type));
                    }
                    else
                    {
                        Assert.IsNull(controller.GetContent(type));
                    }
                }
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
            }
        }
        public async Task FileExtensionActivationDeactivation()
        {
            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test"
            };

            try {
                ProducerExtension.ResetCounters();
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(ProducerExtension));

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.bar", null, null));

                    Assert.AreEqual(0, ProducerExtension.InstancesCreated);

                    controller.FilePath = "foo.test";
                    Assert.AreEqual(1, ProducerExtension.InstancesCreated);
                    Assert.AreEqual(0, ProducerExtension.InstancesDisposed);
                    Assert.IsNotNull(controller.GetContent <ProducerExtension> ());

                    controller.FilePath = "foo.var";
                    Assert.AreEqual(1, ProducerExtension.InstancesCreated);
                    Assert.AreEqual(1, ProducerExtension.InstancesDisposed);
                    Assert.IsNull(controller.GetContent <ProducerExtension> ());
                }
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
            }
        }
        public async Task AttachControllerExtension()
        {
            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test"
            };
            var attr2 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test2"
            };

            try {
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(TestExtension <ExtensionThatMatches>));
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr2, typeof(TestExtension <ExtensionThatDoesntMatch>));

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.test", null, null));

                    Assert.AreEqual(1, TestExtension <ExtensionThatMatches> .InstancesCreated);
                    Assert.AreEqual(0, TestExtension <ExtensionThatMatches> .InstancesDisposed);

                    Assert.AreEqual(0, TestExtension <ExtensionThatDoesntMatch> .InstancesCreated);
                    Assert.AreEqual(0, TestExtension <ExtensionThatDoesntMatch> .InstancesDisposed);
                }

                Assert.AreEqual(1, TestExtension <ExtensionThatMatches> .InstancesCreated);
                Assert.AreEqual(1, TestExtension <ExtensionThatMatches> .InstancesDisposed);
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr2);
            }
        }
        public async Task StatusSerialization()
        {
            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test"
            };
            var attr2 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = "*"
            };

            try {
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(StatusTest1));
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr2, typeof(StatusTest2));
                Properties storedStatus = null;

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.test", null, null));

                    StatusTest1.LiveExtensions [0].Status = "status1";
                    StatusTest2.LiveExtensions [0].Status = "status2";

                    controller.FilePath = "foo.txt";

                    Assert.AreEqual(0, StatusTest1.LiveExtensions.Count);
                    storedStatus = controller.GetDocumentStatus();

                    // Status should be properly restored when reactivating extension
                    controller.FilePath = "foo.test";
                    Assert.AreEqual(1, StatusTest1.LiveExtensions.Count);
                    Assert.AreEqual("status1", StatusTest1.LiveExtensions [0].Status);
                }

                Assert.AreEqual(0, StatusTest1.LiveExtensions.Count);
                Assert.AreEqual(0, StatusTest2.LiveExtensions.Count);

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.test", null, null), storedStatus);

                    // Even though the StatusTest1 extension was disposed when the status was retrieved,
                    // its status was stored before disposing, so it should be available now.
                    Assert.AreEqual("status1", StatusTest1.LiveExtensions [0].Status);
                    Assert.AreEqual("status2", StatusTest2.LiveExtensions [0].Status);
                }

                Assert.AreEqual(0, ProducerExtension.LiveExtensions.Count);
                Assert.AreEqual(0, ConsumerExtension.LiveExtensions.Count);
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr2);
            }
        }
        public async Task ExtensionDependingOnExtension()
        {
            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test"
            };
            var attr2 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = "*"
            };

            try {
                ProducerExtension.ResetCounters();
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(ProducerExtension));
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr2, typeof(ConsumerExtension));

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.test", null, null));

                    Assert.AreEqual(1, ProducerExtension.InstancesCreated);
                    Assert.AreEqual(0, ProducerExtension.InstancesDisposed);

                    Assert.AreEqual(2, ConsumerExtension.InstancesCreated);
                    Assert.AreEqual(1, ConsumerExtension.InstancesDisposed);

                    Assert.IsNotNull(controller.GetContent <ProducerExtension> ());
                    Assert.IsNotNull(controller.GetContent <ConsumerExtension> ());

                    // If Producer extension is removed, consumer should also be removed

                    controller.FilePath = "foo.txt";

                    Assert.IsNull(controller.GetContent <ProducerExtension> ());
                    Assert.IsNull(controller.GetContent <ConsumerExtension> ());
                    Assert.AreEqual(1, ProducerExtension.InstancesDisposed);
                    Assert.AreEqual(0, ConsumerExtension.LiveExtensions.Count);
                }

                Assert.AreEqual(0, ProducerExtension.LiveExtensions.Count);
                Assert.AreEqual(0, ConsumerExtension.LiveExtensions.Count);
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr2);
            }
        }
        public async Task FileAttributeFilters(ExportDocumentControllerExtensionAttribute attribute, bool matches)
        {
            try {
                ProducerExtension.ResetCounters();
                IdeServices.DocumentControllerService.RegisterControllerExtension(attribute, typeof(ProducerExtension));

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.test", "application/test", null));

                    var ext = controller.GetContent <ProducerExtension> ();
                    if (matches)
                    {
                        Assert.IsNotNull(ext);
                    }
                    else
                    {
                        Assert.IsNull(ext);
                    }
                }
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attribute);
            }
        }
        public async Task GetContents(Type type, int count)
        {
            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test"
            };
            var attr2 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = "*"
            };

            try {
                ProducerExtension.ResetCounters();
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(ProducerExtension));
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr2, typeof(ProducerExtension));

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.test", null, null));

                    Assert.AreEqual(count, controller.GetContents(type).Count());
                }
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr2);
            }
        }
        public async Task ProjectReloadCapabilityOverride()
        {
            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".full, .full-unsaved-default, .full-unsaved-default-none"
            };
            var attr2 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".unsaved, .full-unsaved-default, .full-unsaved-default-none"
            };
            var attr3 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".none, .full-unsaved-default-none"
            };
            var attr4 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".default, .full-unsaved-default"
            };

            try {
                ProducerExtension.ResetCounters();
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(FullReloadExtension));
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr2, typeof(UnsavedDataReloadExtension));
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr3, typeof(NoReloadExtension));
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr4, typeof(ProducerExtension));

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.noext", null, null));

                    // No extensions

                    controller.SetReloadCapability(ProjectReloadCapability.None);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.Full);
                    Assert.AreEqual(ProjectReloadCapability.Full, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.UnsavedData);
                    Assert.AreEqual(ProjectReloadCapability.UnsavedData, controller.ProjectReloadCapability);

                    // Extension with ProjectReloadCapability.Full

                    controller.FilePath = "foo.full";

                    controller.SetReloadCapability(ProjectReloadCapability.None);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.Full);
                    Assert.AreEqual(ProjectReloadCapability.Full, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.UnsavedData);
                    Assert.AreEqual(ProjectReloadCapability.UnsavedData, controller.ProjectReloadCapability);

                    // Extension with ProjectReloadCapability.UnsavedData

                    controller.FilePath = "foo.unsaved";

                    controller.SetReloadCapability(ProjectReloadCapability.None);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.Full);
                    Assert.AreEqual(ProjectReloadCapability.UnsavedData, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.UnsavedData);
                    Assert.AreEqual(ProjectReloadCapability.UnsavedData, controller.ProjectReloadCapability);

                    // Extension with ProjectReloadCapability.None

                    controller.FilePath = "foo.none";

                    controller.SetReloadCapability(ProjectReloadCapability.None);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.Full);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.UnsavedData);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);

                    // Extension with default

                    controller.FilePath = "foo.default";

                    controller.SetReloadCapability(ProjectReloadCapability.None);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.Full);
                    Assert.AreEqual(ProjectReloadCapability.Full, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.UnsavedData);
                    Assert.AreEqual(ProjectReloadCapability.UnsavedData, controller.ProjectReloadCapability);

                    // Extensions with Full, UnsavedData and default

                    controller.FilePath = "foo.full-unsaved-default";

                    controller.SetReloadCapability(ProjectReloadCapability.None);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.Full);
                    Assert.AreEqual(ProjectReloadCapability.UnsavedData, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.UnsavedData);
                    Assert.AreEqual(ProjectReloadCapability.UnsavedData, controller.ProjectReloadCapability);

                    // Extensions with Full, UnsavedData, Default and none

                    controller.FilePath = "foo.full-unsaved-default-none";

                    controller.SetReloadCapability(ProjectReloadCapability.None);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.Full);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);

                    controller.SetReloadCapability(ProjectReloadCapability.UnsavedData);
                    Assert.AreEqual(ProjectReloadCapability.None, controller.ProjectReloadCapability);
                }
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr2);
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr3);
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr4);
            }
        }
        public async Task KeepExtensionInstanceOnRefresh()
        {
            // When reloading extensions, if an extension still applies it should be reused, not re-created

            var attr1 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test1, .test2"
            };
            var attr2 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test1"
            };
            var attr3 = new ExportDocumentControllerExtensionAttribute {
                FileExtension = ".test2"
            };

            try {
                TestExtension <Test1> .ResetCounters();

                TestExtension <Test2> .ResetCounters();

                TestExtension <Test3> .ResetCounters();

                IdeServices.DocumentControllerService.RegisterControllerExtension(attr1, typeof(TestExtension <Test1>));
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr2, typeof(TestExtension <Test2>));
                IdeServices.DocumentControllerService.RegisterControllerExtension(attr3, typeof(TestExtension <Test3>));

                using (var controller = new TestControllerWithExtension()) {
                    await controller.Initialize(new FileDescriptor ("foo.test1", null, null));

                    var instance = controller.GetContent <TestExtension <Test1> > ();
                    Assert.IsNotNull(instance);
                    Assert.AreEqual(1, TestExtension <Test1> .LiveExtensions.Count());

                    Assert.IsNotNull(controller.GetContent <TestExtension <Test2> > ());
                    Assert.AreEqual(1, TestExtension <Test2> .LiveExtensions.Count());

                    Assert.IsNull(controller.GetContent <TestExtension <Test3> > ());
                    Assert.AreEqual(0, TestExtension <Test3> .LiveExtensions.Count());

                    controller.FilePath = "foo.test2";

                    Assert.AreSame(instance, controller.GetContent <TestExtension <Test1> > ());
                    Assert.AreEqual(1, TestExtension <Test1> .LiveExtensions.Count());

                    Assert.IsNull(controller.GetContent <TestExtension <Test2> > ());
                    Assert.AreEqual(0, TestExtension <Test2> .LiveExtensions.Count());

                    Assert.IsNotNull(controller.GetContent <TestExtension <Test3> > ());
                    Assert.AreEqual(1, TestExtension <Test3> .LiveExtensions.Count());

                    controller.FilePath = "foo.test1";

                    Assert.AreSame(instance, controller.GetContent <TestExtension <Test1> > ());
                    Assert.AreEqual(1, TestExtension <Test1> .LiveExtensions.Count());

                    Assert.IsNotNull(controller.GetContent <TestExtension <Test2> > ());
                    Assert.AreEqual(1, TestExtension <Test2> .LiveExtensions.Count());

                    Assert.IsNull(controller.GetContent <TestExtension <Test3> > ());
                    Assert.AreEqual(0, TestExtension <Test3> .LiveExtensions.Count());
                }
            } finally {
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr1);
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr2);
                IdeServices.DocumentControllerService.UnregisterControllerExtension(attr3);
            }
        }