Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Appenders/RiskeerUserDataFolderConverterTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Attributes/DynamicPropertyOrderAttributeTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Attributes/DynamicPropertyOrderEvaluationMethodAttributeTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Attributes/DynamicReadOnlyAttributeTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Attributes/DynamicReadOnlyValidationMethodAttributeTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Attributes/DynamicVisibleAttributeTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Attributes/DynamicVisibleValidationMethodAttributeTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Attributes/PropertyOrderAttributeTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Attributes/TestCaseClasses/DynamicPropertyOrderTestCases.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Attributes/TestCaseClasses/DynamicReadOnlyTestCases.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Attributes/TestCaseClasses/DynamicVisibilityTestCases.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Clipboard/ClipboardProviderTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Commands/ApplicationFeatureCommandHandlerTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Commands/GuiExportHandlerTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Commands/GuiImportHandlerTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Commands/GuiUpdateHandlerTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Commands/StorageCommandHandlerTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Commands/ViewCommandHandlerTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/ContextMenu/ContextMenuBuilderExceptionTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/ContextMenu/ContextMenuBuilderTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/ContextMenu/GuiContextMenuItemFactoryTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/ContextMenu/StrictContextMenuItemTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/ContextMenu/TreeViewContextMenuItemFactoryTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Converters/ColorTypeConverterTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Converters/ExpandableArrayConverterTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Converters/ExpandableReadOnlyArrayConverterTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Converters/KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttributeTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Converters/KeyValueElementAttributeTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Converters/KeyValueExpandableArrayConverterTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Converters/PngToIconConverterTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/ExceptionDialogTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/MainWindow/MainWindowTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/MessageWindow/MessageWindowDialogTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/MessageWindow/MessageWindowLogAppenderTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/MessageWindow/MessageWindowTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/ProgressDialog/ActivityProgressDialogTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/ProjectExplorer/ProjectExplorerTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/PropertyGridView/PropertyGridViewTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/PropertyGridView/PropertyResolverTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/RichTextFileTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/RichTextViewTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/SelectItemDialogTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/SelectViewDialogTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/SplashScreen/SplashScreenTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/ViewHost/AvalonDockViewHostTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/ViewHost/DocumentViewControllerTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/ViewHost/TestView.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/ViewHost/TestView.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/ViewHost/TestView.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Forms/ViewHost/ViewChangeEventArgsTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/GuiCoreTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Helpers/DialogBasedInquiryHelperTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Helpers/ExportHelperTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/OpenProjectActivityTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Plugin/ExportInfoTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Plugin/ImportInfoTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Plugin/PluginBaseTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Plugin/PropertyInfoTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Plugin/UpdateInfoTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Plugin/ViewInfoTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Properties/AssemblyInfo.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Properties/Resources.Designer.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/Properties/Resources.resx'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/PropertyBag/DynamicPropertyBagTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/PropertyBag/ObjectPropertiesTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecDescriptorTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/PropertyBag/ReadOnlyPropertyDescriptorDecoratorTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: Core/Common/test/Core.Common.Gui.Test/Resources/abacus.png =================================================================== diff -u -rce50b65f662bcccb1849444e4d51549731131234 -r781a97409ffc49e5b666a7856f633f46178056df Binary files differ Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/SaveProjectActivityTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/UITypeEditors/ColorEditorTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/UITypeEditors/SelectionEditorTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.Test/ViewPropertyEditorTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.TestUtil/Clipboard/ClipboardConfig.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.TestUtil/ContextMenu/CustomItemsOnlyContextMenuBuilder.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.TestUtil/Core.Common.Gui.TestUtil.csproj'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.TestUtil/PluginTestHelper.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Gui.TestUtil/Properties/AssemblyInfo.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Integration.Test/Core.Common.Integration.Test.csproj'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Integration.Test/Properties/AssemblyInfo.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 781a97409ffc49e5b666a7856f633f46178056df refers to a dead (removed) revision in file `Core/Common/test/Core.Common.Integration.Test/Riskeer/Application.Riskeer/GuiCoreIntegrationTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: Core/Gui/test/Core.Gui.Test/Appenders/RiskeerUserDataFolderConverterTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Appenders/RiskeerUserDataFolderConverterTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Appenders/RiskeerUserDataFolderConverterTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,73 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.IO; +using Core.Common.Util.Settings; +using Core.Gui.Appenders; +using log4net.Util; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Appenders +{ + [TestFixture] + public class RiskeerUserDataFolderConverterTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var converter = new RiskeerUserDataFolderConverter(); + + // Assert + Assert.IsInstanceOf(converter.FormattingInfo); + Assert.IsNull(converter.Next); + Assert.IsNull(converter.Option); + Assert.IsNull(converter.Properties); + } + + [Test] + [TestCase("")] + [TestCase(" ")] + [TestCase("some string")] + public void Convert_Always_WriteLocalUserDataDirectory(string infix) + { + // Setup + string settingsDirectory = SettingsHelper.Instance.GetApplicationLocalUserSettingsDirectory(infix); + + var mocks = new MockRepository(); + var textWriter = mocks.StrictMock(); + textWriter.Expect(w => w.Write(settingsDirectory)); + mocks.ReplayAll(); + + var converter = new RiskeerUserDataFolderConverter + { + Option = infix + }; + + // Call + converter.Format(textWriter, null); + + // Assert + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Attributes/DynamicPropertyOrderAttributeTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Attributes/DynamicPropertyOrderAttributeTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Attributes/DynamicPropertyOrderAttributeTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,172 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Gui.Attributes; +using Core.Gui.Test.Attributes.TestCaseClasses; +using NUnit.Framework; + +namespace Core.Gui.Test.Attributes +{ + [TestFixture] + public class DynamicPropertyOrderAttributeTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var attribute = new DynamicPropertyOrderAttribute(); + + // Assert + Assert.IsInstanceOf(attribute); + } + + [Test] + [TestCase("")] + [TestCase(null)] + public void PropertyOrder_NoPropertyName_ReturnZero(string propertyName) + { + // Call + int propertyOrder = DynamicPropertyOrderAttribute.PropertyOrder(new object(), propertyName); + + // Assert + Assert.AreEqual(0.0, propertyOrder); + } + + [Test] + public void PropertyOrder_GivenPropertyNameDoesNotExistOnObject_ThrowMissingMemberException() + { + // Setup + var o = new object(); + + // Call + TestDelegate call = () => DynamicPropertyOrderAttribute.PropertyOrder(o, "NotExistingProperty"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + Assert.AreEqual($"Kon eigenschap NotExistingProperty van type {o.GetType()} niet vinden.", exceptionMessage); + } + + [Test] + public void PropertyOrder_GivenPropertyDoesNotHaveDynamicPropertyOrderAttribute_ReturnZero() + { + // Setup + var o = new ClassWithPropertyWithoutDynamicPropertyOrderAttribute(); + + // Call + int propertyOrder = DynamicPropertyOrderAttribute.PropertyOrder(o, "Property"); + + // Assert + Assert.AreEqual(0, propertyOrder); + } + + [Test] + public void PropertyOrder_ClassLacksDynamicPropertyOrderValidationMethod_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicPropertyOrderPropertyButNoEvaluationMethod(); + + // Call + TestDelegate call = () => DynamicPropertyOrderAttribute.PropertyOrder(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicPropertyOrderEvaluationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void PropertyOrder_ClassHasMultipleDynamicPropertyOrderEvaluationMethods_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicPropertyOrderPropertyAndMultipleEvaluationMethods(); + + // Call + TestDelegate call = () => DynamicPropertyOrderAttribute.PropertyOrder(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Slechts één DynamicPropertyOrderEvaluationMethod toegestaan per klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void PropertyOrder_ClassHasDynamicPropertyOrderEvaluationMethodWithNonIntReturnType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicPropertyOrderPropertyButEvaluationMethodReturnsIncorrectValueType(); + + // Call + TestDelegate call = () => DynamicPropertyOrderAttribute.PropertyOrder(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicPropertyOrderEvaluationMethod moet 'int' als 'return type' hebben. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void PropertyOrder_ClassHasDynamicPropertyOrderEvaluationMethodWithIncorrectArgumentCount_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicPropertyOrderPropertyButEvaluationMethodNotOneArgument(); + + // Call + TestDelegate call = () => DynamicPropertyOrderAttribute.PropertyOrder(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicPropertyOrderEvaluationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void PropertyOrder_ClassHasDynamicPropertyOrderEvaluationMethodWithIncorrectArgumentType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicPropertyOrderPropertyButEvaluationMethodArgumentNotString(); + + // Call + TestDelegate call = () => DynamicPropertyOrderAttribute.PropertyOrder(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Argument van DynamicPropertyOrderEvaluationMethod moet van het type 'string' zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + [TestCase(1)] + [TestCase(2)] + [TestCase(10)] + public void PropertyOrder_ClassWithDynamicPropertyOrderProperty_ReturnResultFromEvaluationMethod(int propertyOrder) + { + // Setup + var o = new ClassWithDynamicPropertyOrderProperty(propertyOrder); + + // Call + int result = DynamicPropertyOrderAttribute.PropertyOrder(o, "Property"); + + // Assert + Assert.AreEqual(propertyOrder, result); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Attributes/DynamicPropertyOrderEvaluationMethodAttributeTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Attributes/DynamicPropertyOrderEvaluationMethodAttributeTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Attributes/DynamicPropertyOrderEvaluationMethodAttributeTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,123 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Gui.Attributes; +using Core.Gui.Test.Attributes.TestCaseClasses; +using NUnit.Framework; + +namespace Core.Gui.Test.Attributes +{ + [TestFixture] + public class DynamicPropertyOrderEvaluationMethodAttributeTest + { + [Test] + public void CreatePropertyOrderMethod_ClassLacksDynamicPropertyOrderEvaluationMethod_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicPropertyOrderPropertyButNoEvaluationMethod(); + + // Call + TestDelegate call = () => DynamicPropertyOrderEvaluationMethodAttribute.CreatePropertyOrderMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicPropertyOrderEvaluationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreatePropertyOrderMethod_ClassHasMultipleDynamicPropertyOrderEvaluationMethods_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicPropertyOrderPropertyAndMultipleEvaluationMethods(); + + // Call + TestDelegate call = () => DynamicPropertyOrderEvaluationMethodAttribute.CreatePropertyOrderMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Slechts één DynamicPropertyOrderEvaluationMethod toegestaan per klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreatePropertyOrderMethod_ClassHasDynamicPropertyOrderEvaluationMethodWithNonIntReturnType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicPropertyOrderPropertyButEvaluationMethodReturnsIncorrectValueType(); + + // Call + TestDelegate call = () => DynamicPropertyOrderEvaluationMethodAttribute.CreatePropertyOrderMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicPropertyOrderEvaluationMethod moet 'int' als 'return type' hebben. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreatePropertyOrderMethod_ClassHasDynamicPropertyOrderEvaluationMethodWithIncorrectArgumentCount_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicPropertyOrderPropertyButEvaluationMethodNotOneArgument(); + + // Call + TestDelegate call = () => DynamicPropertyOrderEvaluationMethodAttribute.CreatePropertyOrderMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicPropertyOrderEvaluationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreatePropertyOrderMethod_ClassHasDynamicPropertyOrderEvaluationMethodWithIncorrectArgumentType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicPropertyOrderPropertyButEvaluationMethodArgumentNotString(); + + // Call + TestDelegate call = () => DynamicPropertyOrderEvaluationMethodAttribute.CreatePropertyOrderMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Argument van DynamicPropertyOrderEvaluationMethod moet van het type 'string' zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + [TestCase(1)] + [TestCase(2)] + [TestCase(10)] + public void CreatePropertyOrderMethod_ClassWithDynamicPropertyOrderProperty_ReturnResultFromEvaluationMethod(int propertyOrder) + { + // Setup + var o = new ClassWithDynamicPropertyOrderProperty(propertyOrder); + + // Call + DynamicPropertyOrderEvaluationMethodAttribute.PropertyOrder result = DynamicPropertyOrderEvaluationMethodAttribute.CreatePropertyOrderMethod(o); + + // Assert + Assert.AreEqual(propertyOrder, result("Property")); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Attributes/DynamicReadOnlyAttributeTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Attributes/DynamicReadOnlyAttributeTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Attributes/DynamicReadOnlyAttributeTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,171 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Gui.Attributes; +using Core.Gui.Test.Attributes.TestCaseClasses; +using NUnit.Framework; + +namespace Core.Gui.Test.Attributes +{ + [TestFixture] + public class DynamicReadOnlyAttributeTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var attribute = new DynamicReadOnlyAttribute(); + + // Assert + Assert.IsInstanceOf(attribute); + } + + [Test] + [TestCase("")] + [TestCase(null)] + public void IsReadOnly_NoPropertyName_ReturnFalse(string propertyName) + { + // Call + bool isReadOnly = DynamicReadOnlyAttribute.IsReadOnly(new object(), propertyName); + + // Assert + Assert.IsFalse(isReadOnly); + } + + [Test] + public void IsReadOnly_GivenPropertyNameDoesNotExistOnObject_ThrowMissingMemberException() + { + // Setup + var o = new object(); + + // Call + TestDelegate call = () => DynamicReadOnlyAttribute.IsReadOnly(o, "NotExistingProperty"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + Assert.AreEqual($"Kon eigenschap NotExistingProperty van type {o.GetType()} niet vinden.", exceptionMessage); + } + + [Test] + public void IsReadOnly_GivenPropertyDoesNotHaveDynamicReadOnlyAttribute_ReturnFalse() + { + // Setup + var o = new ClassWithPropertyWithoutDynamicReadOnlyAttribute(); + + // Call + bool isReadOnly = DynamicReadOnlyAttribute.IsReadOnly(o, "Property"); + + // Assert + Assert.IsFalse(isReadOnly); + } + + [Test] + public void IsReadOnly_ClassLacksDynamicReadOnlyValidationMethod_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicReadOnlyPropertyButNoValidationMethod(); + + // Call + TestDelegate call = () => DynamicReadOnlyAttribute.IsReadOnly(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicReadOnlyValidationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void IsReadOnly_ClassHasMultipleDynamicReadOnlyValidationMethods_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicReadOnlyPropertyAndMultipleValidationMethods(); + + // Call + TestDelegate call = () => DynamicReadOnlyAttribute.IsReadOnly(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Slechts één DynamicReadOnlyValidationMethod toegestaan per klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void IsReadOnly_ClassHasDynamicReadOnlyValidationMethodWithNonBoolReturnType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicReadOnlyPropertyButValidationMethodReturnsIncorrectValueType(); + + // Call + TestDelegate call = () => DynamicReadOnlyAttribute.IsReadOnly(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicReadOnlyValidationMethod moet 'bool' als 'return type' hebben. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void IsReadOnly_ClassHasDynamicReadOnlyValidationMethodWithIncorrectArgumentCount_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicReadOnlyPropertyButValidationMethodNotOneArgument(); + + // Call + TestDelegate call = () => DynamicReadOnlyAttribute.IsReadOnly(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicReadOnlyValidationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void IsReadOnly_ClassHasDynamicReadOnlyValidationMethodWithIncorrectArgumentType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicReadOnlyPropertyButValidationMethodArgumentNotString(); + + // Call + TestDelegate call = () => DynamicReadOnlyAttribute.IsReadOnly(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Argument van DynamicReadOnlyValidationMethod moet van het type 'string' zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + [TestCase(false)] + [TestCase(true)] + public void IsReadOnly_ClassWithDynamicReadOnlyProperty_ReturnResultFromValidationMethod(bool isReadOnly) + { + // Setup + var o = new ClassWithDynamicReadOnlyProperty(isReadOnly); + + // Call + bool result = DynamicReadOnlyAttribute.IsReadOnly(o, "Property"); + + // Assert + Assert.AreEqual(isReadOnly, result); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Attributes/DynamicReadOnlyValidationMethodAttributeTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Attributes/DynamicReadOnlyValidationMethodAttributeTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Attributes/DynamicReadOnlyValidationMethodAttributeTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,122 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Gui.Attributes; +using Core.Gui.Test.Attributes.TestCaseClasses; +using NUnit.Framework; + +namespace Core.Gui.Test.Attributes +{ + [TestFixture] + public class DynamicReadOnlyValidationMethodAttributeTest + { + [Test] + public void CreateIsReadOnlyMethod_ClassLacksDynamicReadOnlyValidationMethod_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicReadOnlyPropertyButNoValidationMethod(); + + // Call + TestDelegate call = () => DynamicReadOnlyValidationMethodAttribute.CreateIsReadOnlyMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicReadOnlyValidationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreateIsReadOnlyMethod_ClassHasMultipleDynamicReadOnlyValidationMethods_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicReadOnlyPropertyAndMultipleValidationMethods(); + + // Call + TestDelegate call = () => DynamicReadOnlyValidationMethodAttribute.CreateIsReadOnlyMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Slechts één DynamicReadOnlyValidationMethod toegestaan per klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreateIsReadOnlyMethod_ClassHasDynamicReadOnlyValidationMethodWithNonBoolReturnType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicReadOnlyPropertyButValidationMethodReturnsIncorrectValueType(); + + // Call + TestDelegate call = () => DynamicReadOnlyValidationMethodAttribute.CreateIsReadOnlyMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicReadOnlyValidationMethod moet 'bool' als 'return type' hebben. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreateIsReadOnlyMethod_ClassHasDynamicReadOnlyValidationMethodWithIncorrectArgumentCount_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicReadOnlyPropertyButValidationMethodNotOneArgument(); + + // Call + TestDelegate call = () => DynamicReadOnlyValidationMethodAttribute.CreateIsReadOnlyMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicReadOnlyValidationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreateIsReadOnlyMethod_ClassHasDynamicReadOnlyValidationMethodWithIncorrectArgumentType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicReadOnlyPropertyButValidationMethodArgumentNotString(); + + // Call + TestDelegate call = () => DynamicReadOnlyValidationMethodAttribute.CreateIsReadOnlyMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Argument van DynamicReadOnlyValidationMethod moet van het type 'string' zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + [TestCase(false)] + [TestCase(true)] + public void CreateIsReadOnlyMethod_ClassWithDynamicReadOnlyProperty_ReturnResultFromValidationMethod(bool isReadOnly) + { + // Setup + var o = new ClassWithDynamicReadOnlyProperty(isReadOnly); + + // Call + DynamicReadOnlyValidationMethodAttribute.IsPropertyReadOnly result = DynamicReadOnlyValidationMethodAttribute.CreateIsReadOnlyMethod(o); + + // Assert + Assert.AreEqual(isReadOnly, result("Property")); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Attributes/DynamicVisibleAttributeTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Attributes/DynamicVisibleAttributeTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Attributes/DynamicVisibleAttributeTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,171 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Gui.Attributes; +using Core.Gui.Test.Attributes.TestCaseClasses; +using NUnit.Framework; + +namespace Core.Gui.Test.Attributes +{ + [TestFixture] + public class DynamicVisibleAttributeTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var attribute = new DynamicVisibleAttribute(); + + // Assert + Assert.IsInstanceOf(attribute); + } + + [Test] + [TestCase("")] + [TestCase(null)] + public void IsVisible_NoPropertyName_ReturnTrue(string propertyName) + { + // Call + bool isVisible = DynamicVisibleAttribute.IsVisible(new object(), propertyName); + + // Assert + Assert.IsTrue(isVisible); + } + + [Test] + public void IsVisible_GivenPropertyNameDoesNotExistOnObject_ThrowMissingMemberException() + { + // Setup + var o = new object(); + + // Call + TestDelegate call = () => DynamicVisibleAttribute.IsVisible(o, "NotExistingProperty"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + Assert.AreEqual($"Kon eigenschap NotExistingProperty van type {o.GetType()} niet vinden.", exceptionMessage); + } + + [Test] + public void IsVisible_GivenPropertyDoesNotHaveDynamicVisibleAttribute_ReturnTrue() + { + // Setup + var o = new ClassWithPropertyWithoutDynamicVisibleAttribute(); + + // Call + bool isVisible = DynamicVisibleAttribute.IsVisible(o, "Property"); + + // Assert + Assert.IsTrue(isVisible); + } + + [Test] + public void IsVisible_ClassLacksDynamicVisibleValidationMethod_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicVisiblePropertyButNoValidationMethod(); + + // Call + TestDelegate call = () => DynamicVisibleAttribute.IsVisible(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicVisibleValidationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void IsVisible_ClassHasMultipleDynamicVisibleValidationMethods_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicVisiblePropertyAndMultipleValidationMethods(); + + // Call + TestDelegate call = () => DynamicVisibleAttribute.IsVisible(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Slechts één DynamicVisibleValidationMethod toegestaan per klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void IsVisible_ClassHasDynamicVisibleValidationMethodWithNonBoolReturnType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicVisiblePropertyButValidationMethodReturnsIncorrectValueType(); + + // Call + TestDelegate call = () => DynamicVisibleAttribute.IsVisible(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicVisibleValidationMethod moet 'bool' als 'return type' hebben. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void IsVisible_ClassHasDynamicVisibleValidationMethodWithIncorrectArgumentCount_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicVisiblePropertyButValidationMethodNotOneArgument(); + + // Call + TestDelegate call = () => DynamicVisibleAttribute.IsVisible(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicVisibleValidationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void IsVisible_ClassHasDynamicVisibleValidationMethodWithIncorrectArgumentType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicVisiblePropertyButValidationMethodArgumentNotString(); + + // Call + TestDelegate call = () => DynamicVisibleAttribute.IsVisible(o, "Property"); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Argument van DynamicVisibleValidationMethod moet van het type 'string' zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + [TestCase(false)] + [TestCase(true)] + public void IsVisible_ClassWithDynamicVisibleProperty_ReturnResultFromValidationMethod(bool isVisible) + { + // Setup + var o = new ClassWithDynamicVisibleProperty(isVisible); + + // Call + bool result = DynamicVisibleAttribute.IsVisible(o, "Property"); + + // Assert + Assert.AreEqual(isVisible, result); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Attributes/DynamicVisibleValidationMethodAttributeTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Attributes/DynamicVisibleValidationMethodAttributeTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Attributes/DynamicVisibleValidationMethodAttributeTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,122 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Gui.Attributes; +using Core.Gui.Test.Attributes.TestCaseClasses; +using NUnit.Framework; + +namespace Core.Gui.Test.Attributes +{ + [TestFixture] + public class DynamicVisibleValidationMethodAttributeTest + { + [Test] + public void CreateIsVisibleMethod_ClassLacksDynamicVisibleValidationMethod_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicVisiblePropertyButNoValidationMethod(); + + // Call + TestDelegate call = () => DynamicVisibleValidationMethodAttribute.CreateIsVisibleMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicVisibleValidationMethod niet gevonden (of geen 'public' toegankelijkheid). Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreateIsVisibleMethod_ClassHasMultipleDynamicVisibleValidationMethods_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicVisiblePropertyAndMultipleValidationMethods(); + + // Call + TestDelegate call = () => DynamicVisibleValidationMethodAttribute.CreateIsVisibleMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Slechts één DynamicVisibleValidationMethod toegestaan per klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreateIsVisibleMethod_ClassHasDynamicVisibleValidationMethodWithNonBoolReturnType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicVisiblePropertyButValidationMethodReturnsIncorrectValueType(); + + // Call + TestDelegate call = () => DynamicVisibleValidationMethodAttribute.CreateIsVisibleMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicVisibleValidationMethod moet 'bool' als 'return type' hebben. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreateIsVisibleMethod_ClassHasDynamicVisibleValidationMethodWithIncorrectArgumentCount_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicVisiblePropertyButValidationMethodNotOneArgument(); + + // Call + TestDelegate call = () => DynamicVisibleValidationMethodAttribute.CreateIsVisibleMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"DynamicVisibleValidationMethod heeft een incorrect aantal argumenten. Zou er één moeten zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + public void CreateIsVisibleMethod_ClassHasDynamicVisibleValidationMethodWithIncorrectArgumentType_ThrowsMissingMethodException() + { + // Setup + var o = new InvalidClassWithDynamicVisiblePropertyButValidationMethodArgumentNotString(); + + // Call + TestDelegate call = () => DynamicVisibleValidationMethodAttribute.CreateIsVisibleMethod(o); + + // Assert + string exceptionMessage = Assert.Throws(call).Message; + string expectedMessage = $"Argument van DynamicVisibleValidationMethod moet van het type 'string' zijn. Klasse: {o.GetType()}."; + Assert.AreEqual(expectedMessage, exceptionMessage); + } + + [Test] + [TestCase(false)] + [TestCase(true)] + public void CreateIsVisibleMethod_ClassWithDynamicVisibleProperty_ReturnResultFromValidationMethod(bool isVisible) + { + // Setup + var o = new ClassWithDynamicVisibleProperty(isVisible); + + // Call + DynamicVisibleValidationMethodAttribute.IsPropertyVisible result = DynamicVisibleValidationMethodAttribute.CreateIsVisibleMethod(o); + + // Assert + Assert.AreEqual(isVisible, result("Property")); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Attributes/PropertyOrderAttributeTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Attributes/PropertyOrderAttributeTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Attributes/PropertyOrderAttributeTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,45 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Gui.Attributes; +using NUnit.Framework; + +namespace Core.Gui.Test.Attributes +{ + [TestFixture] + public class PropertyOrderAttributeTest + { + [Test] + public void ParameteredConstructor_ExpectedValues() + { + // Setup + int order = new Random(21).Next(int.MinValue, int.MaxValue); + + // Call + var attribute = new PropertyOrderAttribute(order); + + // Assert + Assert.IsInstanceOf(attribute); + Assert.AreEqual(order, attribute.Order); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Attributes/TestCaseClasses/DynamicPropertyOrderTestCases.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Attributes/TestCaseClasses/DynamicPropertyOrderTestCases.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Attributes/TestCaseClasses/DynamicPropertyOrderTestCases.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,109 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using Core.Gui.Attributes; + +namespace Core.Gui.Test.Attributes.TestCaseClasses +{ + internal class ClassWithPropertyWithoutDynamicPropertyOrderAttribute + { + public double Property { get; set; } + } + + internal class InvalidClassWithDynamicPropertyOrderPropertyButNoEvaluationMethod + { + [DynamicPropertyOrder] + public double Property { get; set; } + } + + internal class InvalidClassWithDynamicPropertyOrderPropertyAndMultipleEvaluationMethods + { + [DynamicPropertyOrder] + public double Property { get; set; } + + [DynamicPropertyOrderEvaluationMethod] + public int DynamicPropertyOrder1(string propertyName) + { + return 1; + } + + [DynamicPropertyOrderEvaluationMethod] + public int DynamicPropertyOrder2(string propertyName) + { + return 2; + } + } + + internal class InvalidClassWithDynamicPropertyOrderPropertyButEvaluationMethodReturnsIncorrectValueType + { + [DynamicPropertyOrder] + public double Property { get; set; } + + [DynamicPropertyOrderEvaluationMethod] + public double DynamicPropertyOrder(string propertyName) + { + return 0.1; + } + } + + internal class InvalidClassWithDynamicPropertyOrderPropertyButEvaluationMethodNotOneArgument + { + [DynamicPropertyOrder] + public double Property { get; set; } + + [DynamicPropertyOrderEvaluationMethod] + public int DynamicPropertyOrder(object o, string propertyName) + { + return 1; + } + } + + internal class InvalidClassWithDynamicPropertyOrderPropertyButEvaluationMethodArgumentNotString + { + [DynamicPropertyOrder] + public double Property { get; set; } + + [DynamicPropertyOrderEvaluationMethod] + public int DynamicPropertyOrder(object o) + { + return 1; + } + } + + internal class ClassWithDynamicPropertyOrderProperty + { + private readonly int order; + + public ClassWithDynamicPropertyOrderProperty(int order) + { + this.order = order; + } + + [DynamicPropertyOrder] + public double Property { get; set; } + + [DynamicPropertyOrderEvaluationMethod] + public int DynamicPropertyOrder(string propertyName) + { + return order; + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Attributes/TestCaseClasses/DynamicReadOnlyTestCases.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Attributes/TestCaseClasses/DynamicReadOnlyTestCases.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Attributes/TestCaseClasses/DynamicReadOnlyTestCases.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,109 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using Core.Gui.Attributes; + +namespace Core.Gui.Test.Attributes.TestCaseClasses +{ + internal class ClassWithPropertyWithoutDynamicReadOnlyAttribute + { + public double Property { get; set; } + } + + internal class InvalidClassWithDynamicReadOnlyPropertyButNoValidationMethod + { + [DynamicReadOnly] + public double Property { get; set; } + } + + internal class InvalidClassWithDynamicReadOnlyPropertyAndMultipleValidationMethods + { + [DynamicReadOnly] + public double Property { get; set; } + + [DynamicReadOnlyValidationMethod] + public bool IsDynamicReadOnly1(string propertyName) + { + return true; + } + + [DynamicReadOnlyValidationMethod] + public bool IsDynamicReadOnly2(string propertyName) + { + return false; + } + } + + internal class InvalidClassWithDynamicReadOnlyPropertyButValidationMethodReturnsIncorrectValueType + { + [DynamicReadOnly] + public double Property { get; set; } + + [DynamicReadOnlyValidationMethod] + public int IsDynamicReadOnly(string propertyName) + { + return 0; + } + } + + internal class InvalidClassWithDynamicReadOnlyPropertyButValidationMethodNotOneArgument + { + [DynamicReadOnly] + public double Property { get; set; } + + [DynamicReadOnlyValidationMethod] + public bool IsDynamicReadOnly(object o, string propertyName) + { + return true; + } + } + + internal class InvalidClassWithDynamicReadOnlyPropertyButValidationMethodArgumentNotString + { + [DynamicReadOnly] + public double Property { get; set; } + + [DynamicReadOnlyValidationMethod] + public bool IsDynamicReadOnly(object o) + { + return true; + } + } + + internal class ClassWithDynamicReadOnlyProperty + { + private readonly bool isReadOnly; + + public ClassWithDynamicReadOnlyProperty(bool isReadOnly) + { + this.isReadOnly = isReadOnly; + } + + [DynamicReadOnly] + public double Property { get; set; } + + [DynamicReadOnlyValidationMethod] + public bool IsDynamicReadOnly(string propertyName) + { + return isReadOnly; + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Attributes/TestCaseClasses/DynamicVisibilityTestCases.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Attributes/TestCaseClasses/DynamicVisibilityTestCases.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Attributes/TestCaseClasses/DynamicVisibilityTestCases.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,109 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using Core.Gui.Attributes; + +namespace Core.Gui.Test.Attributes.TestCaseClasses +{ + internal class ClassWithPropertyWithoutDynamicVisibleAttribute + { + public double Property { get; set; } + } + + internal class InvalidClassWithDynamicVisiblePropertyButNoValidationMethod + { + [DynamicVisible] + public double Property { get; set; } + } + + internal class InvalidClassWithDynamicVisiblePropertyAndMultipleValidationMethods + { + [DynamicVisible] + public double Property { get; set; } + + [DynamicVisibleValidationMethod] + public bool IsDynamicVisible1(string propertyName) + { + return true; + } + + [DynamicVisibleValidationMethod] + public bool IsDynamicVisible2(string propertyName) + { + return false; + } + } + + internal class InvalidClassWithDynamicVisiblePropertyButValidationMethodReturnsIncorrectValueType + { + [DynamicVisible] + public double Property { get; set; } + + [DynamicVisibleValidationMethod] + public int IsDynamicVisible(string propertyName) + { + return 0; + } + } + + internal class InvalidClassWithDynamicVisiblePropertyButValidationMethodNotOneArgument + { + [DynamicVisible] + public double Property { get; set; } + + [DynamicVisibleValidationMethod] + public bool IsDynamicVisible(object o, string propertyName) + { + return true; + } + } + + internal class InvalidClassWithDynamicVisiblePropertyButValidationMethodArgumentNotString + { + [DynamicVisible] + public double Property { get; set; } + + [DynamicVisibleValidationMethod] + public bool IsDynamicVisible(object o) + { + return true; + } + } + + internal class ClassWithDynamicVisibleProperty + { + private readonly bool isVisible; + + public ClassWithDynamicVisibleProperty(bool isVisible) + { + this.isVisible = isVisible; + } + + [DynamicVisible] + public double Property { get; set; } + + [DynamicVisibleValidationMethod] + public bool IsDynamicVisible(string propertyName) + { + return isVisible; + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Clipboard/ClipboardProviderTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Clipboard/ClipboardProviderTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Clipboard/ClipboardProviderTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,36 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using Core.Gui.Clipboard; +using NUnit.Framework; + +namespace Core.Gui.Test.Clipboard +{ + [TestFixture] + public class ClipboardProviderTest + { + [Test] + public void Clipboard_InitializedCorrectly() + { + Assert.IsInstanceOf(ClipboardProvider.Clipboard); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Commands/ApplicationFeatureCommandHandlerTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Commands/ApplicationFeatureCommandHandlerTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Commands/ApplicationFeatureCommandHandlerTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,99 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using Core.Gui.Commands; +using Core.Gui.Forms.MainWindow; +using Core.Gui.Forms.PropertyGridView; +using Core.Gui.PropertyBag; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Commands +{ + [TestFixture] + public class ApplicationFeatureCommandHandlerTest + { + [Test] + public void ShowPropertiesFor_InitializeAndShowPropertyGrid() + { + // Setup + var mocks = new MockRepository(); + var propertyResolver = mocks.Stub(); + var mainWindow = mocks.Stub(); + mainWindow.Expect(w => w.InitPropertiesWindowOrBringToFront()); + mocks.ReplayAll(); + + var commandHandler = new ApplicationFeatureCommandHandler(propertyResolver, mainWindow); + + // Call + commandHandler.ShowPropertiesForSelection(); + + // Assert + mocks.VerifyAll(); + } + + [Test] + public void CanShowPropertiesFor_ObjectHasProperties_ReturnTrue() + { + // Setup + var target = new object(); + + var mocks = new MockRepository(); + var propertyResolver = mocks.Stub(); + propertyResolver.Expect(r => r.GetObjectProperties(target)) + .Return(mocks.Stub()); + var mainWindow = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new ApplicationFeatureCommandHandler(propertyResolver, mainWindow); + + // Call + bool result = commandHandler.CanShowPropertiesFor(target); + + // Assert + Assert.IsTrue(result); + mocks.VerifyAll(); + } + + [Test] + public void CanShowPropertiesFor_ObjectDoesNotHaveProperties_ReturnFalse() + { + // Setup + var target = new object(); + + var mocks = new MockRepository(); + var propertyResolver = mocks.Stub(); + propertyResolver.Expect(r => r.GetObjectProperties(target)) + .Return(null); + var mainWindow = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new ApplicationFeatureCommandHandler(propertyResolver, mainWindow); + + // Call + bool result = commandHandler.CanShowPropertiesFor(target); + + // Assert + Assert.IsFalse(result); + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Commands/GuiExportHandlerTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Commands/GuiExportHandlerTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Commands/GuiExportHandlerTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,428 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Threading; +using System.Windows.Forms; +using Core.Common.Base.IO; +using Core.Common.TestUtil; +using Core.Common.Util.Reflection; +using Core.Gui.Commands; +using Core.Gui.Forms.MainWindow; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Commands +{ + [TestFixture] + public class GuiExportHandlerTest : NUnitFormTest + { + [Test] + [TestCase(1234)] + [TestCase(null)] + public void ExportFrom_NoExporterAvailable_GivesMessageBoxAndLogsMessage(object source) + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + mockRepository.ReplayAll(); + + string messageBoxText = null; + string messageBoxTitle = null; + + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + + messageBoxText = messageBox.Text; + messageBoxTitle = messageBox.Title; + + messageBox.ClickOk(); + }; + + var exportHandler = new GuiExportHandler(mainWindow, new List()); + + // Call + Action call = () => exportHandler.ExportFrom(source); + + // Assert + string sourceTypeName = source == null ? "null" : source.GetType().FullName; + TestHelper.AssertLogMessageIsGenerated(call, $"Riskeer kan de huidige selectie ({sourceTypeName}) niet exporteren."); + Assert.AreEqual("Fout", messageBoxTitle); + Assert.AreEqual("Riskeer kan de huidige selectie niet exporteren.", messageBoxText); + mockRepository.VerifyAll(); + } + + [Test] + [TestCase(1234)] + [TestCase(null)] + public void ExportFrom_NoSupportedExporterAvailable_GivesMessageBoxAndLogsMessage(object source) + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + mockRepository.ReplayAll(); + + string messageBoxText = null; + string messageBoxTitle = null; + + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + + messageBoxText = messageBox.Text; + messageBoxTitle = messageBox.Title; + + messageBox.ClickOk(); + }; + + var exportHandler = new GuiExportHandler(mainWindow, new List + { + new ExportInfo() + }); + + // Call + Action call = () => exportHandler.ExportFrom(source); + + // Assert + string sourceTypeName = source == null ? "null" : source.GetType().FullName; + TestHelper.AssertLogMessageIsGenerated(call, $"Riskeer kan de huidige selectie ({sourceTypeName}) niet exporteren."); + Assert.AreEqual("Fout", messageBoxTitle); + Assert.AreEqual("Riskeer kan de huidige selectie niet exporteren.", messageBoxText); + mockRepository.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void ExportFrom_SupportedExporterAvailableNoFilePathGiven_AbortsExport() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + var exporter = mockRepository.StrictMock(); + mockRepository.ReplayAll(); + + var exportHandler = new GuiExportHandler(mainWindow, new List + { + new ExportInfo + { + CreateFileExporter = (o, s) => exporter, + GetExportPath = () => null + } + }); + + // Call + exportHandler.ExportFrom(1234); + + // Assert + mockRepository.VerifyAll(); // Expect no calls on exporter mock + } + + [Test] + [Apartment(ApartmentState.STA)] + public void ExportFrom_SupportedExporterAvailableAndFilePathGivenAndExporterRunsSuccessful_CallsExportAndLogsMessages() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + var exporter = mockRepository.StrictMock(); + exporter.Stub(e => e.Export()).Return(true); + mockRepository.ReplayAll(); + + const int expectedData = 1234; + string targetExportFileName = Path.GetFullPath("exportFile.txt"); + + const string exportInfoName = "Random data"; + var exportHandler = new GuiExportHandler(mainWindow, new List + { + new ExportInfo + { + Name = exportInfoName, + CreateFileExporter = (data, filePath) => + { + Assert.AreEqual(expectedData, data); + Assert.AreEqual(targetExportFileName, filePath); + return exporter; + }, + GetExportPath = () => targetExportFileName + } + }); + + // Call + Action call = () => exportHandler.ExportFrom(expectedData); + + // Assert + TestHelper.AssertLogMessagesAreGenerated(call, new[] + { + $"Exporteren van '{exportInfoName}' is gestart.", + $"Gegevens zijn geëxporteerd naar bestand '{targetExportFileName}'.", + $"Exporteren van '{exportInfoName}' is gelukt." + }); + mockRepository.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void ExportFrom_SupportedExporterAvailableAndFilePathGivenAndExporterFails_CallsExportAndLogsMessages() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + var exporter = mockRepository.StrictMock(); + exporter.Stub(e => e.Export()).Return(false); + mockRepository.ReplayAll(); + + string targetExportFileName = Path.GetFullPath("exportFile.txt"); + + const string exportInfoName = "Random data"; + var exportHandler = new GuiExportHandler(mainWindow, new List + { + new ExportInfo + { + Name = exportInfoName, + CreateFileExporter = (data, filePath) => exporter, + GetExportPath = () => targetExportFileName + } + }); + + // Call + Action call = () => exportHandler.ExportFrom(1234); + + // Assert + TestHelper.AssertLogMessagesAreGenerated(call, new[] + { + $"Exporteren van '{exportInfoName}' is gestart.", + $"Exporteren van '{exportInfoName}' is mislukt." + }); + mockRepository.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void ExportFrom_MultipleSupportedExportersAvailableWithDefaultSelectionDialogStyling_GivesExpectedSelectionDialog() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + mockRepository.ReplayAll(); + + var dialogText = ""; + TestListViewItem[] listViewItems = null; + + ModalFormHandler = (name, wnd, form) => + { + var dialog = new FormTester(name); + var imageList = TypeUtils.GetField(dialog.TheObject, "imageList"); + var listView = (ListView) new ControlTester("listViewItemTypes").TheObject; + + dialogText = dialog.Text; + listViewItems = listView.Items + .OfType() + .Select(lvi => new TestListViewItem(lvi.Name, lvi.Group.Name, imageList.Images[lvi.ImageIndex])) + .ToArray(); + + dialog.Close(); + }; + + var exportHandler = new GuiExportHandler(mainWindow, new List + { + new ExportInfo(), + new ExportInfo() + }); + + // Call + exportHandler.ExportFrom(1234); + + // Assert + Assert.AreEqual("Kies wat u wilt exporteren", dialogText); + + Assert.AreEqual(2, listViewItems.Length); + Assert.AreEqual("", listViewItems[0].Name); + Assert.AreEqual("Algemeen", listViewItems[0].Group); + Assert.AreEqual("", listViewItems[1].Name); + Assert.AreEqual("Algemeen", listViewItems[1].Group); + + mockRepository.VerifyAll(); + } + + [Test] + public void CanExportFrom_HasNoFileExportersForTarget_ReturnFalse() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiExportHandler(dialogParent, new List + { + new ExportInfo(), // Wrong object type + new ExportInfo // Disabled + { + IsEnabled = o => false + } + }); + + // Call + bool isExportPossible = commandHandler.CanExportFrom(new object()); + + // Assert + Assert.IsFalse(isExportPossible); + mocks.VerifyAll(); + } + + [Test] + public void CanExportFrom_HasOneFileExporterForTarget_ReturnTrue() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiExportHandler(dialogParent, new List + { + new ExportInfo() + }); + + // Call + bool isExportPossible = commandHandler.CanExportFrom(new object()); + + // Assert + Assert.IsTrue(isExportPossible); + mocks.VerifyAll(); + } + + [Test] + public void CanExportFrom_HasMultipleFileExportersForTarget_ReturnTrue() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiExportHandler(dialogParent, new List + { + new ExportInfo(), + new ExportInfo() + }); + + // Call + bool isExportPossible = commandHandler.CanExportFrom(new object()); + + // Assert + Assert.IsTrue(isExportPossible); + mocks.VerifyAll(); + } + + [TestCase(true)] + [TestCase(false)] + [Apartment(ApartmentState.STA)] + public void ExportFrom_MultipleSupportedExportersAvailableWithCustomSelectionDialogStyling_GivesExpectedSelectionDialog(bool hasFileExtension) + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + mockRepository.ReplayAll(); + + var dialogText = ""; + TestListViewItem[] listViewItems = null; + + ModalFormHandler = (name, wnd, form) => + { + var dialog = new FormTester(name); + var imageList = TypeUtils.GetField(dialog.TheObject, "imageList"); + var listView = (ListView) new ControlTester("listViewItemTypes").TheObject; + + dialogText = dialog.Text; + listViewItems = listView.Items + .OfType() + .Select(lvi => new TestListViewItem(lvi.Name, lvi.Group.Name, imageList.Images[lvi.ImageIndex])) + .ToArray(); + + dialog.Close(); + }; + + var exportInfo1 = new ExportInfo + { + Name = "Name 1", + Category = "Category 1", + Image = Resources.Busy_indicator, + Extension = hasFileExtension ? "extension 1" : null + }; + + var exportInfo2 = new ExportInfo + { + Name = "Name 2", + Category = "Category 2", + Image = Resources.DeleteIcon, + Extension = hasFileExtension ? "extension 2" : null + }; + + var exportHandler = new GuiExportHandler(mainWindow, new List + { + exportInfo1, + exportInfo2 + }); + + // Call + exportHandler.ExportFrom(1234); + + // Assert + Assert.AreEqual("Kies wat u wilt exporteren", dialogText); + + Assert.AreEqual(2, listViewItems.Length); + string expectedItemName1 = hasFileExtension + ? $"{exportInfo1.Name} (*.{exportInfo1.Extension})" + : exportInfo1.Name; + Assert.AreEqual(expectedItemName1, listViewItems[0].Name); + Assert.AreEqual(exportInfo1.Category, listViewItems[0].Group); + string expectedItemName2 = hasFileExtension + ? $"{exportInfo2.Name} (*.{exportInfo2.Extension})" + : exportInfo2.Name; + Assert.AreEqual(expectedItemName2, listViewItems[1].Name); + Assert.AreEqual(exportInfo2.Category, listViewItems[1].Group); + + mockRepository.VerifyAll(); + } + + private class TestListViewItem + { + public TestListViewItem(string name, string group, Image image) + { + Name = name; + Group = group; + Image = image; + } + + public string Name { get; } + + public string Group { get; } + + public Image Image { get; } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Commands/GuiImportHandlerTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Commands/GuiImportHandlerTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Commands/GuiImportHandlerTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,522 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Base.IO; +using Core.Common.TestUtil; +using Core.Common.Util; +using Core.Gui.Commands; +using Core.Gui.Forms.MainWindow; +using Core.Gui.Helpers; +using Core.Gui.Plugin; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Commands +{ + [TestFixture] + public class GuiImportHandlerTest : NUnitFormTest + { + [Test] + public void Constructor_DialogParentNull_ThrowsArgumentNullException() + { + // Setup + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + mockRepository.ReplayAll(); + + // Call + void Call() => new GuiImportHandler(null, Enumerable.Empty(), inquiryHelper); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("dialogParent", exception.ParamName); + mockRepository.VerifyAll(); + } + + [Test] + public void Constructor_ImportInfosNull_ThrowsArgumentNullException() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + var inquiryHelper = mockRepository.Stub(); + mockRepository.ReplayAll(); + + // Call + void Call() => new GuiImportHandler(mainWindow, null, inquiryHelper); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("importInfos", exception.ParamName); + mockRepository.VerifyAll(); + } + + [Test] + public void Constructor_InquiryHelperNull_ThrowsArgumentNullException() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + mockRepository.ReplayAll(); + + // Call + void Call() => new GuiImportHandler(mainWindow, Enumerable.Empty(), null); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("inquiryHelper", exception.ParamName); + mockRepository.VerifyAll(); + } + + [Test] + public void GetSupportedImportInfos_TargetNull_ReturnsEmptyEnumeration() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiImportHandler(dialogParent, new ImportInfo[] + { + new ImportInfo() + }, inquiryHelper); + + // Call + IEnumerable supportedImportInfos = commandHandler.GetSupportedImportInfos(null); + + // Assert + CollectionAssert.IsEmpty(supportedImportInfos); + mocks.VerifyAll(); + } + + [Test] + public void GetSupportedImportInfos_NoImportInfos_ReturnsEmptyEnumeration() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiImportHandler(dialogParent, Enumerable.Empty(), inquiryHelper); + + // Call + IEnumerable supportedImportInfos = commandHandler.GetSupportedImportInfos(new object()); + + // Assert + CollectionAssert.IsEmpty(supportedImportInfos); + mocks.VerifyAll(); + } + + [Test] + public void GetSupportedImportInfos_NoImportInfosForTargetType_ReturnsEmptyEnumeration() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiImportHandler(dialogParent, new ImportInfo[] + { + new ImportInfo(), + new ImportInfo() + }, inquiryHelper); + + // Call + IEnumerable supportedImportInfos = commandHandler.GetSupportedImportInfos(new TestClassC()); + + // Assert + CollectionAssert.IsEmpty(supportedImportInfos); + mocks.VerifyAll(); + } + + [Test] + public void GetSupportedImportInfos_MultipleImportInfos_ReturnsEnumerationBasedOnTargetType() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var firstImportInfo = new ImportInfo + { + Name = "1" + }; + + var secondImportInfo = new ImportInfo + { + Name = "2" + }; + + var thirdImportInfo = new ImportInfo + { + Name = "3" + }; + + var fourthImportInfo = new ImportInfo + { + Name = "4" + }; + + var commandHandler = new GuiImportHandler(dialogParent, new ImportInfo[] + { + firstImportInfo, + secondImportInfo, + thirdImportInfo, + fourthImportInfo + }, inquiryHelper); + + // Call + IEnumerable supportedImportInfos = commandHandler.GetSupportedImportInfos(new TestClassB()); + + // Assert + var expectedImportInfos = new List + { + firstImportInfo, + secondImportInfo, + fourthImportInfo + }; + + CollectionAssert.AreEqual(expectedImportInfos, supportedImportInfos, new ImportInfoNameComparer()); + mocks.VerifyAll(); + } + + [Test] + [TestCase(true, true)] + [TestCase(true, false)] + [TestCase(false, true)] + [TestCase(false, false)] + public void GetSupportedImportInfos_MultipleImportInfosForTargetType_ReturnsEnumerationBasedOnEnabledState( + bool firstImportInfoEnabled, + bool secondImportInfoEnabled) + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var firstImportInfo = new ImportInfo + { + Name = "1", + IsEnabled = o => firstImportInfoEnabled + }; + + var secondImportInfo = new ImportInfo + { + Name = "2", + IsEnabled = o => secondImportInfoEnabled + }; + + var commandHandler = new GuiImportHandler(dialogParent, new ImportInfo[] + { + firstImportInfo, + secondImportInfo + }, inquiryHelper); + + // Call + IEnumerable supportedImportInfos = commandHandler.GetSupportedImportInfos(new object()); + + // Assert + var expectedImportInfos = new List(); + + if (firstImportInfoEnabled) + { + expectedImportInfos.Add(firstImportInfo); + } + + if (secondImportInfoEnabled) + { + expectedImportInfos.Add(secondImportInfo); + } + + CollectionAssert.AreEqual(expectedImportInfos, supportedImportInfos, new ImportInfoNameComparer()); + mocks.VerifyAll(); + } + + [Test] + public void ImportOn_NoImportInfos_GivesMessageBox() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + var inquiryHelper = mockRepository.Stub(); + mockRepository.ReplayAll(); + + string messageBoxTitle = null, messageBoxText = null; + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + + messageBoxText = messageBox.Text; + messageBoxTitle = messageBox.Title; + + messageBox.ClickOk(); + }; + + var importHandler = new GuiImportHandler(mainWindow, Enumerable.Empty(), inquiryHelper); + + // Call + importHandler.ImportOn(3, Enumerable.Empty()); + + // Assert + Assert.AreEqual("Fout", messageBoxTitle); + Assert.AreEqual("Geen enkele 'Importer' is beschikbaar voor dit element.", messageBoxText); + mockRepository.VerifyAll(); + } + + [Test] + public void ImportOn_SupportedImportInfoAndVerifyUpdatesSuccessful_ExpectedImportInfoFunctionsCalledAndActivityCreated() + { + // Setup + const string filePath = "/some/path"; + var generator = new FileFilterGenerator(); + var targetObject = new object(); + + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + inquiryHelper.Expect(ih => ih.GetSourceFileLocation(generator.Filter)).Return(filePath); + var fileImporter = mockRepository.Stub(); + mockRepository.ReplayAll(); + + const string dataDescription = "Random data"; + var isCreateFileImporterCalled = false; + var isVerifyUpdatedCalled = false; + + DialogBoxHandler = (name, wnd) => + { + // Activity closes itself + }; + + using (var form = new Form()) + { + var supportedImportInfo = new ImportInfo + { + Name = dataDescription, + CreateFileImporter = (o, s) => + { + Assert.AreSame(o, targetObject); + Assert.AreEqual(filePath, s); + isCreateFileImporterCalled = true; + return fileImporter; + }, + FileFilterGenerator = generator, + VerifyUpdates = o => + { + Assert.AreSame(o, targetObject); + isVerifyUpdatedCalled = true; + return true; + } + }; + + var importHandler = new GuiImportHandler(form, Enumerable.Empty(), inquiryHelper); + + // Call + void Call() => importHandler.ImportOn(targetObject, new ImportInfo[] + { + supportedImportInfo + }); + + // Assert + TestHelper.AssertLogMessagesAreGenerated(Call, new[] + { + $"Importeren van '{dataDescription}' is gestart.", + $"Importeren van '{dataDescription}' is mislukt." + }); + } + + // Assert + Assert.IsTrue(isCreateFileImporterCalled); + Assert.IsTrue(isVerifyUpdatedCalled); + mockRepository.VerifyAll(); + } + + [Test] + public void ImportOn_SupportedImportInfoAndVerifyUpdatesUnsuccessful_ActivityNotCreated() + { + // Setup + var generator = new FileFilterGenerator(); + var targetObject = new object(); + + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + inquiryHelper.Stub(ih => ih.GetSourceFileLocation(generator.Filter)).Return("/some/path"); + var fileImporter = mockRepository.Stub(); + mockRepository.ReplayAll(); + + var isVerifyUpdatedCalled = false; + + using (var form = new Form()) + { + var supportedImportInfo = new ImportInfo + { + CreateFileImporter = (o, s) => + { + Assert.Fail("CreateFileImporter is not expected to be called when VerifyUpdates function returns false."); + return fileImporter; + }, + FileFilterGenerator = generator, + VerifyUpdates = o => + { + Assert.AreSame(o, targetObject); + isVerifyUpdatedCalled = true; + return false; + } + }; + + var importHandler = new GuiImportHandler(form, Enumerable.Empty(), inquiryHelper); + + // Call + importHandler.ImportOn(targetObject, new ImportInfo[] + { + supportedImportInfo + }); + } + + // Assert + Assert.IsTrue(isVerifyUpdatedCalled); + mockRepository.VerifyAll(); + } + + [Test] + public void ImportOn_InquiryHelperReturnsNoPath_ImportCancelledWithLogMessage() + { + // Setup + var generator = new FileFilterGenerator(); + var targetObject = new object(); + + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + inquiryHelper.Expect(ih => ih.GetSourceFileLocation(generator.Filter)).Return(null); + var fileImporter = mockRepository.Stub(); + mockRepository.ReplayAll(); + + using (var form = new Form()) + { + var supportedImportInfo = new ImportInfo + { + CreateFileImporter = (o, s) => + { + Assert.Fail("CreateFileImporter is not expected to be called when no file path is chosen."); + return fileImporter; + }, + FileFilterGenerator = generator, + VerifyUpdates = o => true + }; + + var importHandler = new GuiImportHandler(form, Enumerable.Empty(), inquiryHelper); + + // Call + void Call() => importHandler.ImportOn(targetObject, new ImportInfo[] + { + supportedImportInfo + }); + + // Assert + TestHelper.AssertLogMessageIsGenerated(Call, "Importeren van gegevens is geannuleerd."); + } + + mockRepository.VerifyAll(); + } + + [TestCase(true)] + [TestCase(false)] + public void ImportOn_MultipleSupportedImportInfos_ShowsDialogWithOptions(bool hasFileFilterGenerator) + { + // Setup + const string importInfoAName = "nameA"; + var importInfoA = new ImportInfo + { + Name = importInfoAName, + FileFilterGenerator = hasFileFilterGenerator ? new FileFilterGenerator("extensionA") : null + }; + const string importInfoBName = "nameB"; + var importInfoB = new ImportInfo + { + Name = importInfoBName, + FileFilterGenerator = hasFileFilterGenerator ? new FileFilterGenerator("extensionB") : null + }; + + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + mockRepository.ReplayAll(); + + var listViewItems = new ListViewItem[0]; + + DialogBoxHandler = (name, wnd) => + { + using (new FormTester(name)) + { + var listView = (ListView) new ControlTester("listViewItemTypes").TheObject; + listViewItems = listView.Items.OfType().ToArray(); + } + }; + + using (var form = new Form()) + { + var importHandler = new GuiImportHandler(form, Enumerable.Empty(), inquiryHelper); + + // Call + importHandler.ImportOn(new object(), new ImportInfo[] + { + importInfoA, + importInfoB + }); + } + + // Assert + Assert.AreEqual(2, listViewItems.Length); + string expectedItemNameA = hasFileFilterGenerator + ? $"{importInfoA.Name} (*.{importInfoA.FileFilterGenerator.Extension})" + : importInfoA.Name; + Assert.AreEqual(expectedItemNameA, listViewItems[0].Name); + string expectedItemNameB = hasFileFilterGenerator + ? $"{importInfoB.Name} (*.{importInfoB.FileFilterGenerator.Extension})" + : importInfoB.Name; + Assert.AreEqual(expectedItemNameB, listViewItems[1].Name); + + mockRepository.VerifyAll(); + } + + private class TestClassA {} + + private class TestClassB : TestClassA {} + + private class TestClassC {} + + private class ImportInfoNameComparer : IComparer + { + public int Compare(object x, object y) + { + return string.CompareOrdinal(((ImportInfo) x)?.Name, ((ImportInfo) y)?.Name); + } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Commands/GuiUpdateHandlerTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Commands/GuiUpdateHandlerTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Commands/GuiUpdateHandlerTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,530 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Base.IO; +using Core.Common.TestUtil; +using Core.Common.Util; +using Core.Gui.Commands; +using Core.Gui.Forms.MainWindow; +using Core.Gui.Helpers; +using Core.Gui.Plugin; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Commands +{ + [TestFixture] + public class GuiUpdateHandlerTest : NUnitFormTest + { + [Test] + public void Constructor_WithoutDialogParent_ThrowsArgumentNullException() + { + // Setup + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + mockRepository.ReplayAll(); + + // Call + TestDelegate test = () => new GuiUpdateHandler(null, Enumerable.Empty(), inquiryHelper); + + // Assert + string paramName = Assert.Throws(test).ParamName; + Assert.AreEqual("dialogParent", paramName); + mockRepository.VerifyAll(); + } + + [Test] + public void Constructor_WithoutUpdateInfos_ThrowsArgumentNullException() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + var inquiryHelper = mockRepository.Stub(); + mockRepository.ReplayAll(); + + // Call + TestDelegate test = () => new GuiUpdateHandler(mainWindow, null, inquiryHelper); + + // Assert + string paramName = Assert.Throws(test).ParamName; + Assert.AreEqual("updateInfos", paramName); + mockRepository.VerifyAll(); + } + + [Test] + public void Constructor_WithoutInquiryHelper_ThrowsArgumentNullException() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + mockRepository.ReplayAll(); + + // Call + TestDelegate test = () => new GuiUpdateHandler(mainWindow, Enumerable.Empty(), null); + + // Assert + string paramName = Assert.Throws(test).ParamName; + Assert.AreEqual("inquiryHelper", paramName); + mockRepository.VerifyAll(); + } + + [Test] + public void CanUpdateOn_HasNoFileUpdatersForTarget_ReturnFalse() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiUpdateHandler(dialogParent, Enumerable.Empty(), inquiryHelper); + + // Call + bool isUpdatePossible = commandHandler.CanUpdateOn(new object()); + + // Assert + Assert.IsFalse(isUpdatePossible); + mocks.VerifyAll(); + } + + [Test] + public void CanUpdateOn_HasOneUpdateInfoForTarget_ReturnTrue() + { + // Setup + var target = new object(); + + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiUpdateHandler(dialogParent, new UpdateInfo[] + { + new UpdateInfo() + }, inquiryHelper); + + // Call + bool isUpdatePossible = commandHandler.CanUpdateOn(target); + + // Assert + Assert.IsTrue(isUpdatePossible); + mocks.VerifyAll(); + } + + [Test] + public void CanUpdateOn_HasOneUpdateInfoForTargetThatIsNotEnabledForTarget_ReturnFalse() + { + // Setup + var target = new object(); + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiUpdateHandler(dialogParent, new UpdateInfo[] + { + new UpdateInfo + { + IsEnabled = data => false + } + }, inquiryHelper); + + // Call + bool isUpdatePossible = commandHandler.CanUpdateOn(target); + + // Assert + Assert.IsFalse(isUpdatePossible); + mocks.VerifyAll(); + } + + [Test] + public void CanUpdateOn_HasMultipleUpdateInfosForTargetWhereAtLeastOneEnabledForTargetItem_ReturnTrue() + { + // Setup + var target = new object(); + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiUpdateHandler(dialogParent, new UpdateInfo[] + { + new UpdateInfo + { + IsEnabled = data => false + }, + new UpdateInfo + { + IsEnabled = data => true + } + }, inquiryHelper); + + // Call + bool isUpdatePossible = commandHandler.CanUpdateOn(target); + + // Assert + Assert.IsTrue(isUpdatePossible); + mocks.VerifyAll(); + } + + [Test] + public void CanUpdateOn_HasMultipleUpdateInfosForTargetThatCannotBeUsedForUpdating_ReturnFalse() + { + // Setup + var target = new object(); + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new GuiUpdateHandler(dialogParent, new UpdateInfo[] + { + new UpdateInfo + { + IsEnabled = data => false + }, + new UpdateInfo + { + IsEnabled = data => false + } + }, inquiryHelper); + + // Call + bool isUpdatePossible = commandHandler.CanUpdateOn(target); + + // Assert + Assert.IsFalse(isUpdatePossible); + mocks.VerifyAll(); + } + + [Test] + public void UpdateOn_NoUpdaterAvailable_GivesMessageBox() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + var inquiryHelper = mockRepository.Stub(); + mockRepository.ReplayAll(); + + string messageBoxTitle = null, messageBoxText = null; + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + + messageBoxText = messageBox.Text; + messageBoxTitle = messageBox.Title; + + messageBox.ClickOk(); + }; + + var updateHandler = new GuiUpdateHandler(mainWindow, Enumerable.Empty(), inquiryHelper); + + // Call + updateHandler.UpdateOn(3); + + // Assert + Assert.AreEqual("Fout", messageBoxTitle); + Assert.AreEqual("Geen enkele 'Updater' is beschikbaar voor dit element.", messageBoxText); + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateOn_NoSupportedUpdateInfoAvailable_GivesMessageBox() + { + // Setup + var mockRepository = new MockRepository(); + var mainWindow = mockRepository.Stub(); + var inquiryHelper = mockRepository.Stub(); + mockRepository.ReplayAll(); + + string messageBoxTitle = null, messageBoxText = null; + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + + messageBoxText = messageBox.Text; + messageBoxTitle = messageBox.Title; + + messageBox.ClickOk(); + }; + + var updateHandler = new GuiUpdateHandler(mainWindow, new UpdateInfo[] + { + new UpdateInfo() + }, inquiryHelper); + + // Call + updateHandler.UpdateOn(string.Empty); + + // Assert + Assert.AreEqual("Fout", messageBoxTitle); + Assert.AreEqual("Geen enkele 'Updater' is beschikbaar voor dit element.", messageBoxText); + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateOn_SupportedUpdateInfoAvailableVerifyUpdatesSuccessful_ExpectedUpdateInfoFunctionsCalledActivityCreated() + { + // Setup + const string filePath = "/some/path"; + var generator = new FileFilterGenerator(); + var targetObject = new object(); + + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + inquiryHelper.Stub(ih => ih.GetSourceFileLocation(generator.Filter)).Return(filePath); + var fileImporter = mockRepository.Stub(); + mockRepository.ReplayAll(); + + const string dataDescription = "Random data"; + var isCreateFileImporterCalled = false; + var isVerifyUpdatedCalled = false; + + DialogBoxHandler = (name, wnd) => + { + // Activity closes itself + }; + + using (var form = new Form()) + { + var updateHandler = new GuiUpdateHandler(form, new UpdateInfo[] + { + new UpdateInfo + { + Name = dataDescription, + CreateFileImporter = (o, s) => + { + Assert.AreSame(o, targetObject); + Assert.AreEqual(filePath, s); + isCreateFileImporterCalled = true; + return fileImporter; + }, + FileFilterGenerator = generator, + VerifyUpdates = o => + { + Assert.AreSame(o, targetObject); + isVerifyUpdatedCalled = true; + return true; + } + } + }, inquiryHelper); + + // Call + Action call = () => updateHandler.UpdateOn(targetObject); + + // Assert + TestHelper.AssertLogMessagesAreGenerated(call, new[] + { + $"Bijwerken van '{dataDescription}' is gestart.", + $"Bijwerken van '{dataDescription}' is mislukt." + }); + } + + // Assert + Assert.IsTrue(isCreateFileImporterCalled); + Assert.IsTrue(isVerifyUpdatedCalled); + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateOn_InquiryHelperReturnsNoPathAndCurrentPathNotSet_UpdateCancelledWithLogMessage() + { + // Setup + var generator = new FileFilterGenerator(); + var targetObject = new object(); + + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + inquiryHelper.Stub(ih => ih.GetSourceFileLocation(generator.Filter)).Return(null); + var fileImporter = mockRepository.Stub(); + mockRepository.ReplayAll(); + + using (var form = new Form()) + { + var updateHandler = new GuiUpdateHandler(form, new UpdateInfo[] + { + new UpdateInfo + { + CreateFileImporter = (o, s) => + { + Assert.Fail("CreateFileImporter is not expected to be called when no file path is chosen."); + return fileImporter; + }, + FileFilterGenerator = generator, + VerifyUpdates = o => true + } + }, inquiryHelper); + + // Call + Action call = () => updateHandler.UpdateOn(targetObject); + + // Assert + const string expectedLogMessage = "Bijwerken van gegevens is geannuleerd."; + Tuple expectedLogMessageAndLevel = Tuple.Create(expectedLogMessage, + LogLevelConstant.Info); + TestHelper.AssertLogMessageWithLevelIsGenerated(call, expectedLogMessageAndLevel); + } + + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateOn_InquiryHelperReturnsNoPathAndCurrentPathSet_UpdateCancelledWithLogMessage() + { + // Setup + var generator = new FileFilterGenerator(); + var targetObject = new object(); + + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + inquiryHelper.Stub(ih => ih.GetSourceFileLocation(generator.Filter)).Return(null); + var fileImporter = mockRepository.Stub(); + mockRepository.ReplayAll(); + + const string currentPath = "FilePath/to/Update"; + using (var form = new Form()) + { + var updateHandler = new GuiUpdateHandler(form, new UpdateInfo[] + { + new UpdateInfo + { + CreateFileImporter = (o, s) => + { + Assert.Fail("CreateFileImporter is not expected to be called when no file path is chosen."); + return fileImporter; + }, + FileFilterGenerator = generator, + VerifyUpdates = o => true, + CurrentPath = o => currentPath + } + }, inquiryHelper); + + // Call + Action call = () => updateHandler.UpdateOn(targetObject); + + // Assert + string expectedLogMessage = $"Bijwerken van gegevens in '{currentPath}' is geannuleerd."; + Tuple expectedLogMessageAndLevel = Tuple.Create(expectedLogMessage, + LogLevelConstant.Info); + TestHelper.AssertLogMessageWithLevelIsGenerated(call, expectedLogMessageAndLevel); + } + + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateOn_SupportedUpdateInfoAvailableVerifyUpdatesUnsuccessful_ActivityNotCreated() + { + // Setup + var generator = new FileFilterGenerator(); + var targetObject = new object(); + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + inquiryHelper.Stub(ih => ih.GetSourceFileLocation(generator.Filter)).Return("/some/path"); + var fileImporter = mockRepository.Stub(); + mockRepository.ReplayAll(); + + var isVerifyUpdatedCalled = false; + + using (var form = new Form()) + { + var updateHandler = new GuiUpdateHandler(form, new UpdateInfo[] + { + new UpdateInfo + { + CreateFileImporter = (o, s) => + { + Assert.Fail("CreateFileImporter is not expected to be called when VerifyUpdates function returns false."); + return fileImporter; + }, + FileFilterGenerator = generator, + VerifyUpdates = o => + { + Assert.AreSame(o, targetObject); + isVerifyUpdatedCalled = true; + return false; + } + } + }, inquiryHelper); + + // Call + updateHandler.UpdateOn(targetObject); + } + + // Assert + Assert.IsTrue(isVerifyUpdatedCalled); + mockRepository.VerifyAll(); + } + + [Test] + public void UpdateOn_MultipleSupportedUpdateInfoAvailable_ShowsDialogWithOptions() + { + // Setup + const string updateInfoAName = "nameA"; + var updateInfoA = new UpdateInfo + { + Name = updateInfoAName + }; + const string updateInfoBName = "nameB"; + var updateInfoB = new UpdateInfo + { + Name = updateInfoBName + }; + + var mockRepository = new MockRepository(); + var inquiryHelper = mockRepository.Stub(); + mockRepository.ReplayAll(); + + var listViewItems = new ListViewItem[0]; + + DialogBoxHandler = (name, wnd) => + { + using (new FormTester(name)) + { + var listView = (ListView) new ControlTester("listViewItemTypes").TheObject; + listViewItems = listView.Items.OfType().ToArray(); + } + }; + + using (var form = new Form()) + { + var updateHandler = new GuiUpdateHandler(form, new UpdateInfo[] + { + updateInfoA, + updateInfoB + }, inquiryHelper); + + // Call + updateHandler.UpdateOn(new object()); + } + + // Assert + Assert.AreEqual(2, listViewItems.Length); + Assert.AreEqual(updateInfoAName, listViewItems[0].Name); + Assert.AreEqual(updateInfoBName, listViewItems[1].Name); + mockRepository.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Commands/StorageCommandHandlerTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Commands/StorageCommandHandlerTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Commands/StorageCommandHandlerTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,1046 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Windows.Forms; +using Core.Common.Base.Data; +using Core.Common.Base.IO; +using Core.Common.Base.Storage; +using Core.Common.TestUtil; +using Core.Gui.Commands; +using Core.Gui.Helpers; +using Core.Gui.Selection; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Commands +{ + [TestFixture] + public class StorageCommandHandlerTest : NUnitFormTest + { + private MockRepository mocks; + + [Test] + public void CreateNewProject_SavedProjectThenNewProject_NewProjectAndPathAreSet() + { + // Setup + const string savedProjectPath = @"C:\savedProject.rtd"; + + var oldProject = mocks.Stub(); + var newProject = mocks.Stub(); + + var projectStorage = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(oldProject); + projectOwner.Stub(po => po.ProjectFilePath).Return(savedProjectPath); + var projectFactory = mocks.Stub(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(newProject); + projectOwner.Expect(po => po.SetProject(newProject, null)); + + var inquiryHelper = mocks.Stub(); + var mainWindowController = mocks.Stub(); + + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + // Call + Action call = () => storageCommandHandler.CreateNewProject(); + + // Assert + Tuple[] expectedMessages = + { + Tuple.Create("Nieuw project aanmaken is gestart.", LogLevelConstant.Info), + Tuple.Create("Nieuw project aanmaken is gelukt.", LogLevelConstant.Info) + }; + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, expectedMessages, 2); + + mocks.VerifyAll(); + } + + [Test] + public void SaveProject_SavingProjectThrowsStorageException_AbortSaveAndReturnFalse() + { + // Setup + string someValidFilePath = TestHelper.GetScratchPadPath(nameof(SaveProject_SavingProjectThrowsStorageException_AbortSaveAndReturnFalse)); + using (new FileDisposeHelper(someValidFilePath)) + { + var project = mocks.Stub(); + var projectFactory = mocks.Stub(); + + const string exceptionMessage = ""; + + var projectStorage = mocks.StrictMock(); + projectStorage.Expect(ps => ps.HasStagedProject).Return(false); + projectStorage.Expect(ps => ps.StageProject(project)); + projectStorage.Expect(ps => ps.SaveProjectAs(someValidFilePath)) + .Throw(new StorageException(exceptionMessage, new Exception("l33t h4xor!"))); + + var projectMigrator = mocks.Stub(); + + var mainWindowController = mocks.Stub(); + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Stub(po => po.ProjectFilePath).Return(someValidFilePath); + + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (s, hWnd) => + { + // Expect progress dialog, which will close automatically. + }; + + // Call + var result = true; + Action call = () => result = storageCommandHandler.SaveProject(); + + // Assert + Tuple[] expectedMessages = + { + Tuple.Create("Opslaan van bestaand project is gestart.", LogLevelConstant.Info), + Tuple.Create(exceptionMessage, LogLevelConstant.Error), + Tuple.Create("Opslaan van bestaand project is mislukt.", LogLevelConstant.Error) + }; + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, expectedMessages, 3); + Assert.IsFalse(result); + } + + mocks.VerifyAll(); + } + + [Test] + public void SaveProject_SavingProjectIsSuccessful_LogSuccessAndReturnTrue() + { + // Setup + string someValidFilePath = TestHelper.GetScratchPadPath(nameof(SaveProject_SavingProjectIsSuccessful_LogSuccessAndReturnTrue)); + using (new FileDisposeHelper(someValidFilePath)) + { + var project = mocks.Stub(); + var projectFactory = mocks.Stub(); + + var projectStorage = mocks.Stub(); + projectStorage.Expect(ps => ps.StageProject(project)); + projectStorage.Expect(ps => ps.HasStagedProject).Return(false); + projectStorage.Expect(ps => ps.SaveProjectAs(someValidFilePath)); + + var projectMigrator = mocks.Stub(); + + var mainWindowController = mocks.Stub(); + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Stub(po => po.ProjectFilePath).Return(someValidFilePath); + + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (s, hWnd) => + { + // Expect progress dialog, which will close automatically. + }; + + // Call + var result = false; + Action call = () => result = storageCommandHandler.SaveProject(); + + // Assert + TestHelper.AssertLogMessageWithLevelIsGenerated(call, Tuple.Create("Opslaan van bestaand project is gelukt.", LogLevelConstant.Info)); + Assert.IsTrue(result); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenExistingProject_MigrationNeeded_MigratesFileAndSetNewlyLoadedProjectAtMigratedFileAndReturnTrue() + { + // Setup + const string fileName = "newProject"; + string pathToSomeValidFile = $"C://folder/directory/{fileName}.rtd"; + string pathToMigratedFile = $"C://folder/directory/{fileName}-newerVersion.rtd"; + var loadedProject = mocks.Stub(); + var projectFactory = mocks.Stub(); + + var projectStorage = mocks.Stub(); + projectStorage.Stub(ps => ps.LoadProject(pathToMigratedFile)) + .Return(loadedProject); + + var projectMigrator = mocks.StrictMock(); + using (mocks.Ordered()) + { + projectMigrator.Expect(pm => pm.ShouldMigrate(pathToSomeValidFile)).Return(MigrationRequired.Yes); + projectMigrator.Expect(pm => pm.DetermineMigrationLocation(pathToSomeValidFile)).Return(pathToMigratedFile); + projectMigrator.Expect(pm => pm.Migrate(pathToSomeValidFile, pathToMigratedFile)).Return(true); + } + + var mainWindowController = mocks.Stub(); + + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.SetProject(loadedProject, pathToMigratedFile)); + + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (name, wnd) => + { + // Activity dialog opened and will be closed automatically once done. + }; + + // Call + var result = false; + Action call = () => result = storageCommandHandler.OpenExistingProject(pathToSomeValidFile); + + // Assert + Tuple[] expectedMessages = + { + Tuple.Create("Openen van project is gestart.", LogLevelConstant.Info), + Tuple.Create("Openen van project is gelukt.", LogLevelConstant.Info) + }; + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, expectedMessages, 2); + Assert.IsTrue(result); + + mocks.VerifyAll(); + } + + [Test] + public void OpenExistingProject_ShouldMigrateCancelled_LeaveCurrentProjectUnaffectedAndReturnsFalse() + { + // Setup + const string fileName = "newProject"; + string pathToSomeValidFile = $"C://folder/directory/{fileName}.rtd"; + + var projectStorage = mocks.StrictMock(); + + var projectMigrator = mocks.StrictMock(); + projectMigrator.Expect(pm => pm.ShouldMigrate(pathToSomeValidFile)).Return(MigrationRequired.Aborted); + + var project = mocks.Stub(); + var projectFactory = mocks.StrictMock(); + projectFactory.Expect(pf => pf.CreateNewProject()).Return(project) + .Repeat.Never(); + + var projectOwner = mocks.StrictMock(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Expect(po => po.SetProject(project, null)) + .Repeat.Never(); + + var mainWindowController = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + // Call + bool result = storageCommandHandler.OpenExistingProject(pathToSomeValidFile); + + // Assert + Assert.IsFalse(result); + mocks.VerifyAll(); + } + + [Test] + public void OpenExistingProject_DetermineMigrationLocationButCancelled_LeaveCurrentProjectUnaffectedAndReturnsFalse() + { + // Setup + const string fileName = "newProject"; + string pathToSomeValidFile = $"C://folder/directory/{fileName}.rtd"; + + var projectStorage = mocks.StrictMock(); + + var projectMigrator = mocks.StrictMock(); + using (mocks.Ordered()) + { + projectMigrator.Expect(pm => pm.ShouldMigrate(pathToSomeValidFile)).Return(MigrationRequired.Yes); + projectMigrator.Expect(pm => pm.DetermineMigrationLocation(pathToSomeValidFile)).Return(null); + } + + var project = mocks.Stub(); + var projectFactory = mocks.StrictMock(); + projectFactory.Expect(pf => pf.CreateNewProject()).Return(project) + .Repeat.Never(); + + var projectOwner = mocks.StrictMock(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Expect(po => po.SetProject(project, null)) + .Repeat.Never(); + + var mainWindowController = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + // Call + bool result = storageCommandHandler.OpenExistingProject(pathToSomeValidFile); + + // Assert + Assert.IsFalse(result); + mocks.VerifyAll(); + } + + [Test] + [TestCaseSource(nameof(GetExceptions))] + public void OpenExistingProject_ShouldMigrateThrowsException_LogFailureAndCreateNewProjectAndReturnsFalse(Exception exception, string errorMessage) + { + // Setup + const string pathToSomeValidFile = " "; + + var projectStorage = mocks.StrictMock(); + + var projectMigrator = mocks.StrictMock(); + projectMigrator.Expect(pm => pm.ShouldMigrate(pathToSomeValidFile)) + .Throw(exception); + + var project = mocks.Stub(); + var projectFactory = mocks.StrictMock(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(project); + + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Stub(po => po.SetProject(project, null)); + + var mainWindowController = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + // Call + var result = true; + Action call = () => result = storageCommandHandler.OpenExistingProject(pathToSomeValidFile); + + // Assert + TestHelper.AssertLogMessageWithLevelIsGenerated(call, Tuple.Create(errorMessage, LogLevelConstant.Error), 1); + Assert.IsFalse(result); + mocks.VerifyAll(); + } + + [Test] + public void OpenExistingProject_ShouldMigrateYesAndDetermineMigrationLocationThrowsArgumentException_LogFailureAndCreateNewProjectAndReturnsFalse() + { + // Setup + const string errorMessage = "I am an error message."; + const string pathToSomeValidFile = "C://folder/directory/newProject.rtd"; + + var projectStorage = mocks.StrictMock(); + + var projectMigrator = mocks.StrictMock(); + using (mocks.Ordered()) + { + projectMigrator.Expect(pm => pm.ShouldMigrate(pathToSomeValidFile)).Return(MigrationRequired.Yes); + projectMigrator.Expect(pm => pm.DetermineMigrationLocation(pathToSomeValidFile)) + .Throw(new ArgumentException(errorMessage)); + } + + var project = mocks.Stub(); + var projectFactory = mocks.StrictMock(); + projectFactory.Expect(pf => pf.CreateNewProject()).Return(project); + + var projectOwner = mocks.StrictMock(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Expect(po => po.SetProject(project, null)); + + var mainWindowController = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + // Call + var result = true; + Action call = () => result = storageCommandHandler.OpenExistingProject(pathToSomeValidFile); + + // Assert + TestHelper.AssertLogMessageWithLevelIsGenerated(call, Tuple.Create(errorMessage, LogLevelConstant.Error), 1); + Assert.IsFalse(result); + mocks.VerifyAll(); + } + + [Test] + public void OpenExistingProject_ShouldMigrateTrueAndMigrateThrowsArgumentException_LogFailureAndCreateNewProjectAndReturnsFalse() + { + // Setup + const string errorMessage = "I am an error message."; + const string fileName = "newProject"; + string pathToSomeValidFile = $"C://folder/directory/{fileName}.rtd"; + string pathToMigratedFile = $"C://folder/directory/{fileName}-newerVersion.rtd"; + + var projectStorage = mocks.StrictMock(); + + var projectMigrator = mocks.StrictMock(); + using (mocks.Ordered()) + { + projectMigrator.Expect(pm => pm.ShouldMigrate(pathToSomeValidFile)).Return(MigrationRequired.Yes); + projectMigrator.Expect(pm => pm.DetermineMigrationLocation(pathToSomeValidFile)).Return(pathToMigratedFile); + projectMigrator.Expect(pm => pm.Migrate(pathToSomeValidFile, pathToMigratedFile)) + .Throw(new ArgumentException(errorMessage)); + } + + var project = mocks.Stub(); + var projectFactory = mocks.StrictMock(); + projectFactory.Expect(pf => pf.CreateNewProject()).Return(project); + + var projectOwner = mocks.StrictMock(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Expect(po => po.SetProject(project, null)); + + var mainWindowController = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (name, wnd) => + { + // Activity dialog opened and will be closed automatically once done. + }; + + // Call + var result = true; + Action call = () => result = storageCommandHandler.OpenExistingProject(pathToSomeValidFile); + + // Assert + TestHelper.AssertLogMessageWithLevelIsGenerated(call, Tuple.Create(errorMessage, LogLevelConstant.Error), 3); + Assert.IsFalse(result); + mocks.VerifyAll(); + } + + [Test] + public void OpenExistingProject_LoadingProjectThrowsStorageException_LogFailureCreateNewProjectAndReturnFalse() + { + // Setup + const string pathToSomeInvalidFile = ""; + const string goodErrorMessageText = ""; + + var project = mocks.Stub(); + var projectStorage = mocks.Stub(); + projectStorage.Stub(ps => ps.LoadProject(pathToSomeInvalidFile)) + .Throw(new StorageException(goodErrorMessageText, new Exception("H@X!"))); + var projectMigrator = mocks.Stub(); + projectMigrator.Stub(m => m.ShouldMigrate(pathToSomeInvalidFile)).Return(MigrationRequired.No); + var projectFactory = mocks.Stub(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(project); + var mainWindowController = mocks.Stub(); + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Stub(po => po.SetProject(project, null)); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (name, wnd) => + { + // Activity dialog opened and will be closed automatically once done. + }; + + // Call + var result = true; + Action call = () => result = storageCommandHandler.OpenExistingProject(pathToSomeInvalidFile); + + // Assert + Tuple[] expectedMessages = + { + Tuple.Create("Openen van project is gestart.", LogLevelConstant.Info), + Tuple.Create(goodErrorMessageText, LogLevelConstant.Error), + Tuple.Create("Openen van project is mislukt.", LogLevelConstant.Error) + }; + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, expectedMessages, 3); + Assert.IsFalse(result); + + mocks.VerifyAll(); + } + + [Test] + public void OpenExistingProject_LoadingNull_LogFailureCreateNewProjectAndReturnFalse() + { + // Setup + const string pathToSomeInvalidFile = ""; + + var project = mocks.Stub(); + var mainWindowController = mocks.Stub(); + var projectStorage = mocks.Stub(); + projectStorage.Stub(ps => ps.LoadProject(pathToSomeInvalidFile)) + .Return(null); + + var projectMigrator = mocks.Stub(); + + var projectFactory = mocks.Stub(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(project); + + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Stub(po => po.SetProject(project, null)); + + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (name, wnd) => + { + // Activity dialog opened and will be closed automatically once done. + }; + + // Call + var result = true; + Action call = () => result = storageCommandHandler.OpenExistingProject(pathToSomeInvalidFile); + + // Assert + Tuple[] expectedMessages = + { + Tuple.Create("Openen van project is gestart.", LogLevelConstant.Info), + Tuple.Create("Openen van project is mislukt.", LogLevelConstant.Error) + }; + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, expectedMessages, 2); + Assert.IsFalse(result); + + mocks.VerifyAll(); + } + + [Test] + public void OpenExistingProject_OpeningProjectWhenNoProjectHasBeenLoaded_SetNewlyLoadedProjectAndReturnTrue() + { + // Setup + const string fileName = "newProject"; + string pathToSomeValidFile = $"C://folder/directory/{fileName}.rtd"; + var loadedProject = mocks.Stub(); + var projectFactory = mocks.Stub(); + + var projectStorage = mocks.Stub(); + projectStorage.Stub(ps => ps.LoadProject(pathToSomeValidFile)) + .Return(loadedProject); + + var projectMigrator = mocks.Stub(); + projectMigrator.Stub(m => m.ShouldMigrate(pathToSomeValidFile)).Return(MigrationRequired.No); + var mainWindowController = mocks.Stub(); + + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.SetProject(loadedProject, pathToSomeValidFile)); + + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (name, wnd) => + { + // Activity dialog opened and will be closed automatically once done. + }; + + // Call + var result = false; + Action call = () => result = storageCommandHandler.OpenExistingProject(pathToSomeValidFile); + + // Assert + Tuple[] expectedMessages = + { + Tuple.Create("Openen van project is gestart.", LogLevelConstant.Info), + Tuple.Create("Openen van project is gelukt.", LogLevelConstant.Info) + }; + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, expectedMessages, 2); + Assert.IsTrue(result); + + mocks.VerifyAll(); + } + + [Test] + public void OpenExistingProject_OpeningProjectWithAlreadyLoadedProject_SetNewlyLoadedProjectAndReturnTrue() + { + // Setup + const string fileName = "newProject"; + string pathToSomeValidFile = $"C://folder/directory/{fileName}.rtd"; + var loadedProject = mocks.Stub(); + var originalProject = mocks.Stub(); + var projectFactory = mocks.Stub(); + + var projectStorage = mocks.Stub(); + projectStorage.Stub(ps => ps.LoadProject(pathToSomeValidFile)) + .Return(loadedProject); + + var projectMigrator = mocks.Stub(); + projectMigrator.Stub(m => m.ShouldMigrate(pathToSomeValidFile)).Return(MigrationRequired.No); + + var applicationSelection = mocks.Stub(); + applicationSelection.Selection = originalProject; + + var mainWindowController = mocks.Stub(); + + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(originalProject); + projectOwner.Stub(po => po.ProjectFilePath).Return(""); + projectOwner.Stub(po => po.SetProject(loadedProject, pathToSomeValidFile)); + + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (name, wnd) => + { + // Activity dialog opened and will be closed automatically once done. + }; + + // Call + var result = false; + Action call = () => result = storageCommandHandler.OpenExistingProject(pathToSomeValidFile); + + // Assert + Tuple[] expectedMessages = + { + Tuple.Create("Openen van project is gestart.", LogLevelConstant.Info), + Tuple.Create("Openen van project is gelukt.", LogLevelConstant.Info) + }; + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, expectedMessages, 2); + Assert.IsTrue(result); + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetExistingProjectFilePath_FilePathSelectedAndOkClicked_ReturnsSelectedFilePath() + { + // Setup + var mainWindowController = mocks.Stub(); + var projectFactory = mocks.Stub(); + var projectStorage = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var projectOwner = mocks.Stub(); + var project = mocks.Stub(); + + projectOwner.Stub(po => po.Project).Return(project); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(project); + projectStorage.Stub(ps => ps.HasStagedProjectChanges(null)).IgnoreArguments().Return(false); + projectStorage.Stub(ps => ps.OpenProjectFileFilter).Return(string.Empty); + + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + string projectPath = TestHelper.GetScratchPadPath( + nameof(GetExistingProjectFilePath_FilePathSelectedAndOkClicked_ReturnsSelectedFilePath)); + using (new FileDisposeHelper(projectPath)) + { + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (name, wnd) => + { + var helper = new OpenFileDialogTester(wnd); + helper.OpenFile(projectPath); + }; + + // Call + string returnedPath = storageCommandHandler.GetExistingProjectFilePath(); + + // Assert + Assert.AreEqual(projectPath, returnedPath); + } + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetExistingProjectFilePath_NoFilePathSelectedAndCancelClicked_ReturnsFilePathNull() + { + // Setup + var mainWindowController = mocks.Stub(); + var projectFactory = mocks.Stub(); + var projectStorage = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var projectOwner = mocks.Stub(); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (name, wnd) => + { + var helper = new OpenFileDialogTester(wnd); + helper.ClickCancel(); + }; + + // Call + string returnedPath = storageCommandHandler.GetExistingProjectFilePath(); + + // Assert + Assert.IsNull(returnedPath); + } + + [Test] + public void AskConfirmationUnsavedChanges_ProjectSetNoChange_ReturnsTrue() + { + // Setup + var mainWindowController = mocks.Stub(); + var project = mocks.Stub(); + var projectFactory = mocks.Stub(); + var projectStorage = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Stub(po => po.ProjectFilePath).Return(""); + var inquiryHelper = mocks.Stub(); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + // Call + bool changesHandled = storageCommandHandler.HandleUnsavedChanges(); + + // Assert + Assert.IsTrue(changesHandled); + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void AskConfirmationUnsavedChanges_ProjectSetWithChangeCancelPressed_ReturnsFalse() + { + // Setup + var mainWindowController = mocks.Stub(); + var projectFactory = mocks.Stub(); + + var project = mocks.Stub(); + const string projectName = "Project"; + project.Name = projectName; + + var projectStorage = mocks.StrictMock(); + projectStorage.Expect(ps => ps.StageProject(project)); + projectStorage.Expect(ps => ps.HasStagedProject).Return(true); + projectStorage.Expect(ps => ps.HasStagedProjectChanges(null)).IgnoreArguments().Return(true); + projectStorage.Expect(ps => ps.UnstageProject()); + + var projectMigrator = mocks.Stub(); + + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Stub(po => po.ProjectFilePath).Return(""); + + var inquiryHelper = mocks.StrictMock(); + inquiryHelper.Expect(h => h.InquirePerformOptionalStep("Project afsluiten", + $"Sla wijzigingen in het project op: {projectName}?")) + .Return(OptionalStepResult.Cancel); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + // Call + bool changesHandled = storageCommandHandler.HandleUnsavedChanges(); + + // Assert + Assert.IsFalse(changesHandled); + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void AskConfirmationUnsavedChanges_ProjectSetWithChangeNoPressed_ReturnsTrue() + { + // Setup + var mainWindowController = mocks.Stub(); + var projectFactory = mocks.Stub(); + + var project = mocks.Stub(); + const string projectName = "Project"; + project.Name = projectName; + + var projectStorage = mocks.StrictMock(); + projectStorage.Expect(ps => ps.StageProject(project)); + projectStorage.Expect(ps => ps.HasStagedProject).Return(true); + projectStorage.Expect(ps => ps.HasStagedProjectChanges(null)).IgnoreArguments().Return(true); + projectStorage.Expect(ps => ps.UnstageProject()); + + var projectMigrator = mocks.Stub(); + + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Stub(po => po.ProjectFilePath).Return(""); + + var inquiryHelper = mocks.StrictMock(); + inquiryHelper.Expect(h => h.InquirePerformOptionalStep("Project afsluiten", + $"Sla wijzigingen in het project op: {projectName}?")) + .Return(OptionalStepResult.SkipOptionalStep); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + // Call + bool changesHandled = storageCommandHandler.HandleUnsavedChanges(); + + // Assert + Assert.IsTrue(changesHandled); + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void AskConfirmationUnsavedChanges_ProjectSetWithChangeYesPressed_ReturnsTrue() + { + // Setup + const string projectName = "Project"; + string someValidFilePath = TestHelper.GetScratchPadPath(nameof(AskConfirmationUnsavedChanges_ProjectSetWithChangeYesPressed_ReturnsTrue)); + using (new FileDisposeHelper(someValidFilePath)) + { + var mainWindowController = mocks.Stub(); + var projectFactory = mocks.Stub(); + + var project = mocks.Stub(); + project.Name = projectName; + + var projectStorage = mocks.StrictMock(); + projectStorage.Expect(ps => ps.StageProject(project)); + projectStorage.Expect(ps => ps.HasStagedProject).Return(true).Repeat.Twice(); + projectStorage.Expect(ps => ps.HasStagedProjectChanges(null)).IgnoreArguments().Return(true); + projectStorage.Expect(ps => ps.UnstageProject()); + projectStorage.Expect(p => p.SaveProjectAs(someValidFilePath)); + + var projectMigrator = mocks.Stub(); + + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Stub(po => po.ProjectFilePath).Return(someValidFilePath); + + var inquiryHelper = mocks.StrictMock(); + inquiryHelper.Expect(h => h.InquirePerformOptionalStep("Project afsluiten", + $"Sla wijzigingen in het project op: {projectName}?")) + .Return(OptionalStepResult.PerformOptionalStep); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (s, hWnd) => + { + // Expect progress dialog, which will close automatically. + }; + + // Call + bool changesHandled = storageCommandHandler.HandleUnsavedChanges(); + + // Assert + Assert.IsTrue(changesHandled); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void AskConfirmationUnsavedChanges_ProjectSetWithChangeYesFileDoesNotExist_ReturnsTrue() + { + // Setup + const string fileFilter = " | *.rtd"; + const string projectName = "Project"; + string someValidFilePath = TestHelper.GetScratchPadPath(nameof(AskConfirmationUnsavedChanges_ProjectSetWithChangeYesFileDoesNotExist_ReturnsTrue)); + + var mainWindowController = mocks.Stub(); + var projectFactory = mocks.Stub(); + + var project = mocks.Stub(); + project.Name = projectName; + + var projectStorage = mocks.StrictMock(); + projectStorage.Expect(ps => ps.StageProject(project)); + projectStorage.Stub(ps => ps.HasStagedProject).Return(true); + projectStorage.Expect(ps => ps.HasStagedProjectChanges(someValidFilePath)).Return(true); + projectStorage.Expect(ps => ps.UnstageProject()); + projectStorage.Stub(ps => ps.SaveProjectFileFilter).Return(fileFilter); + projectStorage.Expect(p => p.SaveProjectAs(someValidFilePath)); + + var projectMigrator = mocks.Stub(); + + var projectOwner = mocks.Stub(); + projectOwner.Stub(po => po.Project).Return(project); + projectOwner.Stub(po => po.ProjectFilePath).Return(someValidFilePath); + projectOwner.Expect(po => po.SetProject(project, someValidFilePath)); + + var inquiryHelper = mocks.StrictMock(); + inquiryHelper.Expect(h => h.InquirePerformOptionalStep("Project afsluiten", + $"Sla wijzigingen in het project op: {projectName}?")) + .Return(OptionalStepResult.PerformOptionalStep); + inquiryHelper.Expect(h => h.GetTargetFileLocation(fileFilter, projectName)) + .Return(someValidFilePath); + mocks.ReplayAll(); + + var storageCommandHandler = new StorageCommandHandler( + projectStorage, + projectMigrator, + projectFactory, + projectOwner, + inquiryHelper, + mainWindowController); + + DialogBoxHandler = (s, hWnd) => + { + // Expect progress dialog, which will close automatically. + }; + + // Call + bool changesHandled = storageCommandHandler.HandleUnsavedChanges(); + + // Assert + Assert.IsTrue(changesHandled); + + mocks.VerifyAll(); + } + + public override void Setup() + { + mocks = new MockRepository(); + } + + private static IEnumerable GetExceptions() + { + const string exceptionMessage = "I am an error message"; + + yield return new TestCaseData(new ArgumentException(exceptionMessage), exceptionMessage) + .SetName("ArgumentException"); + yield return new TestCaseData(new CriticalFileReadException(exceptionMessage), exceptionMessage) + .SetName("CriticalFileReadException"); + yield return new TestCaseData(new StorageValidationException(exceptionMessage), exceptionMessage) + .SetName("StorageValidationException"); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Commands/ViewCommandHandlerTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Commands/ViewCommandHandlerTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Commands/ViewCommandHandlerTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,230 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Collections.Generic; +using Core.Common.Controls.Views; +using Core.Gui.Commands; +using Core.Gui.Forms.ViewHost; +using Core.Gui.Plugin; +using Core.Gui.Selection; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Commands +{ + [TestFixture] + public class ViewCommandHandlerTest + { + [Test] + public void OpenViewForSelection_OpenViewDialogForSelection() + { + // Setup + var selectedObject = new object(); + + var mocks = new MockRepository(); + var documentViewController = mocks.Stub(); + documentViewController.Expect(r => r.OpenViewForData(selectedObject)).Return(true); + var viewController = mocks.Stub(); + viewController.Stub(c => c.DocumentViewController).Return(documentViewController); + var applicationSelection = mocks.Stub(); + applicationSelection.Selection = selectedObject; + var pluginsHost = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new ViewCommandHandler(viewController, applicationSelection, pluginsHost); + + // Call + commandHandler.OpenViewForSelection(); + + // Assert + mocks.VerifyAll(); // Expect open view method is called + } + + [Test] + public void CanOpenViewFor_NoViewInfosForTarget_ReturnFalse() + { + // Setup + var viewObject = new object(); + + var viewInfos = new ViewInfo[0]; + + var mocks = new MockRepository(); + var documentViewController = mocks.Stub(); + documentViewController.Expect(r => r.GetViewInfosFor(viewObject)).Return(viewInfos); + var viewController = mocks.Stub(); + viewController.Stub(c => c.DocumentViewController).Return(documentViewController); + var applicationSelection = mocks.Stub(); + var pluginsHost = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new ViewCommandHandler(viewController, applicationSelection, pluginsHost); + + // Call + bool hasViewDefinitionsForData = commandHandler.CanOpenViewFor(viewObject); + + // Assert + Assert.IsFalse(hasViewDefinitionsForData); + mocks.VerifyAll(); + } + + [Test] + [TestCase(1)] + [TestCase(11)] + public void CanOpenViewFor_HasViewInfoDefinedForData_ReturnTrue(int numberOfViewDefinitions) + { + // Setup + var viewObject = new object(); + + var viewInfos = new ViewInfo[numberOfViewDefinitions]; + for (var i = 0; i < viewInfos.Length; i++) + { + viewInfos[i] = new ViewInfo(); + } + + var mocks = new MockRepository(); + var documentViewController = mocks.Stub(); + documentViewController.Expect(r => r.GetViewInfosFor(viewObject)).Return(viewInfos); + var viewController = mocks.Stub(); + viewController.Stub(c => c.DocumentViewController).Return(documentViewController); + var applicationSelection = mocks.Stub(); + var pluginsHost = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new ViewCommandHandler(viewController, applicationSelection, pluginsHost); + + // Call + bool hasViewDefinitionsForData = commandHandler.CanOpenViewFor(viewObject); + + // Assert + Assert.IsTrue(hasViewDefinitionsForData); + mocks.VerifyAll(); + } + + [Test] + public void OpenView_OpenViewDialogForSelection() + { + // Setup + var viewObject = new object(); + + var mocks = new MockRepository(); + var documentViewController = mocks.Stub(); + documentViewController.Expect(r => r.OpenViewForData(viewObject)).Return(true); + var viewController = mocks.Stub(); + viewController.Stub(c => c.DocumentViewController).Return(documentViewController); + var applicationSelection = mocks.Stub(); + var pluginsHost = mocks.Stub(); + mocks.ReplayAll(); + + var commandHandler = new ViewCommandHandler(viewController, applicationSelection, pluginsHost); + + // Call + commandHandler.OpenView(viewObject); + + // Assert + mocks.VerifyAll(); // Expect open view method is called + } + + [Test] + public void RemoveAllViewsForItem_DataObjectNull_DoNothing() + { + // Setup + var mocks = new MockRepository(); + var viewController = mocks.StrictMock(); + var applicationSelection = mocks.StrictMock(); + var pluginsHost = mocks.StrictMock(); + mocks.ReplayAll(); + + var commandHandler = new ViewCommandHandler(viewController, applicationSelection, pluginsHost); + + // Call + commandHandler.RemoveAllViewsForItem(null); + + // Assert + mocks.VerifyAll(); // Expect no calls on mocks + } + + [Test] + public void RemoveAllViewsForItem_DocumentViewsListNull_DoNothing() + { + // Setup + var mocks = new MockRepository(); + var viewController = mocks.StrictMock(); + viewController.Expect(c => c.ViewHost).Return(null); + var applicationSelection = mocks.StrictMock(); + var pluginsHost = mocks.StrictMock(); + mocks.ReplayAll(); + + var commandHandler = new ViewCommandHandler(viewController, applicationSelection, pluginsHost); + + // Call + commandHandler.RemoveAllViewsForItem(new object()); + + // Assert + mocks.VerifyAll(); // Expect no calls on mocks + } + + [Test] + public void RemoveAllViewsForItem_GuiHasDocumentViews_CloseViewForDataAndChildren() + { + // Setup + var data = new object(); + var childData = new object(); + + var mocks = new MockRepository(); + var documentViewsResolver = mocks.StrictMock(); + documentViewsResolver.Expect(vr => vr.CloseAllViewsFor(data)); + documentViewsResolver.Expect(vr => vr.CloseAllViewsFor(childData)); + + var dataView = mocks.Stub(); + dataView.Data = data; + var childDataView = mocks.Stub(); + childDataView.Data = childData; + + var viewsArray = new List + { + dataView, + childDataView + }; + + var viewHost = mocks.StrictMock(); + viewHost.Stub(ws => ws.DocumentViews).Return(viewsArray); + + var applicationSelection = mocks.Stub(); + var pluginsHost = mocks.Stub(); + pluginsHost.Expect(g => g.GetAllDataWithViewDefinitionsRecursively(data)).Return(new[] + { + childData + }); + var viewController = mocks.Stub(); + viewController.Stub(g => g.ViewHost).Return(viewHost); + viewController.Stub(g => g.DocumentViewController).Return(documentViewsResolver); + mocks.ReplayAll(); + + var viewCommandHandler = new ViewCommandHandler(viewController, applicationSelection, pluginsHost); + + // Call + viewCommandHandler.RemoveAllViewsForItem(data); + + // Assert + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/ContextMenu/ContextMenuBuilderExceptionTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/ContextMenu/ContextMenuBuilderExceptionTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/ContextMenu/ContextMenuBuilderExceptionTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,32 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Common.TestUtil; +using Core.Gui.ContextMenu; +using NUnit.Framework; + +namespace Core.Gui.Test.ContextMenu +{ + [TestFixture] + public class ContextMenuBuilderExceptionTest : + CustomExceptionDesignGuidelinesTestFixture {} +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/ContextMenu/ContextMenuBuilderTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/ContextMenu/ContextMenuBuilderTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/ContextMenu/ContextMenuBuilderTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,1060 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Drawing; +using System.Windows.Forms; +using Core.Common.Controls.TreeView; +using Core.Common.TestUtil; +using Core.Gui.Commands; +using Core.Gui.ContextMenu; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.ContextMenu +{ + [TestFixture] + public class ContextMenuBuilderTest + { + private MockRepository mocks; + + [SetUp] + public void SetUp() + { + mocks = new MockRepository(); + } + + [Test] + public void Constructor_NoApplicationFeatureCommands_ThrowsContextMenuBuilderException() + { + // Setup + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + // Call + void Call() => new ContextMenuBuilder(null, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object(), + treeViewControl); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual(Resources.ContextMenuBuilder_ContextMenuBuilder_Cannot_create_instances_of_factories, exception.Message); + } + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_NoImportCommandHandler_ThrowsContextMenuBuilderException() + { + // Setup + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var applicationFeatureCommands = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + // Call + void Call() => new ContextMenuBuilder(applicationFeatureCommands, + null, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object(), + treeViewControl); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual(Resources.ContextMenuBuilder_ContextMenuBuilder_Cannot_create_instances_of_factories, exception.Message); + } + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_NoExportCommandHandler_ThrowsContextMenuBuilderException() + { + // Setup + var importCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var applicationFeatureCommands = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + // Call + void Call() => new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + null, + updateCommandHandler, + viewCommands, + new object(), + treeViewControl); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual(Resources.ContextMenuBuilder_ContextMenuBuilder_Cannot_create_instances_of_factories, exception.Message); + } + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_NoUpdateCommandHandler_ThrowsContextMenuBuilderException() + { + // Setup + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var applicationFeatureCommands = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + // Call + void Call() => new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + null, + viewCommands, + new object(), + treeViewControl); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual(Resources.ContextMenuBuilder_ContextMenuBuilder_Cannot_create_instances_of_factories, exception.Message); + } + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_NoViewCommands_ThrowsContextMenuBuilderException() + { + // Setup + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + // Call + void Call() => new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + null, + new object(), + treeViewControl); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual(Resources.ContextMenuBuilder_ContextMenuBuilder_Cannot_create_instances_of_factories, exception.Message); + } + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_NoDataObject_ThrowsContextMenuBuilderException() + { + // Setup + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + // Call + void Call() => new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + null, + treeViewControl); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual(Resources.ContextMenuBuilder_ContextMenuBuilder_Cannot_create_instances_of_factories, exception.Message); + } + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_NoTreeViewControl_ThrowsContextMenuBuilderException() + { + // Setup + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + + // Call + void Call() => new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object(), + null); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual(Resources.ContextMenuBuilder_ContextMenuBuilder_Cannot_create_instances_of_factories, exception.Message); + } + + [Test] + public void Constructor_ParamsSet_DoesNotThrow() + { + // Setup + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + // Call + void Call() => new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object(), + treeViewControl); + + // Assert + Assert.DoesNotThrow(Call); + } + + mocks.VerifyAll(); + } + + [Test] + public void Build_NothingAdded_EmptyContextMenu() + { + // Setup + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object(), + treeViewControl); + + // Call + ContextMenuStrip result = builder.Build(); + + // Assert + Assert.IsInstanceOf(result); + CollectionAssert.IsEmpty(result.Items); + } + + mocks.VerifyAll(); + } + + [Test] + public void AddRenameItem_WhenBuild_ItemAddedToContextMenu() + { + // Setup + var dataObject = new object(); + using (var treeViewControl = new TreeViewControl()) + { + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var treeNodeInfo = mocks.StrictMock>(); + mocks.ReplayAll(); + + treeNodeInfo.CanRename = (data, parentData) => data == dataObject; + treeViewControl.RegisterTreeNodeInfo(treeNodeInfo); + treeViewControl.Data = dataObject; + + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + dataObject, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddRenameItem().Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, Resources.Rename, Resources.Rename_ToolTip, Resources.RenameIcon); + + mocks.VerifyAll(); + } + } + + [Test] + public void AddDeleteItem_WhenBuild_ItemAddedToContextMenu() + { + // Setup + const string nodeData = "string"; + var parentData = new object(); + using (var treeViewControl = new TreeViewControl()) + { + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var treeNodeInfo = mocks.StrictMock>(); + var parentTreeNodeInfo = mocks.StrictMock>(); + mocks.ReplayAll(); + + treeNodeInfo.CanRemove = (nd, pnd) => nd == nodeData && pnd == parentData; + parentTreeNodeInfo.ChildNodeObjects = nd => new object[] + { + nodeData + }; + + treeViewControl.RegisterTreeNodeInfo(treeNodeInfo); + treeViewControl.RegisterTreeNodeInfo(parentTreeNodeInfo); + + treeViewControl.Data = parentData; + + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddDeleteItem().Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, Resources.Delete, Resources.Delete_ToolTip, Resources.DeleteIcon); + + mocks.VerifyAll(); + } + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddRemoveAllChildrenItem_WhenBuild_ItemAddedToContextMenu(bool hasChildren) + { + // Setup + var dataObject = new object(); + var applicationFeatureCommands = mocks.Stub(); + var importCommandHandler = mocks.Stub(); + var exportCommandHandler = mocks.Stub(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.Stub(); + var treeViewControl = mocks.StrictMock(); + treeViewControl.Expect(tvc => tvc.CanRemoveChildNodesOfData(dataObject)).Return(hasChildren).Repeat.AtLeastOnce(); + + mocks.ReplayAll(); + + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + dataObject, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddDeleteChildrenItem().Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + string expectedTooltip = hasChildren + ? "Verwijder alle onderliggende elementen van dit element." + : "Er zijn geen onderliggende elementen om te verwijderen."; + TestHelper.AssertContextMenuStripContainsItem(result, 0, + "Ma&p leegmaken...", + expectedTooltip, + Resources.DeleteChildrenIcon, + hasChildren); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddExpandAllItem_WhenBuild_ItemAddedToContextMenu(bool hasChildren) + { + // Setup + var dataObject = new object(); + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + + treeViewControl.Expect(tvc => tvc.CanExpandOrCollapseForData(dataObject)).Return(hasChildren); + + mocks.ReplayAll(); + + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + dataObject, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddExpandAllItem().Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, Resources.Expand_all, Resources.Expand_all_ToolTip, Resources.ExpandAllIcon, hasChildren); + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddCollapseAllItem_WhenBuild_ItemAddedToContextMenu(bool hasChildren) + { + // Setup + var dataObject = new object(); + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + + treeViewControl.Expect(tvc => tvc.CanExpandOrCollapseForData(dataObject)).Return(hasChildren); + + mocks.ReplayAll(); + + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + dataObject, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddCollapseAllItem().Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, Resources.Collapse_all, Resources.Collapse_all_ToolTip, Resources.CollapseAllIcon, hasChildren); + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddOpenItem_WhenBuild_ItemAddedToContextMenu(bool hasViewForNodeData) + { + // Setup + var nodeData = new object(); + + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + viewCommands.Expect(ch => ch.CanOpenViewFor(nodeData)).Return(hasViewForNodeData); + + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddOpenItem().Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, Resources.Open, Resources.Open_ToolTip, Resources.OpenIcon, hasViewForNodeData); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddExportItem_WhenBuild_ItemAddedToContextMenu(bool hasExportersForNodeData) + { + // Setup + var nodeData = new object(); + + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + exportCommandHandler.Expect(ch => ch.CanExportFrom(nodeData)).Return(hasExportersForNodeData); + + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddExportItem().Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, Resources.Export, Resources.Export_ToolTip, Resources.ExportIcon, hasExportersForNodeData); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddImportItemWithoutParameters_WhenBuild_ItemAddedToContextMenu(bool hasImportersForNodeData) + { + // Setup + var nodeData = new object(); + + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + importCommandHandler.Expect(ch => ch.GetSupportedImportInfos(nodeData)) + .Return(hasImportersForNodeData + ? new[] + { + new ImportInfo() + } + : new ImportInfo[0]); + + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddImportItem().Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, Resources.Import, Resources.Import_ToolTip, Resources.ImportIcon, hasImportersForNodeData); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddImportItemWithImportInfosParameter_WhenBuild_ItemAddedToContextMenu(bool hasImportersForNodeData) + { + // Setup + var nodeData = new object(); + + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + + mocks.ReplayAll(); + + ImportInfo[] importInfos = hasImportersForNodeData + ? new[] + { + new ImportInfo() + } + : new ImportInfo[0]; + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddImportItem(importInfos).Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, Resources.Import, Resources.Import_ToolTip, Resources.ImportIcon, hasImportersForNodeData); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddImportItemWithTextualParameters_WhenBuild_ItemAddedToContextMenu(bool hasImportersForNodeData) + { + // Setup + const string text = "import"; + const string toolTip = "import tooltip"; + Image image = Resources.ImportIcon; + + var nodeData = new object(); + + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + importCommandHandler.Expect(ch => ch.GetSupportedImportInfos(nodeData)) + .Return(hasImportersForNodeData + ? new[] + { + new ImportInfo() + } + : new ImportInfo[0]); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddImportItem(text, toolTip, image).Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, text, toolTip, image, hasImportersForNodeData); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddImportItemWithAllParameters_WhenBuild_ItemAddedToContextMenu(bool hasImportersForNodeData) + { + // Setup + const string text = "import"; + const string toolTip = "import tooltip"; + Image image = Resources.ImportIcon; + + var nodeData = new object(); + + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + + mocks.ReplayAll(); + + ImportInfo[] importInfos = hasImportersForNodeData + ? new[] + { + new ImportInfo() + } + : new ImportInfo[0]; + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddImportItem(text, toolTip, image, importInfos).Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, text, toolTip, image, hasImportersForNodeData); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddUpdateItem_WhenBuild_ItemAddedToContextMenu(bool hasUpdatesForNodeData) + { + // Setup + var nodeData = new object(); + + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + updateCommandHandler.Expect(ch => ch.CanUpdateOn(nodeData)).Return(hasUpdatesForNodeData); + + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddUpdateItem().Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, Resources.Update, Resources.Update_ToolTip, Resources.RefreshIcon, hasUpdatesForNodeData); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void AddPropertiesItem_WhenBuild_ItemAddedToContextMenu(bool hasPropertiesForNodeData) + { + // Setup + var nodeData = new object(); + + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + applicationFeatureCommands.Expect(ch => ch.CanShowPropertiesFor(nodeData)).Return(hasPropertiesForNodeData); + + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData, + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddPropertiesItem().Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + TestHelper.AssertContextMenuStripContainsItem(result, 0, Resources.Properties, Resources.Properties_ToolTip, Resources.PropertiesHS, hasPropertiesForNodeData); + } + + mocks.VerifyAll(); + } + + [Test] + public void AddCustomItem_WhenBuild_ItemAddedToContextMenu() + { + // Setup + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, exportCommandHandler, + updateCommandHandler, + viewCommands, + new object(), + treeViewControl); + var item = new StrictContextMenuItem(null, null, null, null); + + // Call + ContextMenuStrip result = builder.AddCustomItem(item).Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + Assert.AreSame(item, result.Items[0]); + } + + mocks.VerifyAll(); + } + + [Test] + public void AddSeparator_NoOtherItemsWhenBuild_EmptyContextMenu() + { + // Setup + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object(), + treeViewControl); + + // Call + ContextMenuStrip result = builder.AddSeparator().Build(); + + // Assert + Assert.IsInstanceOf(result); + CollectionAssert.IsEmpty(result.Items); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(1)] + [TestCase(10)] + public void AddSeparator_SeparatorAddedAtStart_SeparatorsNotAdded(int count) + { + // Setup + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object(), + treeViewControl); + + var someItem = new StrictContextMenuItem(null, null, null, null); + + // Call + for (var i = 0; i < count; i++) + { + builder.AddSeparator(); + } + + ContextMenuStrip result = builder.AddCustomItem(someItem).Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + + Assert.IsInstanceOf(result.Items[0]); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(1)] + [TestCase(10)] + public void AddSeparator_SeparatorsAddedInBetweenItems_OneSeparatorAdded(int count) + { + // Setup + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object(), + treeViewControl); + + var someItem = new StrictContextMenuItem(null, null, null, null); + var someOtherItem = new StrictContextMenuItem(null, null, null, null); + + builder.AddCustomItem(someItem); + + // Call + for (var i = 0; i < count; i++) + { + builder.AddSeparator(); + } + + ContextMenuStrip result = builder.AddCustomItem(someOtherItem).Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(3, result.Items.Count); + + Assert.IsInstanceOf(result.Items[1]); + Assert.IsInstanceOf(result.Items[2]); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(1)] + [TestCase(10)] + public void AddSeparator_SeparatorsAddedAtEnd_SeparatorsNotAdded(int count) + { + // Setup + var applicationFeatureCommands = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var treeViewControl = new TreeViewControl()) + { + var builder = new ContextMenuBuilder(applicationFeatureCommands, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object(), + treeViewControl); + + builder.AddCustomItem(new StrictContextMenuItem(null, null, null, null)); + + // Call + for (var i = 0; i < count; i++) + { + builder.AddSeparator(); + } + + ContextMenuStrip result = builder.Build(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(1, result.Items.Count); + } + + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/ContextMenu/GuiContextMenuItemFactoryTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/ContextMenu/GuiContextMenuItemFactoryTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/ContextMenu/GuiContextMenuItemFactoryTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,1047 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using Core.Common.TestUtil; +using Core.Gui.Commands; +using Core.Gui.ContextMenu; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.ContextMenu +{ + [TestFixture] + public class ContextMenuItemFactoryTest + { + private MockRepository mocks; + + [SetUp] + public void SetUp() + { + mocks = new MockRepository(); + } + + [Test] + public void Constructor_WithoutApplicationFeatureCommandHandler_ThrowsArgumentNullException() + { + // Setup + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + + mocks.ReplayAll(); + + // Call + void Call() => new GuiContextMenuItemFactory(null, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object()); + + // Assert + var exception = Assert.Throws(Call); + StringAssert.StartsWith($"Kan geen '{nameof(ApplicationFeatureCommandHandler)}'-afhankelijk element " + + $"in het contextmenu creëren zonder een '{nameof(ApplicationFeatureCommandHandler)}'.", + exception.Message); + StringAssert.EndsWith("applicationFeatureCommandHandler", exception.Message); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_WithoutImportCommandHandler_ThrowsArgumentNullException() + { + // Setup + var applicationFeatureCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + + mocks.ReplayAll(); + + // Call + void Call() => new GuiContextMenuItemFactory(applicationFeatureCommandHandler, + null, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object()); + + // Assert + var exception = Assert.Throws(Call); + StringAssert.StartsWith($"Kan geen '{nameof(IImportCommandHandler)}'-afhankelijk element " + + $"in het contextmenu creëren zonder een '{nameof(IImportCommandHandler)}'.", + exception.Message); + StringAssert.EndsWith("importCommandHandler", exception.Message); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_WithoutExportCommandHandler_ThrowsArgumentNullException() + { + // Setup + var applicationFeatureCommandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + + mocks.ReplayAll(); + + // Call + void Call() => new GuiContextMenuItemFactory(applicationFeatureCommandHandler, + importCommandHandler, + null, + updateCommandHandler, + viewCommands, + new object()); + + // Assert + var exception = Assert.Throws(Call); + StringAssert.StartsWith($"Kan geen '{nameof(IExportCommandHandler)}'-afhankelijk element " + + $"in het contextmenu creëren zonder een '{nameof(IExportCommandHandler)}'.", + exception.Message); + StringAssert.EndsWith("exportCommandHandler", exception.Message); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_WithoutUpdateCommandHandler_ThrowsArgumentNullException() + { + // Setup + var applicationFeatureCommandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + + mocks.ReplayAll(); + + // Call + void Call() => new GuiContextMenuItemFactory(applicationFeatureCommandHandler, + importCommandHandler, + exportCommandHandler, + null, + viewCommands, + new object()); + + // Assert + var exception = Assert.Throws(Call); + StringAssert.StartsWith($"Kan geen '{nameof(IUpdateCommandHandler)}'-afhankelijk element " + + $"in het contextmenu creëren zonder een '{nameof(IUpdateCommandHandler)}'.", + exception.Message); + StringAssert.EndsWith("updateCommandHandler", exception.Message); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_WithoutViewCommandsHandler_ThrowsArgumentNullException() + { + // Setup + var applicationFeatureCommandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + + mocks.ReplayAll(); + + // Call + void Call() => new GuiContextMenuItemFactory(applicationFeatureCommandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + null, + new object()); + + // Assert + var exception = Assert.Throws(Call); + StringAssert.StartsWith($"Kan geen '{nameof(IViewCommands)}'-afhankelijk element " + + $"in het contextmenu creëren zonder een '{nameof(IViewCommands)}'.", + exception.Message); + StringAssert.EndsWith("viewCommandsHandler", exception.Message); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_WithoutDataObject_ThrowsArgumentNullException() + { + // Setup + var applicationFeatureCommandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + + mocks.ReplayAll(); + + // Call + void Call() => new GuiContextMenuItemFactory(applicationFeatureCommandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + null); + + // Assert + var exception = Assert.Throws(Call); + StringAssert.StartsWith("Kan geen element in het contextmenu creëren zonder dat de data bekend is.", exception.Message); + StringAssert.EndsWith("dataObject", exception.Message); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_ValidInputParameters_DoesNotThrow() + { + // Setup + var applicationFeatureCommandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + + mocks.ReplayAll(); + + // Call + void Call() => new GuiContextMenuItemFactory(applicationFeatureCommandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + new object()); + + // Assert + Assert.DoesNotThrow(Call); + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateOpenItem_Always_ItemWithPropertiesSet(bool canOpenView) + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + viewCommands.Expect(ch => ch.CanOpenViewFor(nodeData)).Return(canOpenView); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + ToolStripItem item = contextMenuFactory.CreateOpenItem(); + + // Assert + Assert.AreEqual("&Openen", item.Text); + Assert.AreEqual("Open de gegevens in een nieuw documentvenster.", item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.OpenIcon, item.Image); + Assert.AreEqual(canOpenView, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + public void CreateOpenItem_CanOpenView_CausesViewToOpenWhenClicked() + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + viewCommands.Expect(ch => ch.CanOpenViewFor(nodeData)).Return(true); + viewCommands.Expect(ch => ch.OpenView(nodeData)); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + ToolStripItem item = contextMenuFactory.CreateOpenItem(); + + // Call + item.PerformClick(); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateExportItem_Always_ItemWithPropertiesSet(bool hasExportersForNodeData) + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + exportCommandHandler.Expect(ch => ch.CanExportFrom(nodeData)).Return(hasExportersForNodeData); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + ToolStripItem item = contextMenuFactory.CreateExportItem(); + + // Assert + Assert.AreEqual("&Exporteren...", item.Text); + Assert.AreEqual("Exporteer de gegevens naar een bestand.", item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.ExportIcon, item.Image); + Assert.AreEqual(hasExportersForNodeData, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + public void CreateExportItem_CanExportFrom_CausesExportToStartWhenClicked() + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + exportCommandHandler.Expect(ch => ch.CanExportFrom(nodeData)).Return(true); + exportCommandHandler.Expect(ch => ch.ExportFrom(nodeData)); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + ToolStripItem item = contextMenuFactory.CreateExportItem(); + + // Call + item.PerformClick(); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateImportItemWithoutParameters_Always_ItemWithPropertiesSet(bool hasImportersForNodeData) + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + importCommandHandler.Expect(ich => ich.GetSupportedImportInfos(nodeData)).Return(hasImportersForNodeData + ? new[] + { + new ImportInfo() + } + : new ImportInfo[0]); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + ToolStripItem item = contextMenuFactory.CreateImportItem(); + + // Assert + Assert.AreEqual("&Importeren...", item.Text); + Assert.AreEqual("Importeer de gegevens vanuit een bestand.", item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.ImportIcon, item.Image); + Assert.AreEqual(hasImportersForNodeData, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + public void CreateImportItemWithoutParameters_SupportedImportInfo_CausesImportToStartWhenClicked() + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + ImportInfo[] importInfos = + { + new ImportInfo() + }; + + importCommandHandler.Expect(ich => ich.GetSupportedImportInfos(nodeData)).Return(importInfos); + importCommandHandler.Expect(ich => ich.ImportOn(nodeData, importInfos)); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + ToolStripItem item = contextMenuFactory.CreateImportItem(); + + // Call + item.PerformClick(); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateImportItemWithImportInfosParameter_Always_ItemWithPropertiesSet(bool hasImportersForNodeData) + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + mocks.ReplayAll(); + + ImportInfo[] importInfos = hasImportersForNodeData + ? new[] + { + new ImportInfo() + } + : new ImportInfo[0]; + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + ToolStripItem item = contextMenuFactory.CreateImportItem(importInfos); + + // Assert + Assert.AreEqual("&Importeren...", item.Text); + Assert.AreEqual("Importeer de gegevens vanuit een bestand.", item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.ImportIcon, item.Image); + Assert.AreEqual(hasImportersForNodeData, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + public void CreateImportItemWithImportInfosParameter_SupportedImportInfo_CausesImportToStartWhenClicked() + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + ImportInfo[] importInfos = + { + new ImportInfo() + }; + + importCommandHandler.Expect(ich => ich.ImportOn(nodeData, importInfos)); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + ToolStripItem item = contextMenuFactory.CreateImportItem(importInfos); + + // Call + item.PerformClick(); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [TestCase(null)] + [TestCase("")] + [TestCase(" ")] + public void CreateImportItemWithTextualParameters_InvalidTextParameter_ThrowArgumentException(string text) + { + // Setup + const string toolTip = "Import tooltip"; + Image image = Resources.ImportIcon; + + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + void Call() => contextMenuFactory.CreateImportItem(text, toolTip, image); + + // Assert + var exception = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(Call, "Text should be set."); + Assert.AreEqual("text", exception.ParamName); + + mocks.VerifyAll(); + } + + [Test] + public void CreateImportItemWithTextualParameters_TooltipParameterNull_ThrowArgumentNullException() + { + // Setup + const string text = "Import"; + Image image = Resources.ImportIcon; + + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + void Call() => contextMenuFactory.CreateImportItem(text, null, image); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("toolTip", exception.ParamName); + + mocks.VerifyAll(); + } + + [Test] + public void CreateImportItemWithTextualParameters_ImageParameterNull_ThrowArgumentNullException() + { + // Setup + const string text = "Import"; + const string toolTip = "Import tooltip"; + + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + void Call() => contextMenuFactory.CreateImportItem(text, toolTip, null); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("image", exception.ParamName); + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateImportItemWithTextualParameters_Always_ItemWithPropertiesSet(bool hasImportersForNodeData) + { + // Setup + const string text = "Import"; + const string toolTip = "Import tooltip"; + Image image = Resources.ImportIcon; + + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + importCommandHandler.Expect(ich => ich.GetSupportedImportInfos(nodeData)).Return(hasImportersForNodeData + ? new[] + { + new ImportInfo() + } + : new ImportInfo[0]); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + ToolStripItem item = contextMenuFactory.CreateImportItem(text, toolTip, image); + + // Assert + Assert.AreEqual(text, item.Text); + Assert.AreEqual(toolTip, item.ToolTipText); + TestHelper.AssertImagesAreEqual(image, item.Image); + Assert.AreEqual(hasImportersForNodeData, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + public void CreateImportItemWithTextualParameters_SupportedImportInfo_CausesImportToStartWhenClicked() + { + // Setup + const string text = "Import"; + const string toolTip = "Import tooltip"; + Image image = Resources.ImportIcon; + + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + ImportInfo[] importInfos = + { + new ImportInfo() + }; + + importCommandHandler.Expect(ich => ich.GetSupportedImportInfos(nodeData)).Return(importInfos); + importCommandHandler.Expect(ich => ich.ImportOn(nodeData, importInfos)); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + ToolStripItem item = contextMenuFactory.CreateImportItem(text, toolTip, image); + + // Call + item.PerformClick(); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [TestCase(null)] + [TestCase("")] + [TestCase(" ")] + public void CreateImportItemWithAllParameters_InvalidTextParameter_ThrowArgumentException(string text) + { + // Setup + const string toolTip = "Import tooltip"; + Image image = Resources.ImportIcon; + + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + void Call() => contextMenuFactory.CreateImportItem(text, toolTip, image, Enumerable.Empty()); + + // Assert + var exception = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(Call, "Text should be set."); + Assert.AreEqual("text", exception.ParamName); + + mocks.VerifyAll(); + } + + [Test] + public void CreateImportItemWithAllParameters_TooltipParameterNull_ThrowArgumentNullException() + { + // Setup + const string text = "Import"; + Image image = Resources.ImportIcon; + + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + void Call() => contextMenuFactory.CreateImportItem(text, null, image, Enumerable.Empty()); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("toolTip", exception.ParamName); + + mocks.VerifyAll(); + } + + [Test] + public void CreateImportItemWithAllParameters_ImageParameterNull_ThrowArgumentNullException() + { + // Setup + const string text = "Import"; + const string toolTip = "Import tooltip"; + + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + void Call() => contextMenuFactory.CreateImportItem(text, toolTip, null, Enumerable.Empty()); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("image", exception.ParamName); + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateImportItemWithAllParameters_Always_ItemWithPropertiesSet(bool hasImportersForNodeData) + { + // Setup + const string text = "Import"; + const string toolTip = "Import tooltip"; + Image image = Resources.ImportIcon; + + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + mocks.ReplayAll(); + + ImportInfo[] importInfos = hasImportersForNodeData + ? new[] + { + new ImportInfo() + } + : new ImportInfo[0]; + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + ToolStripItem item = contextMenuFactory.CreateImportItem(text, toolTip, image, importInfos); + + // Assert + Assert.AreEqual(text, item.Text); + Assert.AreEqual(toolTip, item.ToolTipText); + TestHelper.AssertImagesAreEqual(image, item.Image); + Assert.AreEqual(hasImportersForNodeData, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + public void CreateImportItemWithAllParameters_SupportedImportInfo_CausesImportToStartWhenClicked() + { + // Setup + const string text = "Import"; + const string toolTip = "Import tooltip"; + Image image = Resources.ImportIcon; + + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + ImportInfo[] importInfos = + { + new ImportInfo() + }; + + importCommandHandler.Expect(ich => ich.ImportOn(nodeData, importInfos)); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + ToolStripItem item = contextMenuFactory.CreateImportItem(text, toolTip, image, importInfos); + + // Call + item.PerformClick(); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateUpdateItem_Always_ItemWithPropertiesSet(bool canUpdateOn) + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + updateCommandHandler.Expect(ch => ch.CanUpdateOn(nodeData)).Return(canUpdateOn); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + // Call + ToolStripItem item = contextMenuFactory.CreateUpdateItem(); + + // Assert + Assert.AreEqual("&Bijwerken...", item.Text); + Assert.AreEqual("Werk de geïmporteerde gegevens bij met nieuwe gegevens vanuit een bestand.", item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.RefreshIcon, item.Image); + Assert.AreEqual(canUpdateOn, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + public void CreateUpdateItem_CanUpdateOn_CausesUpdateToStartWhenClicked() + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + updateCommandHandler.Expect(ch => ch.CanUpdateOn(nodeData)).Return(true); + updateCommandHandler.Expect(ch => ch.UpdateOn(nodeData)); + + mocks.ReplayAll(); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + ToolStripItem item = contextMenuFactory.CreateUpdateItem(); + + // Call + item.PerformClick(); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreatePropertiesItem_Always_ItemWithPropertiesSet(bool hasPropertyInfoForNodeData) + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + commandHandler.Expect(ch => ch.CanShowPropertiesFor(nodeData)).Return(hasPropertyInfoForNodeData); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + mocks.ReplayAll(); + + // Call + ToolStripItem item = contextMenuFactory.CreatePropertiesItem(); + + // Assert + Assert.AreEqual("Ei&genschappen", item.Text); + Assert.AreEqual("Toon de eigenschappen in het Eigenschappenpaneel.", item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.PropertiesHS, item.Image); + Assert.AreEqual(hasPropertyInfoForNodeData, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + public void CreatePropertiesItem_CanShowPropertiesFor_CausesPropertiesToBeShownWhenClicked() + { + // Setup + var commandHandler = mocks.StrictMock(); + var importCommandHandler = mocks.StrictMock(); + var exportCommandHandler = mocks.StrictMock(); + var updateCommandHandler = mocks.StrictMock(); + var viewCommands = mocks.StrictMock(); + var nodeData = new object(); + + commandHandler.Expect(ch => ch.CanShowPropertiesFor(nodeData)).Return(true); + commandHandler.Expect(ch => ch.ShowPropertiesForSelection()); + + var contextMenuFactory = new GuiContextMenuItemFactory(commandHandler, + importCommandHandler, + exportCommandHandler, + updateCommandHandler, + viewCommands, + nodeData); + + mocks.ReplayAll(); + + ToolStripItem item = contextMenuFactory.CreatePropertiesItem(); + + // Call + item.PerformClick(); + + // Assert + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/ContextMenu/StrictContextMenuItemTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/ContextMenu/StrictContextMenuItemTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/ContextMenu/StrictContextMenuItemTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,64 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Drawing; +using Core.Common.TestUtil; +using Core.Gui.ContextMenu; +using Core.Gui.Properties; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.ContextMenu +{ + [TestFixture] + public class StrictContextMenuItemTest + { + [Test] + public void Constructor_WithParameters_PropertiesSet() + { + // Setup + var mockRepository = new MockRepository(); + + const string text = "text"; + const string toolTip = "tooltip"; + Bitmap image = Resources.ImportIcon; + var counter = 0; + + mockRepository.ReplayAll(); + + EventHandler handler = (s, e) => counter++; + + // Call + var result = new StrictContextMenuItem(text, toolTip, image, handler); + result.PerformClick(); + + // Assert + Assert.IsInstanceOf(result); + Assert.AreEqual(text, result.Text); + Assert.AreEqual(toolTip, result.ToolTipText); + Assert.AreEqual(1, counter); + TestHelper.AssertImagesAreEqual(image, result.Image); + + mockRepository.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/ContextMenu/TreeViewContextMenuItemFactoryTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/ContextMenu/TreeViewContextMenuItemFactoryTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/ContextMenu/TreeViewContextMenuItemFactoryTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,260 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Windows.Forms; +using Core.Common.Controls.TreeView; +using Core.Common.TestUtil; +using Core.Gui.ContextMenu; +using Core.Gui.Properties; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.ContextMenu +{ + [TestFixture] + public class TreeViewContextMenuItemFactoryTest : NUnitFormTest + { + private MockRepository mocks; + + [Test] + public void Constructor_WithoutDataObject_ThrowsArgumentNullException() + { + // Setup + using (var treeViewControl = new TreeViewControl()) + { + // Call + TestDelegate test = () => new TreeViewContextMenuItemFactory(null, treeViewControl); + + // Assert + string message = Assert.Throws(test).Message; + StringAssert.StartsWith(Resources.ContextMenuItemFactory_Can_not_create_context_menu_items_without_data, message); + StringAssert.EndsWith("dataObject", message); + } + } + + [Test] + public void Constructor_WithoutTreeViewControl_ThrowsArgumentNullException() + { + // Call + TestDelegate test = () => new TreeViewContextMenuItemFactory(new object(), null); + + // Assert + string message = Assert.Throws(test).Message; + StringAssert.StartsWith(Resources.ContextMenuItemFactory_Can_not_create_context_menu_items_without_tree_view_control, message); + StringAssert.EndsWith("treeViewControl", message); + } + + [Test] + public void Constructor_WithAllInput_DoesNotThrow() + { + // Setup + using (var treeViewControl = new TreeViewControl()) + { + // Call + TestDelegate test = () => new TreeViewContextMenuItemFactory(new object(), treeViewControl); + + // Assert + Assert.DoesNotThrow(test); + } + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateDeleteItem_DependingOnCanRemoveNodeForData_ItemWithDeleteFunctionWillBeEnabled(bool canDelete) + { + // Setup + var treeViewControl = mocks.StrictMock(); + + var nodeData = new object(); + + treeViewControl.Expect(tvc => tvc.CanRemoveNodeForData(nodeData)).Return(canDelete); + + if (canDelete) + { + treeViewControl.Expect(tvc => tvc.TryRemoveNodeForData(nodeData)); + } + + mocks.ReplayAll(); + + var factory = new TreeViewContextMenuItemFactory(nodeData, treeViewControl); + + // Call + ToolStripItem item = factory.CreateDeleteItem(); + item.PerformClick(); + + // Assert + Assert.AreEqual(Resources.Delete, item.Text); + Assert.AreEqual(Resources.Delete_ToolTip, item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.DeleteIcon, item.Image); + Assert.AreEqual(canDelete, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateDeleteChildrenItem_DependingOnCanRemoveChildNodesOfData_ItemWithDeleteChildrenFunctionWillBeEnabled(bool canDelete) + { + // Setup + var nodeData = new object(); + var treeViewControl = mocks.StrictMock(); + treeViewControl.Expect(tvc => tvc.CanRemoveChildNodesOfData(nodeData)).Return(canDelete).Repeat.AtLeastOnce(); + + if (canDelete) + { + treeViewControl.Expect(tvc => tvc.TryRemoveChildNodesOfData(nodeData)); + } + + mocks.ReplayAll(); + + var factory = new TreeViewContextMenuItemFactory(nodeData, treeViewControl); + + // Call + ToolStripItem item = factory.CreateDeleteChildrenItem(); + item.PerformClick(); + + // Assert + Assert.AreEqual(Resources.DeleteChildren, item.Text); + string expectedTooltip = canDelete + ? "Verwijder alle onderliggende elementen van dit element." + : "Er zijn geen onderliggende elementen om te verwijderen."; + Assert.AreEqual(expectedTooltip, item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.DeleteChildrenIcon, item.Image); + Assert.AreEqual(canDelete, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateRenameItem_DependingOnCanRenameNodeForData_ItemWithDeleteFunctionWillBeEnabled(bool canRename) + { + // Setup + var dataObject = new object(); + var treeViewControl = mocks.StrictMock(); + + treeViewControl.Expect(tvc => tvc.CanRenameNodeForData(dataObject)).Return(canRename); + + if (canRename) + { + treeViewControl.Expect(tvc => tvc.TryRenameNodeForData(dataObject)); + } + + mocks.ReplayAll(); + + var factory = new TreeViewContextMenuItemFactory(dataObject, treeViewControl); + + // Call + ToolStripItem item = factory.CreateRenameItem(); + item.PerformClick(); + + // Assert + Assert.AreEqual(Resources.Rename, item.Text); + Assert.AreEqual(Resources.Rename_ToolTip, item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.RenameIcon, item.Image); + Assert.AreEqual(canRename, item.Enabled); + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateExpandAllItem_DependingOnCanExpandOrCollapseForData_ItemWithExpandFunctionWillBeEnabled(bool hasChildren) + { + // Setup + const string dataObject = "string"; + var treeNodeInfo = new TreeNodeInfo(); + var childTreeNodeInfo = new TreeNodeInfo(); + var treeViewControl = new TreeViewControl(); + + if (hasChildren) + { + treeNodeInfo.ChildNodeObjects = o => new object[] + { + 10.0 + }; + } + + var factory = new TreeViewContextMenuItemFactory(dataObject, treeViewControl); + + treeViewControl.RegisterTreeNodeInfo(treeNodeInfo); + treeViewControl.RegisterTreeNodeInfo(childTreeNodeInfo); + treeViewControl.Data = dataObject; + + // Call + ToolStripItem item = factory.CreateExpandAllItem(); + item.PerformClick(); + + // Assert + Assert.AreEqual(Resources.Expand_all, item.Text); + Assert.AreEqual(Resources.Expand_all_ToolTip, item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.ExpandAllIcon, item.Image); + Assert.AreEqual(hasChildren, item.Enabled); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CreateCollapseAllItem_DependingOnCanExpandOrCollapseForData_ItemWithCollapseFunctionWillBeEnabled(bool hasChildren) + { + // Setup + const string dataObject = "string"; + var treeNodeInfo = new TreeNodeInfo(); + var childTreeNodeInfo = new TreeNodeInfo(); + var treeViewControl = new TreeViewControl(); + + if (hasChildren) + { + treeNodeInfo.ChildNodeObjects = o => new object[] + { + 10.0 + }; + } + + var factory = new TreeViewContextMenuItemFactory(dataObject, treeViewControl); + + treeViewControl.RegisterTreeNodeInfo(treeNodeInfo); + treeViewControl.RegisterTreeNodeInfo(childTreeNodeInfo); + treeViewControl.Data = dataObject; + + // Call + ToolStripItem item = factory.CreateCollapseAllItem(); + item.PerformClick(); + + // Assert + Assert.AreEqual(Resources.Collapse_all, item.Text); + Assert.AreEqual(Resources.Collapse_all_ToolTip, item.ToolTipText); + TestHelper.AssertImagesAreEqual(Resources.CollapseAllIcon, item.Image); + Assert.AreEqual(hasChildren, item.Enabled); + } + + public override void Setup() + { + mocks = new MockRepository(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Converters/ColorTypeConverterTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Converters/ColorTypeConverterTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Converters/ColorTypeConverterTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,54 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Drawing; +using Core.Gui.Converters; +using NUnit.Framework; + +namespace Core.Gui.Test.Converters +{ + [TestFixture] + public class ColorTypeConverterTest + { + [Test] + public void Constructor_ExpectedProperties() + { + // Call + var converter = new ColorTypeConverter(); + + // Assert + Assert.IsInstanceOf(converter); + } + + [Test] + public void GetStandardValuesSupported_Always_ReturnFalse() + { + // Setup + var converter = new ColorTypeConverter(); + + // Call + bool standardValuesSupported = converter.GetStandardValuesSupported(null); + + // Assert + Assert.IsFalse(standardValuesSupported); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Converters/ExpandableArrayConverterTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Converters/ExpandableArrayConverterTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Converters/ExpandableArrayConverterTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,152 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.ComponentModel; +using System.Linq; +using Core.Gui.Converters; +using Core.Gui.PropertyBag; +using NUnit.Framework; + +namespace Core.Gui.Test.Converters +{ + [TestFixture] + public class ExpandableArrayConverterTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var converter = new ExpandableArrayConverter(); + + // Assert + Assert.IsInstanceOf(converter); + } + + [Test] + public void ConvertTo_FromArrayToString_ReturnCountText() + { + // Setup + int arrayCount = new Random(21).Next(0, 10); + + var sourceArray = new int[arrayCount]; + var converter = new ExpandableArrayConverter(); + + // Call + object text = converter.ConvertTo(sourceArray, typeof(string)); + + // Assert + Assert.AreEqual($"Aantal ({arrayCount})", text); + } + + [Test] + public void ConvertTo_FromNullToString_ReturnEmptyText() + { + // Setup + var converter = new ExpandableArrayConverter(); + + // Call + object text = converter.ConvertTo(null, typeof(string)); + + // Assert + Assert.AreEqual(string.Empty, text); + } + + [Test] + public void ConvertTo_FromArrayToInt_ThrowsNotSupportedException() + { + // Setup + var sourceArray = new int[1]; + var converter = new ExpandableArrayConverter(); + + // Call + TestDelegate call = () => converter.ConvertTo(sourceArray, typeof(int)); + + // Assert + Assert.Throws(call); + } + + [Test] + public void ConvertTo_FromArrayToNull_ThrowsArgumentNullException() + { + // Setup + var sourceArray = new int[2]; + var converter = new ExpandableArrayConverter(); + + // Call + TestDelegate call = () => converter.ConvertTo(sourceArray, null); + + // Assert + Assert.Throws(call); + } + + [Test] + [TestCase(0)] + [TestCase(1)] + [TestCase(12)] + public void GetProperties_FromArray_ReturnPropertyDescriptorsForEachElementWithNameToOneBasedIndex(int elementCount) + { + // Setup + int[] array = Enumerable.Range(10, elementCount).ToArray(); + + var converter = new ExpandableArrayConverter(); + + // Call + PropertyDescriptorCollection propertyDescriptors = converter.GetProperties(array); + + // Assert + Assert.IsNotNull(propertyDescriptors); + Assert.AreEqual(elementCount, propertyDescriptors.Count); + for (var i = 0; i < elementCount; i++) + { + Assert.AreEqual(array.GetType(), propertyDescriptors[i].ComponentType); + Assert.AreEqual($"[{i + 1}]", propertyDescriptors[i].Name); + Assert.AreEqual($"[{i + 1}]", propertyDescriptors[i].DisplayName); + Assert.AreEqual(typeof(int), propertyDescriptors[i].PropertyType); + CollectionAssert.IsEmpty(propertyDescriptors[i].Attributes); + + var value = propertyDescriptors[i].GetValue(array) as DynamicPropertyBag; + Assert.NotNull(value); + Assert.AreEqual(array[i], value.WrappedObject); + } + } + + [Test] + public void GetProperties_FromArray_SettingValuesShouldUpdateArray() + { + // Setup + const int elementCount = 12; + int[] array = Enumerable.Repeat(10, elementCount).ToArray(); + + var converter = new ExpandableArrayConverter(); + + // Call + PropertyDescriptorCollection propertyDescriptors = converter.GetProperties(array); + for (var i = 0; i < elementCount; i++) + { + propertyDescriptors[i].SetValue(array, i); + } + + // Assert + CollectionAssert.AreEqual(Enumerable.Range(0, elementCount), array); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Converters/ExpandableReadOnlyArrayConverterTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Converters/ExpandableReadOnlyArrayConverterTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Converters/ExpandableReadOnlyArrayConverterTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,62 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.ComponentModel; +using System.Linq; +using Core.Gui.Converters; +using NUnit.Framework; + +namespace Core.Gui.Test.Converters +{ + [TestFixture] + public class ExpandableReadOnlyArrayConverterTest + { + [Test] + public void DefaultConstructor_Always_ExpectedValues() + { + // Call + var converter = new ExpandableReadOnlyArrayConverter(); + + // Assert + Assert.IsInstanceOf(converter); + Assert.IsInstanceOf(converter); + } + + [Test] + public void GetProperties_FromArray_ValuesAreReadOnly() + { + // Setup + const int elementCount = 12; + int[] array = Enumerable.Repeat(10, elementCount).ToArray(); + var converter = new ExpandableReadOnlyArrayConverter(); + + // Call + PropertyDescriptorCollection propertyDescriptors = converter.GetProperties(array); + + // Assert + Assert.IsNotNull(propertyDescriptors); + for (var i = 0; i < elementCount; i++) + { + Assert.IsTrue(propertyDescriptors[i].IsReadOnly); + } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Converters/KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttributeTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Converters/KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttributeTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Converters/KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttributeTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,229 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Common.Base.Data; +using Core.Common.TestUtil; +using Core.Gui.Converters; +using NUnit.Framework; + +namespace Core.Gui.Test.Converters +{ + [TestFixture] + public class KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttributeTest + { + [Test] + public void Constructor_WithoutNamePropertyName_ThrowsArgumentNullException() + { + // Call + void Call() => new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(null, + nameof(TestObject.Unit), + nameof(TestObject.Value)); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("namePropertyName", exception.ParamName); + } + + [Test] + public void Constructor_WithoutUnitPropertyName_ThrowsArgumentNullException() + { + // Call + void Call() => new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(nameof(TestObject.Name), + null, + nameof(TestObject.Value)); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("unitPropertyName", exception.ParamName); + } + + [Test] + public void Constructor_WithoutValuePropertyName_ThrowsArgumentNullException() + { + // Call + void Call() => new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(nameof(TestObject.Name), + nameof(TestObject.Unit), + null); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("valuePropertyName", exception.ParamName); + } + + [Test] + public void Constructor_WithParameters_CreatesNewInstance() + { + // Call + var attribute = new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(nameof(TestObject.Name), + nameof(TestObject.Unit), + nameof(TestObject.Value)); + + // Assert + Assert.IsInstanceOf(attribute); + } + + [Test] + public void GetName_ValidProperties_ReturnsExpectedValue() + { + // Setup + const string expectedName = "expectedName"; + const string expectedUnit = "kN"; + + var attribute = new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(nameof(TestObject.Name), + nameof(TestObject.Unit), + nameof(TestObject.Value)); + + // Call + string name = attribute.GetName(new TestObject + { + Name = expectedName, + Unit = expectedUnit + }); + + // Assert + Assert.AreEqual($"{expectedName} [{expectedUnit}]", name); + } + + [Test] + public void GetName_InvalidNameProperty_ThrowsArgumentException() + { + // Setup + var attribute = new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute("IDoNotExist", + nameof(TestObject.Unit), + nameof(TestObject.Value)); + + // Call + void Call() => attribute.GetName(new TestObject()); + + // Assert + const string expectedMessage = "Name property 'IDoNotExist' was not found on type TestObject."; + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(Call, expectedMessage); + } + + [Test] + public void GetName_InvalidUnitProperty_ThrowsArgumentException() + { + // Setup + var attribute = new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(nameof(TestObject.Name), + "IDoNotExist", + nameof(TestObject.Value)); + + // Call + void Call() => attribute.GetName(new TestObject()); + + // Assert + const string expectedMessage = "Unit property 'IDoNotExist' was not found on type TestObject."; + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(Call, expectedMessage); + } + + [Test] + [SetCulture("nl-NL")] + public void GetValue_WithObjectWithRoundedDoubleProperty_ReturnsValueOfProperty() + { + // Setup + var roundedDoubleValue = new RoundedDouble(5, 5.12345); + var attribute = new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(nameof(TestObject.Name), + nameof(TestObject.Unit), + nameof(TestObject.Value)); + + // Call + string value = attribute.GetValue(new TestObject + { + Value = roundedDoubleValue + }); + + // Assert + const string expectedResult = "5,12345"; + Assert.AreEqual(expectedResult, value); + } + + [Test] + [SetCulture("nl-NL")] + [TestCase(5.0000, "5")] + [TestCase(-2.12000, "-2,12")] + [TestCase(1.24560, "1,2456")] + [TestCase(120, "120")] + public void GetValue_WithObjectWithRoundedDoubleProperty_ReturnsValueOfPropertyWithoutTrailingZeroes(double doubleValue, string expectedResult) + { + // Setup + var roundedDoubleValue = new RoundedDouble(5, doubleValue); + var attribute = new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(nameof(TestObject.Name), + nameof(TestObject.Unit), + nameof(TestObject.Value)); + + // Call + string value = attribute.GetValue(new TestObject + { + Value = roundedDoubleValue + }); + + // Assert + Assert.AreEqual(expectedResult, value); + } + + [Test] + public void GetValue_WithObjectWithNonStringProperty_ThrowsArgumentException() + { + // Setup + int expectedValue = new Random(21).Next(3, 50); + + var attribute = new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(nameof(TestObject.Name), + nameof(TestObject.Unit), + nameof(TestObject.NonRoundedDoubleValue)); + + // Call + void Call() => + attribute.GetValue(new TestObject + { + NonRoundedDoubleValue = expectedValue + }); + + // Assert + const string expectedMessage = "Value property 'NonRoundedDoubleValue' was not of type RoundedDouble."; + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(Call, expectedMessage); + } + + [Test] + public void GetValue_InvalidValueProperty_ThrowsArgumentException() + { + // Setup + var attribute = new KeyValueAsRoundedDoubleWithoutTrailingZeroesElementAttribute(nameof(TestObject.Name), + nameof(TestObject.Unit), + "IDoNotExist"); + + // Call + void Call() => attribute.GetValue(new TestObject()); + + // Assert + const string expectedMessage = "Value property 'IDoNotExist' was not found on type TestObject."; + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(Call, expectedMessage); + } + + private class TestObject + { + public string Name { get; set; } + public string Unit { get; set; } + public RoundedDouble Value { get; set; } + public int NonRoundedDoubleValue { get; set; } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Converters/KeyValueElementAttributeTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Converters/KeyValueElementAttributeTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Converters/KeyValueElementAttributeTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,173 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Common.TestUtil; +using Core.Gui.Converters; +using NUnit.Framework; + +namespace Core.Gui.Test.Converters +{ + [TestFixture] + public class KeyValueElementAttributeTest + { + [Test] + public void Constructor_WithoutValuePropertyName_ThrowsArgumentNullException() + { + // Call + TestDelegate test = () => new KeyValueElementAttribute("name", null); + + // Assert + var exception = Assert.Throws(test); + Assert.AreEqual("valuePropertyName", exception.ParamName); + } + + [Test] + public void Constructor_WithoutNamePropertyName_ThrowsArgumentNullException() + { + // Call + TestDelegate test = () => new KeyValueElementAttribute(null, "value"); + + // Assert + var exception = Assert.Throws(test); + Assert.AreEqual("namePropertyName", exception.ParamName); + } + + [Test] + public void Constructor_WithParameters_CreatesNewInstance() + { + // Call + var attribute = new KeyValueElementAttribute("name", "value"); + + // Assert + Assert.IsInstanceOf(attribute); + } + + [Test] + public void GetName_WithObjectWithProperty_ReturnsValueOfProperty() + { + // Setup + const string expectedName = "expectedName"; + + var attribute = new KeyValueElementAttribute(nameof(TestObject.Name), nameof(TestObject.Value)); + + // Call + string name = attribute.GetName(new TestObject + { + Name = expectedName + }); + + // Assert + Assert.AreEqual(expectedName, name); + } + + [Test] + public void GetName_WithObjectWithNonStringProperty_ReturnsValueOfProperty() + { + // Setup + int expectedName = new Random(21).Next(3, 50); + + var attribute = new KeyValueElementAttribute(nameof(TestObject.NonStringName), nameof(TestObject.NonStringValue)); + + // Call + string name = attribute.GetName(new TestObject + { + NonStringName = expectedName + }); + + // Assert + Assert.AreEqual(Convert.ToString(expectedName), name); + } + + [Test] + public void GetName_WithObjectWithoutPropertyWithName_ThrowsArgumentException() + { + // Setup + var attribute = new KeyValueElementAttribute("IDoNotExist", nameof(TestObject.Value)); + + // Call + TestDelegate test = () => attribute.GetName(new TestObject()); + + // Assert + const string expectedMessage = "Name property 'IDoNotExist' was not found on type TestObject."; + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(test, expectedMessage); + } + + [Test] + public void GetValue_WithObjectWithProperty_ReturnsValueOfProperty() + { + // Setup + const string expectedValue = "expectedValue"; + + var attribute = new KeyValueElementAttribute(nameof(TestObject.Name), nameof(TestObject.Value)); + + // Call + string value = attribute.GetValue(new TestObject + { + Value = expectedValue + }); + + // Assert + Assert.AreEqual(expectedValue, value); + } + + [Test] + public void GetValue_WithObjectWithNonStringProperty_ReturnsStringConvertedValueOfProperty() + { + // Setup + int expectedValue = new Random(21).Next(3, 50); + + var attribute = new KeyValueElementAttribute(nameof(TestObject.NonStringName), nameof(TestObject.NonStringValue)); + + // Call + string value = attribute.GetValue(new TestObject + { + NonStringValue = expectedValue + }); + + // Assert + Assert.AreEqual(Convert.ToString(expectedValue), value); + } + + [Test] + public void GetValue_WithObjectWithoutPropertyWithName_ThrowsArgumentException() + { + // Setup + var attribute = new KeyValueElementAttribute(nameof(TestObject.Name), "IDoNotExist"); + + // Call + TestDelegate test = () => attribute.GetValue(new TestObject()); + + // Assert + const string expectedMessage = "Value property 'IDoNotExist' was not found on type TestObject."; + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(test, expectedMessage); + } + + private class TestObject + { + public string Name { get; set; } + public string Value { get; set; } + + public int NonStringName { get; set; } + public int NonStringValue { get; set; } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Converters/KeyValueExpandableArrayConverterTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Converters/KeyValueExpandableArrayConverterTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Converters/KeyValueExpandableArrayConverterTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,301 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.ComponentModel; +using System.Linq; +using Core.Common.TestUtil; +using Core.Gui.Converters; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Converters +{ + [TestFixture] + public class KeyValueExpandableArrayConverterTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var converter = new KeyValueExpandableArrayConverter(); + + // Assert + Assert.IsInstanceOf(converter); + } + + [Test] + public void ConvertTo_FromArrayToString_ReturnCountText() + { + // Setup + int arrayCount = new Random(21).Next(0, 10); + + var sourceArray = new int[arrayCount]; + var converter = new KeyValueExpandableArrayConverter(); + + // Call + object text = converter.ConvertTo(sourceArray, typeof(string)); + + // Assert + Assert.AreEqual($"Aantal ({arrayCount})", text); + } + + [Test] + public void ConvertTo_FromNullToString_ReturnEmptyText() + { + // Setup + var converter = new KeyValueExpandableArrayConverter(); + + // Call + object text = converter.ConvertTo(null, typeof(string)); + + // Assert + Assert.AreEqual(string.Empty, text); + } + + [Test] + public void ConvertTo_FromArrayToInt_ThrowsNotSupportedException() + { + // Setup + var sourceArray = new int[1]; + var converter = new KeyValueExpandableArrayConverter(); + + // Call + TestDelegate call = () => converter.ConvertTo(sourceArray, typeof(int)); + + // Assert + Assert.Throws(call); + } + + [Test] + public void ConvertTo_FromArrayToNull_ThrowsArgumentNullException() + { + // Setup + var sourceArray = new int[2]; + var converter = new KeyValueExpandableArrayConverter(); + + // Call + TestDelegate call = () => converter.ConvertTo(sourceArray, null); + + // Assert + Assert.Throws(call); + } + + [Test] + public void GetProperties_WithoutContext_ThrowsArgumentException() + { + var converter = new KeyValueExpandableArrayConverter(); + + // Call + TestDelegate test = () => converter.GetProperties(new object()); + + // Assert + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(test, + "The KeyValueExpandableArrayConverter can only be used on properties that have the KeyValueElementAttribute defined."); + } + + [Test] + public void GetProperties_WithoutPropertyDescriptor_ThrowsArgumentException() + { + var mocks = new MockRepository(); + var context = mocks.Stub(); + mocks.ReplayAll(); + + var converter = new KeyValueExpandableArrayConverter(); + + // Call + TestDelegate test = () => converter.GetProperties(context, new object()); + + // Assert + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(test, + "The KeyValueExpandableArrayConverter can only be used on properties that have the KeyValueElementAttribute defined."); + mocks.VerifyAll(); + } + + [Test] + public void GetProperties_WithoutKeyValueElementAttribute_ThrowsArgumentException() + { + var mocks = new MockRepository(); + var context = mocks.Stub(); + var descriptor = mocks.Stub("name", new Attribute[0]); + context.Stub(c => c.PropertyDescriptor).Return(descriptor); + mocks.ReplayAll(); + + var converter = new KeyValueExpandableArrayConverter(); + + // Call + TestDelegate test = () => converter.GetProperties(context, new object()); + + // Assert + TestHelper.AssertThrowsArgumentExceptionAndTestMessage( + test, + "The KeyValueExpandableArrayConverter can only be used on properties that have the KeyValueElementAttribute defined."); + mocks.VerifyAll(); + } + + [Test] + [TestCase(0)] + [TestCase(1)] + [TestCase(12)] + public void GetProperties_FromArray_ReturnPropertyDescriptorsForEachElementWithNameToOneBasedIndex(int elementCount) + { + // Setup + var attribute = new KeyValueElementAttribute(nameof(TestObject.Name), nameof(TestObject.Value)); + var attributes = new AttributeCollection(attribute); + + var mocks = new MockRepository(); + var context = mocks.Stub(); + var descriptor = mocks.Stub("name", new Attribute[0]); + descriptor.Stub(d => d.Attributes).Return(attributes); + context.Stub(c => c.PropertyDescriptor).Return(descriptor); + mocks.ReplayAll(); + + const string name = "name"; + const string value = "value"; + TestObject[] array = Enumerable.Repeat(new TestObject + { + Name = name, + Value = value + }, elementCount).ToArray(); + + var converter = new KeyValueExpandableArrayConverter(); + + // Call + PropertyDescriptorCollection propertyDescriptors = converter.GetProperties(context, array); + + // Assert + Assert.IsNotNull(propertyDescriptors); + Assert.AreEqual(elementCount, propertyDescriptors.Count); + for (var i = 0; i < elementCount; i++) + { + Assert.AreEqual(typeof(TestObject), propertyDescriptors[i].ComponentType); + Assert.AreEqual(name, propertyDescriptors[i].Name); + Assert.AreEqual(name, propertyDescriptors[i].DisplayName); + Assert.AreEqual(value.GetType(), propertyDescriptors[i].PropertyType); + CollectionAssert.IsEmpty(propertyDescriptors[i].Attributes); + + var actualValue = propertyDescriptors[i].GetValue(array) as string; + Assert.NotNull(actualValue); + Assert.AreEqual(value, actualValue); + } + + mocks.VerifyAll(); + } + + [Test] + public void GetProperties_FromArray_SettingValuesShouldThrowNotSupportedException() + { + // Setup + var attribute = new KeyValueElementAttribute(nameof(TestObject.Name), nameof(TestObject.Value)); + var attributes = new AttributeCollection(attribute); + + var mocks = new MockRepository(); + var context = mocks.Stub(); + var descriptor = mocks.Stub("name", new Attribute[0]); + descriptor.Stub(d => d.Attributes).Return(attributes); + context.Stub(c => c.PropertyDescriptor).Return(descriptor); + mocks.ReplayAll(); + + const int elementCount = 12; + TestObject[] array = Enumerable.Repeat(new TestObject + { + Name = "some name" + }, elementCount).ToArray(); + + var converter = new KeyValueExpandableArrayConverter(); + + // Call + PropertyDescriptorCollection propertyDescriptors = converter.GetProperties(context, array); + + // Assert + for (var i = 0; i < elementCount; i++) + { + Assert.Throws(() => propertyDescriptors[i].SetValue(array, i)); + } + + mocks.VerifyAll(); + } + + [Test] + public void GetProperties_IncorrectAttributeNamePropertyName_ThrowsArgumentException() + { + // Setup + var attribute = new KeyValueElementAttribute("IDoNotExist", nameof(TestObject.Value)); + var attributes = new AttributeCollection(attribute); + + var mocks = new MockRepository(); + var context = mocks.Stub(); + var descriptor = mocks.Stub("name", new Attribute[0]); + descriptor.Stub(d => d.Attributes).Return(attributes); + context.Stub(c => c.PropertyDescriptor).Return(descriptor); + mocks.ReplayAll(); + + const int elementCount = 12; + TestObject[] array = Enumerable.Repeat(new TestObject + { + Name = "some name" + }, elementCount).ToArray(); + + var converter = new KeyValueExpandableArrayConverter(); + + // Call + TestDelegate test = () => converter.GetProperties(context, array); + + // Assert + Assert.Throws(test); + } + + [Test] + public void GetProperties_IncorrectAttributeValuePropertyName_ThrowsArgumentException() + { + // Setup + var attribute = new KeyValueElementAttribute(nameof(TestObject.Name), "IDoNotExist"); + var attributes = new AttributeCollection(attribute); + + var mocks = new MockRepository(); + var context = mocks.Stub(); + var descriptor = mocks.Stub("name", new Attribute[0]); + descriptor.Stub(d => d.Attributes).Return(attributes); + context.Stub(c => c.PropertyDescriptor).Return(descriptor); + mocks.ReplayAll(); + + const int elementCount = 12; + TestObject[] array = Enumerable.Repeat(new TestObject + { + Name = "some name" + }, elementCount).ToArray(); + + var converter = new KeyValueExpandableArrayConverter(); + + // Call + TestDelegate test = () => converter.GetProperties(context, array); + + // Assert + Assert.Throws(test); + } + + private class TestObject + { + public string Name { get; set; } + public string Value { get; set; } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Converters/PngToIconConverterTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Converters/PngToIconConverterTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Converters/PngToIconConverterTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,75 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Drawing; +using System.Globalization; +using System.Windows.Data; +using System.Windows.Media.Imaging; +using Core.Common.TestUtil; +using Core.Gui.Converters; +using Core.Gui.Test.Properties; +using NUnit.Framework; + +namespace Core.Gui.Test.Converters +{ + [TestFixture] + public class PngToIconConverterTest + { + [Test] + public void DefaultConcstructor_ExpectedValues() + { + // Call + var converter = new PngToIconConverter(); + + // Assert + Assert.IsInstanceOf(converter); + } + + [Test] + public void Convert_WithPngImage_ConvertToBitmapImage() + { + // Setup + var converter = new PngToIconConverter(); + + // Call + object bitmap = converter.Convert(Resources.abacus, typeof(BitmapImage), null, CultureInfo.InvariantCulture); + + // Assert + var bitmapInstance = bitmap as BitmapImage; + Assert.NotNull(bitmapInstance); + TestHelper.AssertImagesAreEqual(new Bitmap(bitmapInstance.StreamSource), Resources.abacus); + } + + [Test] + public void ConvertBack_ThrowNotImplementedException() + { + // Setup + var converter = new PngToIconConverter(); + + // Call + TestDelegate call = () => converter.ConvertBack(new BitmapImage(), typeof(Bitmap), null, CultureInfo.InvariantCulture); + + // Assert + Assert.Throws(call); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Core.Gui.Test.csproj =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Core.Gui.Test.csproj (revision 0) +++ Core/Gui/test/Core.Gui.Test/Core.Gui.Test.csproj (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,71 @@ + + + + + ..\..\..\..\lib\NUnitForms.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Copying.Lesser.licenseheader + + + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + 2.0.12 + + + 2.4.4 + + + 3.8.1 + + + 3.6.1 + + + 2.0.2000 + + + \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/ExceptionDialogTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/ExceptionDialogTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/ExceptionDialogTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,337 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Windows.Forms; +using Core.Gui.Clipboard; +using Core.Gui.Commands; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test +{ + [TestFixture] + public class ExceptionDialogTest : NUnitFormTest + { + [Test] + public void DefaultConstructor_ExpectedValue() + { + // Setup + var mocks = new MockRepository(); + var window = mocks.Stub(); + + mocks.ReplayAll(); + + // Call + using (var dialog = new ExceptionDialog(window, null, null)) + { + // Assert + Assert.IsNotNull(dialog.Icon); + Assert.IsTrue(dialog.ShowIcon); + Assert.AreEqual(0, dialog.MinimumSize.Width); // Set during load + Assert.AreEqual(0, dialog.MinimumSize.Height); // Set during load + Assert.AreEqual(FormBorderStyle.Sizable, dialog.FormBorderStyle); + Assert.AreEqual(FormStartPosition.CenterParent, dialog.StartPosition); + Assert.IsFalse(dialog.ShowInTaskbar); + Assert.IsTrue(dialog.ControlBox); + Assert.IsFalse(dialog.MaximizeBox); + Assert.IsFalse(dialog.MinimizeBox); + Assert.IsNull(dialog.CancelButton); + } + + mocks.VerifyAll(); + } + + [Test] + public void Show_Always_ExpectedValues() + { + // Setup + var mocks = new MockRepository(); + var window = mocks.Stub(); + mocks.ReplayAll(); + + using (var dialog = new ExceptionDialog(window, null, null)) + { + // Call + dialog.Show(); + + // Assert + Assert.AreEqual(470, dialog.MinimumSize.Width); + Assert.AreEqual(200, dialog.MinimumSize.Height); + + var textBox = new RichTextBoxTester("exceptionTextBox"); + string exceptionText = textBox.Text; + Assert.AreEqual("", exceptionText); + } + + mocks.VerifyAll(); + } + + [Test] + public void Show_WithException_ExceptionMessageSetToTextBox() + { + // Setup + var mocks = new MockRepository(); + var window = mocks.Stub(); + mocks.ReplayAll(); + + var exception = new Exception("Test", new Exception("Test inner")); + using (var dialog = new ExceptionDialog(window, null, exception)) + { + // Call + dialog.Show(); + + // Assert + var textBox = new RichTextBoxTester("exceptionTextBox"); + string exceptionText = textBox.Text; + Assert.AreEqual(exception.ToString().Replace(Environment.NewLine, "\n"), exceptionText); + } + + mocks.VerifyAll(); + } + + [Test] + public void GivenExceptionDialog_WhenNoOpenLogActionSet_ThenOpenLogButtonDisabled() + { + // Setup + var mocks = new MockRepository(); + var window = mocks.Stub(); + mocks.ReplayAll(); + + using (var dialog = new ExceptionDialog(window, null, null)) + { + // Call + dialog.Show(); + + // Assert + var button = new ButtonTester("buttonOpenLog"); + var buttonOpenLog = (Button) button.TheObject; + Assert.IsFalse(buttonOpenLog.Enabled); + } + + mocks.VerifyAll(); + } + + [Test] + public void GivenExceptionDialog_WhenOpenLogActionSet_ThenOpenLogButtonEnabled() + { + // Setup + var mocks = new MockRepository(); + var window = mocks.Stub(); + mocks.ReplayAll(); + + using (var dialog = new ExceptionDialog(window, null, null) + { + OpenLogClicked = () => {} + }) + { + // Call + dialog.Show(); + + // Assert + var button = new ButtonTester("buttonOpenLog"); + var buttonOpenLog = (Button) button.TheObject; + Assert.IsTrue(buttonOpenLog.Enabled); + } + + mocks.VerifyAll(); + } + + [Test] + public void GivenExceptionDialog_WhenRestartButtonClicked_ThenDialogResultOk() + { + // Setup + var mocks = new MockRepository(); + var window = mocks.Stub(); + + mocks.ReplayAll(); + + using (var dialog = new ExceptionDialog(window, null, null)) + { + dialog.Show(); + var button = new ButtonTester("buttonRestart"); + + // Call + button.Click(); + + // Assert + Assert.AreEqual(DialogResult.OK, dialog.DialogResult); + } + + mocks.VerifyAll(); + } + + [Test] + public void GivenExceptionDialog_WhenExitButtonClicked_ThenDialogResultCancel() + { + // Setup + var mocks = new MockRepository(); + var window = mocks.Stub(); + mocks.ReplayAll(); + + using (var dialog = new ExceptionDialog(window, null, null)) + { + dialog.Show(); + var button = new ButtonTester("buttonExit"); + + // Call + button.Click(); + + // Assert + Assert.AreEqual(DialogResult.Cancel, dialog.DialogResult); + } + + mocks.VerifyAll(); + } + + [Test] + public void GivenExceptionDialog_WhenOpenLogButtonClicked_ThenPerformsOpenLogClickedAction() + { + // Setup + var counter = 0; + + var mocks = new MockRepository(); + var window = mocks.Stub(); + mocks.ReplayAll(); + + using (var dialog = new ExceptionDialog(window, null, null) + { + OpenLogClicked = () => counter++ + }) + { + dialog.Show(); + var button = new ButtonTester("buttonOpenLog"); + + // Call + button.Click(); + + // Assert + Assert.AreEqual(1, counter); + } + + mocks.VerifyAll(); + } + + [Test] + public void GivenExceptionDialog_WhenCopyToClipboardClicked_ThenExceptionTextCopiedToClipboard() + { + // Setup + var exception = new Exception("Test"); + using (new ClipboardConfig()) + using (var dialog = new ExceptionDialog(new UserControl(), null, exception)) + { + dialog.Show(); + + var button = new ButtonTester("buttonCopyTextToClipboard"); + + // Call + button.Click(); + + // Assert + Assert.AreEqual(exception.ToString(), ClipboardProvider.Clipboard.GetText()); + } + } + + [Test] + [TestCase(true, "Project is opgeslagen", "Opslaan van project is gelukt.")] + [TestCase(false, "Project is niet opgeslagen", "Opslaan van project is mislukt.")] + public void GivenExceptionDialog_WhenSaveProjectClicked_ThenSaveProjectAsCalledAndMessageBoxShown(bool saveSuccessful, string expectedDialogTitle, string expectedDialogMessage) + { + // Setup + var mocks = new MockRepository(); + var commandsOwner = mocks.StrictMock(); + var commands = mocks.StrictMock(); + commandsOwner.Expect(co => co.StorageCommands).Return(commands); + commands.Expect(c => c.SaveProjectAs()).Return(saveSuccessful); + mocks.ReplayAll(); + + var messageBoxTitle = ""; + var messageBoxText = ""; + + // Setup + DialogBoxHandler = (name, wnd) => + { + var openedDialog = new MessageBoxTester(wnd); + messageBoxTitle = openedDialog.Title; + messageBoxText = openedDialog.Text; + openedDialog.ClickOk(); + }; + + var exception = new Exception("Test"); + using (var dialog = new ExceptionDialog(new UserControl(), commandsOwner, exception)) + { + dialog.Show(); + + var buttonTester = new ButtonTester("buttonSaveProject"); + + // Call + buttonTester.Click(); + + // Assert + Assert.AreEqual(expectedDialogTitle, messageBoxTitle); + Assert.AreEqual(expectedDialogMessage, messageBoxText); + } + + mocks.VerifyAll(); + } + + [Test] + public void GivenExceptionDialog_WhenSaveProjectClickedAndExceptionThrown_ThenUnsuccessfulMessageShown() + { + // Setup + var mocks = new MockRepository(); + var commandsOwner = mocks.StrictMock(); + var commands = mocks.StrictMock(); + commandsOwner.Expect(co => co.StorageCommands).Return(commands); + commands.Expect(c => c.SaveProjectAs()).Throw(new Exception()); + mocks.ReplayAll(); + + var messageBoxTitle = ""; + var messageBoxText = ""; + + // Setup + DialogBoxHandler = (name, wnd) => + { + var openedDialog = new MessageBoxTester(wnd); + messageBoxTitle = openedDialog.Title; + messageBoxText = openedDialog.Text; + openedDialog.ClickOk(); + }; + + var exception = new Exception("Test"); + using (var dialog = new ExceptionDialog(new UserControl(), commandsOwner, exception)) + { + dialog.Show(); + var buttonTester = new ButtonTester("buttonSaveProject"); + + // Call + buttonTester.Click(); + + // Assert + Assert.AreEqual("Project is niet opgeslagen", messageBoxTitle); + Assert.AreEqual("Opslaan van project is mislukt.", messageBoxText); + } + + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/MainWindow/MainWindowTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/MainWindow/MainWindowTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/MainWindow/MainWindowTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,580 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.ComponentModel; +using System.Linq; +using System.Threading; +using System.Windows; +using Core.Common.Base.Data; +using Core.Common.Base.Storage; +using Core.Common.Controls.TreeView; +using Core.Common.Controls.Views; +using Core.Common.TestUtil; +using Core.Gui.Commands; +using Core.Gui.Forms.MainWindow; +using Core.Gui.Forms.MessageWindow; +using Core.Gui.Forms.PropertyGridView; +using Core.Gui.Forms.ViewHost; +using Core.Gui.Plugin; +using Core.Gui.PropertyBag; +using Core.Gui.Settings; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Forms.MainWindow +{ + [TestFixture] + public class MainWindowTest + { + private MessageWindowLogAppender originalValue; + + [SetUp] + public void SetUp() + { + originalValue = MessageWindowLogAppender.Instance; + MessageWindowLogAppender.Instance = new MessageWindowLogAppender(); + } + + [TearDown] + public void TearDown() + { + MessageWindowLogAppender.Instance = originalValue; + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Constructor_ExpectedValues() + { + // Call + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + // Assert + Assert.IsInstanceOf(mainWindow); + Assert.IsInstanceOf(mainWindow); + Assert.IsInstanceOf(mainWindow); + + Assert.IsFalse(mainWindow.IsWindowDisposed); + Assert.IsFalse(mainWindow.Visible); + + Assert.IsNull(mainWindow.MessageWindow); + Assert.IsNull(mainWindow.PropertyGrid); + Assert.IsNull(mainWindow.ProjectExplorer); + + Assert.IsNotNull(mainWindow.Handle); + Assert.IsFalse(mainWindow.InvokeRequired, + "'mainWindow' instance on same thread as test, therefore invocation not required."); + + Assert.AreEqual("MainWindow", mainWindow.Title); + Assert.AreEqual(ResizeMode.CanResizeWithGrip, mainWindow.ResizeMode); + Assert.AreEqual(FlowDirection.LeftToRight, mainWindow.FlowDirection); + Assert.AreEqual("RiskeerMainWindow", mainWindow.Name); + } + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Dispose_SetIsWindowDisposedTrue() + { + // Setup + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + // Call + mainWindow.Dispose(); + + // Assert + Assert.IsTrue(mainWindow.IsWindowDisposed); + } + } + + [Test] + [TestCase(true)] + [TestCase(false)] + [Apartment(ApartmentState.STA)] + public void Visible_SettingValueWithoutHavingSetGui_ThrowInvalidOperationException(bool newVisibleValue) + { + // Setup + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + // Call + void Call() => mainWindow.Visible = newVisibleValue; + + // Assert + Assert.Throws(Call); + } + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Visible_SetToTrue_ShowMainForm() + { + // Setup + var mocks = new MockRepository(); + + var viewHost = mocks.Stub(); + viewHost.Stub(vm => vm.ToolViews).Return(new IView[0]); + + var gui = mocks.Stub(); + gui.Stub(g => g.FixedSettings).Return(new GuiCoreSettings()); + gui.Stub(g => g.Plugins).Return(Enumerable.Empty().ToList()); + gui.Stub(g => g.ViewHost).Return(viewHost); + mocks.ReplayAll(); + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + mainWindow.SetGui(gui); + + // Call + mainWindow.Visible = true; + + // Assert + Assert.IsTrue(mainWindow.Visible); + Assert.IsTrue(mainWindow.IsVisible); + Assert.AreEqual(Visibility.Visible, mainWindow.Visibility); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Visible_SetToFalse_HideMainForm() + { + // Setup + var mocks = new MockRepository(); + + var viewHost = mocks.Stub(); + viewHost.Stub(vm => vm.ToolViews).Return(new IView[0]); + + var gui = mocks.Stub(); + gui.Stub(g => g.FixedSettings).Return(new GuiCoreSettings()); + gui.Stub(g => g.Plugins).Return(Enumerable.Empty().ToList()); + gui.Stub(g => g.ViewHost).Return(viewHost); + mocks.ReplayAll(); + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + mainWindow.SetGui(gui); + mainWindow.Visible = true; + + // Call + mainWindow.Visible = false; + + // Assert + Assert.IsFalse(mainWindow.Visible); + Assert.IsFalse(mainWindow.IsVisible); + Assert.AreEqual(Visibility.Hidden, mainWindow.Visibility); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void SubscribeToGui_NoGuiSet_DoNothing() + { + // Setup + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + // Call + void Call() => mainWindow.SubscribeToGui(); + + // Assert + Assert.DoesNotThrow(Call); + } + } + + [Test] + [Apartment(ApartmentState.STA)] + public void SubscribeToGui_GuiSet_AttachEvents() + { + // Setup + var mocks = new MockRepository(); + var viewHost = mocks.Stub(); + viewHost.Expect(vm => vm.ViewClosed += null).IgnoreArguments(); + + var gui = mocks.Stub(); + gui.Stub(g => g.ViewHost).Return(viewHost); + mocks.ReplayAll(); + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + mainWindow.SetGui(gui); + + // Call + mainWindow.SubscribeToGui(); + } + + // Assert + mocks.VerifyAll(); // Expect event subscription + } + + [Test] + [Apartment(ApartmentState.STA)] + public void UnsubscribeFromGui_NoGuiSet_DoNothing() + { + // Setup + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + // Call + void Call() => mainWindow.UnsubscribeFromGui(); + + // Assert + Assert.DoesNotThrow(Call); + } + } + + [Test] + [Apartment(ApartmentState.STA)] + public void UnsubscribeFromGui_GuiSetAndSubscribed_DetachEvents() + { + // Setup + var mocks = new MockRepository(); + var viewHost = mocks.Stub(); + viewHost.Expect(l => l.ViewClosed += null).IgnoreArguments(); + viewHost.Expect(l => l.ViewClosed -= null).IgnoreArguments(); + + var gui = mocks.Stub(); + gui.Stub(g => g.ViewHost).Return(viewHost); + mocks.ReplayAll(); + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + mainWindow.SetGui(gui); + mainWindow.SubscribeToGui(); + + // Call + mainWindow.UnsubscribeFromGui(); + } + + // Assert + mocks.VerifyAll(); // Expect event subscription and desubscription + } + + [Test] + [Apartment(ApartmentState.STA)] + public void InitPropertiesWindowOrBringToFront_GuiNotSet_ThrowInvalidOperationException() + { + // Setup + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + // Call + void Call() => mainWindow.InitPropertiesWindowOrBringToFront(); + + // Assert + Assert.Throws(Call); + } + } + + [Test] + [Apartment(ApartmentState.STA)] + public void InitPropertiesWindowOrBringToFront_GuiSet_InitializePropertyGrid() + { + // Setup + var selectedObject = new object(); + + var mocks = new MockRepository(); + var selectedObjectProperties = mocks.Stub(); + + var viewHost = new AvalonDockViewHost(); + + var propertyResolver = mocks.Stub(); + propertyResolver.Expect(r => r.GetObjectProperties(selectedObject)) + .Return(selectedObjectProperties); + + var gui = mocks.Stub(); + gui.Stub(g => g.ViewHost).Return(viewHost); + gui.Selection = selectedObject; + gui.Stub(g => g.PropertyResolver).Return(propertyResolver); + mocks.ReplayAll(); + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + mainWindow.SetGui(gui); + + // Call + mainWindow.InitPropertiesWindowOrBringToFront(); + + // Assert + Assert.IsNull(viewHost.ActiveDocumentView); + Assert.AreSame(viewHost.ToolViews.ElementAt(0), mainWindow.PropertyGrid, "PropertyGrid instance should remain the same."); + Assert.AreEqual("Eigenschappen", mainWindow.PropertyGrid.Text); + Assert.AreEqual(selectedObject, mainWindow.PropertyGrid.Data); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void InitPropertiesWindowOrBringToFront_GuiSetAndCalledTwice_PropertyGridViewInstanceNotUpdatedRedundantly() + { + // Setup + var selectedObject = new object(); + + var mocks = new MockRepository(); + var selectedObjectProperties = mocks.Stub(); + var viewHost = new AvalonDockViewHost(); + var propertyResolver = mocks.Stub(); + propertyResolver.Expect(r => r.GetObjectProperties(selectedObject)) + .Return(selectedObjectProperties) + .Repeat.Once(); + + var gui = mocks.Stub(); + gui.Stub(g => g.ViewHost).Return(viewHost); + gui.Selection = selectedObject; + gui.Stub(g => g.PropertyResolver).Return(propertyResolver); + mocks.ReplayAll(); + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + mainWindow.SetGui(gui); + mainWindow.InitPropertiesWindowOrBringToFront(); + + IView originalPropertyGrid = mainWindow.PropertyGrid; + + // Call + mainWindow.InitPropertiesWindowOrBringToFront(); + + // Assert + Assert.IsNull(viewHost.ActiveDocumentView); + Assert.AreSame(originalPropertyGrid, mainWindow.PropertyGrid, "PropertyGrid instance should remain the same."); + Assert.AreEqual("Eigenschappen", mainWindow.PropertyGrid.Text); + Assert.AreSame(selectedObject, mainWindow.PropertyGrid.Data); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void InitializeToolWindows_GuiNotSet_ThrowInvalidOperationException() + { + // Setup + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + // Call + void Call() => mainWindow.InitializeToolWindows(); + + // Assert + Assert.Throws(Call); + } + } + + [Test] + [Apartment(ApartmentState.STA)] + public void InitializeToolWindows_GuiSet_InitializeToolWindows() + { + // Setup + var selectedObject = new object(); + var viewHost = new AvalonDockViewHost(); + + var treeNodeInfos = new TreeNodeInfo[] + { + new TreeNodeInfo() + }; + + var mocks = new MockRepository(); + var selectedObjectProperties = mocks.Stub(); + + var propertyResolver = mocks.Stub(); + propertyResolver.Expect(r => r.GetObjectProperties(selectedObject)) + .Return(selectedObjectProperties); + + var viewCommands = mocks.Stub(); + var project = mocks.Stub(); + + var gui = mocks.Stub(); + gui.Stub(g => g.ViewHost).Return(viewHost); + gui.Stub(g => g.PropertyResolver).Return(propertyResolver); + gui.Stub(g => g.ViewCommands).Return(viewCommands); + gui.Stub(g => g.Project).Return(project); + gui.Stub(g => g.GetTreeNodeInfos()).Return(treeNodeInfos); + mocks.ReplayAll(); + + gui.Selection = selectedObject; + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + { + mainWindow.SetGui(gui); + + // Call + mainWindow.InitializeToolWindows(); + + // Assert + Assert.IsInstanceOf(mainWindow.ProjectExplorer); + Assert.AreSame(gui.Project, mainWindow.ProjectExplorer.Data); + + Assert.IsInstanceOf(mainWindow.PropertyGrid); + Assert.AreEqual("Eigenschappen", mainWindow.PropertyGrid.Text); + Assert.AreEqual(selectedObject, mainWindow.PropertyGrid.Data); + + Assert.IsInstanceOf(mainWindow.MessageWindow); + Assert.AreEqual("Berichten", mainWindow.MessageWindow.Text); + + Assert.IsNull(viewHost.ActiveDocumentView); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithProjectExplorer_WhenClosingProjectExplorer_ThenProjectExplorerSetToNull() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var projectFactory = mocks.Stub(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(mocks.Stub()); + mocks.ReplayAll(); + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + + mainWindow.SetGui(gui); + mainWindow.InitializeToolWindows(); + + // Precondition + Assert.IsNotNull(mainWindow.ProjectExplorer); + + // When + mainWindow.ViewHost.Remove(mainWindow.ProjectExplorer); + + // Then + Assert.IsNull(mainWindow.ProjectExplorer); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithPropertyGrid_WhenClosingPropertyGrid_ThenPropertyGridSetToNull() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var projectFactory = mocks.Stub(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(mocks.Stub()); + mocks.ReplayAll(); + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + + mainWindow.SetGui(gui); + mainWindow.InitializeToolWindows(); + + // Precondition + Assert.IsNotNull(mainWindow.PropertyGrid); + + // When + mainWindow.ViewHost.Remove(mainWindow.PropertyGrid); + + // Then + Assert.IsNull(mainWindow.PropertyGrid); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithMessageWindow_WhenClosingMessageWindow_ThenMessageWindowSetToNull() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var projectFactory = mocks.Stub(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(mocks.Stub()); + mocks.ReplayAll(); + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + + mainWindow.SetGui(gui); + mainWindow.InitializeToolWindows(); + + // Precondition + Assert.IsNotNull(mainWindow.MessageWindow); + + // When + mainWindow.ViewHost.Remove(mainWindow.MessageWindow); + + // Then + Assert.IsNull(mainWindow.MessageWindow); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithProjectExplorer_WhenUpdateProjectExplorer_ThenDataSetOnProjectExplorer() + { + // Given + var mocks = new MockRepository(); + var project1 = mocks.Stub(); + var project2 = mocks.Stub(); + + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var projectFactory = mocks.Stub(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(project1); + mocks.ReplayAll(); + + using (var mainWindow = new Gui.Forms.MainWindow.MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + + mainWindow.SetGui(gui); + mainWindow.InitializeToolWindows(); + + // Precondition + Assert.IsNotNull(mainWindow.ProjectExplorer); + Assert.AreSame(project1, mainWindow.ProjectExplorer.Data); + + gui.SetProject(project2, string.Empty); + + // When + mainWindow.UpdateProjectExplorer(); + + // Then + Assert.AreSame(project2, mainWindow.ProjectExplorer.Data); + } + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/MessageWindow/MessageWindowDialogTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/MessageWindow/MessageWindowDialogTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/MessageWindow/MessageWindowDialogTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,55 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Windows.Forms; +using Core.Gui.Forms.MessageWindow; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Forms.MessageWindow +{ + [TestFixture] + public class MessageWindowDialogTest + { + [Test] + public void MessageWindowDialog_Always_SetProperties() + { + // Setup + var mocks = new MockRepository(); + var parent = mocks.StrictMock(); + mocks.ReplayAll(); + + const string testText = "Some text for the dialog"; + + // Call + var dialog = new MessageWindowDialog(parent, testText); + + // Assert + var textBox = (TextBox) dialog.Controls.Find("textBox", true)[0]; + + Assert.AreEqual(testText, textBox.Text); + Assert.IsFalse(textBox.TabStop); + Assert.IsTrue(textBox.ReadOnly); + + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/MessageWindow/MessageWindowLogAppenderTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/MessageWindow/MessageWindowLogAppenderTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/MessageWindow/MessageWindowLogAppenderTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,363 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Globalization; +using Core.Common.TestUtil; +using Core.Gui.Forms.MessageWindow; +using log4net.Core; +using log4net.Util; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Forms.MessageWindow +{ + [TestFixture] + public class MessageWindowLogAppenderTest + { + private MessageWindowLogAppender originalInstance; + + [SetUp] + public void SetUp() + { + originalInstance = MessageWindowLogAppender.Instance; + } + + [TearDown] + public void TearDown() + { + MessageWindowLogAppender.Instance = originalInstance; + } + + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var appender = new MessageWindowLogAppender(); + + // Assert + Assert.IsFalse(appender.Enabled); + Assert.IsNull(appender.MessageWindow); + Assert.IsInstanceOf(appender.ErrorHandler); + Assert.AreEqual(null, appender.FilterHead); + Assert.AreEqual(null, appender.Layout); + Assert.AreEqual(null, appender.Name); + Assert.AreEqual(null, appender.Threshold); + Assert.AreSame(appender, MessageWindowLogAppender.Instance); + } + + [Test] + [TestCase(LogLevelConstant.Off)] + [TestCase(LogLevelConstant.Fatal)] + [TestCase(LogLevelConstant.Error)] + [TestCase(LogLevelConstant.Warn)] + [TestCase(LogLevelConstant.Info)] + [TestCase(LogLevelConstant.Debug)] + public void DoAppend_AppenderEnabled_ForwardAllMessagesToMessageWindow(LogLevelConstant logLevel) + { + // Setup + Level level = logLevel.ToLog4NetLevel(); + DateTime dataTime = DateTime.Now; + const string message = ""; + + var mocks = new MockRepository(); + var messageWindow = mocks.Stub(); + messageWindow.Expect(w => w.AddMessage(level, dataTime, message)); + mocks.ReplayAll(); + + var appender = new MessageWindowLogAppender + { + Enabled = true, + MessageWindow = messageWindow + }; + + var logData = new LoggingEventData + { + Level = level, + TimeStampUtc = dataTime, + Message = message + }; + var logEvent = new LoggingEvent(logData); + + // Call + appender.DoAppend(logEvent); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [SetCulture("nl-NL")] + public void DoAppend_LogMessageHasFormattedText_ReturnLocalCulturedText() + { + // Setup + const string messageText = "Gestart in {0:f2} seconden."; + const double formatArgument = 1.2; + + const string expectedText = "Gestart in 1,20 seconden."; + + Level level = LogLevelConstant.Warn.ToLog4NetLevel(); + DateTime dataTime = DateTime.Now; + var logEvent = new LoggingEvent(null, null, "", Level.Warn, + new SystemStringFormat(CultureInfo.InvariantCulture, messageText, formatArgument), + null); + + var mocks = new MockRepository(); + var messageWindow = mocks.Stub(); + messageWindow.Expect(w => w.AddMessage(Arg.Is.Equal(level), + Arg.Matches(time => time - dataTime <= new TimeSpan(0, 0, 0, 0, 5)), + Arg.Is.Equal(expectedText))); + mocks.ReplayAll(); + + var appender = new MessageWindowLogAppender + { + Enabled = true, + MessageWindow = messageWindow + }; + + // Call + appender.DoAppend(logEvent); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [SetCulture("nl-NL")] + public void DoAppend_LogMessageHasFormattedTextWithBug_ForwardUnformattedText() + { + // Setup + const string messageText = "Gestart in {5:f2} seconden."; + const double formatArgument = 1.2; + + Level level = LogLevelConstant.Warn.ToLog4NetLevel(); + DateTime dataTime = DateTime.Now; + var logEvent = new LoggingEvent(null, null, "", Level.Warn, + new SystemStringFormat(CultureInfo.InvariantCulture, messageText, formatArgument), + null); + + var mocks = new MockRepository(); + var messageWindow = mocks.Stub(); + messageWindow.Expect(w => w.AddMessage(Arg.Is.Equal(level), + Arg.Matches(time => time - dataTime <= new TimeSpan(0, 0, 0, 0, 2)), + Arg.Is.Equal(messageText))); + mocks.ReplayAll(); + + var appender = new MessageWindowLogAppender + { + Enabled = true, + MessageWindow = messageWindow + }; + + // Call + appender.DoAppend(logEvent); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [SetCulture("nl-NL")] + public void DoAppend_LogMessageHasFormattedTextWithoutFormatArgument_ForwardUnformattedText() + { + // Setup + const string messageText = "Gestart in {5:f2} seconden."; + + Level level = LogLevelConstant.Warn.ToLog4NetLevel(); + DateTime dataTime = DateTime.Now; + var logEvent = new LoggingEvent(null, null, "", Level.Warn, + new SystemStringFormat(CultureInfo.InvariantCulture, messageText, null), + null); + + var mocks = new MockRepository(); + var messageWindow = mocks.Stub(); + messageWindow.Expect(w => w.AddMessage(Arg.Is.Equal(level), + Arg.Matches(time => time - dataTime <= new TimeSpan(0, 0, 0, 0, 2)), + Arg.Is.Equal(messageText))); + mocks.ReplayAll(); + + var appender = new MessageWindowLogAppender + { + Enabled = true, + MessageWindow = messageWindow + }; + + // Call + appender.DoAppend(logEvent); + + // Assert + mocks.VerifyAll(); + } + + [Test] + public void DoAppend_LogMessageHasException_AppendTextForReferToLogfileToMessage() + { + // Setup + const string messageText = ""; + string expectedText = $"{messageText} {Environment.NewLine}Controleer logbestand voor meer informatie (\"Bestand\"->\"Help\"->\"Log tonen\")."; + var exception = new Exception(); + + Level level = LogLevelConstant.Error.ToLog4NetLevel(); + DateTime dataTime = DateTime.Now; + var logEvent = new LoggingEvent(null, null, "", Level.Error, + messageText, exception); + + var mocks = new MockRepository(); + var messageWindow = mocks.Stub(); + messageWindow.Expect(w => w.AddMessage(Arg.Is.Equal(level), + Arg.Matches(time => time - dataTime <= new TimeSpan(0, 0, 0, 0, 2)), + Arg.Is.Equal(expectedText))); + mocks.ReplayAll(); + + var appender = new MessageWindowLogAppender + { + Enabled = true, + MessageWindow = messageWindow + }; + + // Call + appender.DoAppend(logEvent); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [TestCase(LogLevelConstant.Off)] + [TestCase(LogLevelConstant.Fatal)] + [TestCase(LogLevelConstant.Error)] + [TestCase(LogLevelConstant.Warn)] + [TestCase(LogLevelConstant.Info)] + [TestCase(LogLevelConstant.Debug)] + public void DoAppend_AppenderDisabled_MessagesNotForwardedToMessageWindow(LogLevelConstant logLevel) + { + // Setup + Level level = logLevel.ToLog4NetLevel(); + DateTime dataTime = DateTime.Now; + const string message = ""; + + var mocks = new MockRepository(); + var messageWindow = mocks.StrictMock(); + mocks.ReplayAll(); + + var appender = new MessageWindowLogAppender + { + Enabled = false, + MessageWindow = messageWindow + }; + + var logData = new LoggingEventData + { + Level = level, + TimeStampUtc = dataTime, + Message = message + }; + var logEvent = new LoggingEvent(logData); + + // Call + appender.DoAppend(logEvent); + + // Assert + mocks.VerifyAll(); + } + + [Test] + [TestCase(LogLevelConstant.Off)] + [TestCase(LogLevelConstant.Fatal)] + [TestCase(LogLevelConstant.Error)] + [TestCase(LogLevelConstant.Warn)] + [TestCase(LogLevelConstant.Info)] + [TestCase(LogLevelConstant.Debug)] + public void Enabled_FromFalseToTrue_ForwardAllCachedMessagesToMessageWindow(LogLevelConstant logLevel) + { + // Setup + Level level = logLevel.ToLog4NetLevel(); + DateTime dataTime = DateTime.Today; + const string message = ""; + + var mocks = new MockRepository(); + var messageWindow = mocks.Stub(); + messageWindow.Expect(w => w.AddMessage(level, dataTime, message)); + mocks.ReplayAll(); + + var appender = new MessageWindowLogAppender + { + Enabled = false, + MessageWindow = messageWindow + }; + + var logData = new LoggingEventData + { + Level = level, + TimeStampUtc = dataTime, + Message = message + }; + var logEvent = new LoggingEvent(logData); + appender.DoAppend(logEvent); + + // Call + appender.Enabled = true; + + // Assert + mocks.VerifyAll(); + } + + [Test] + [TestCase(LogLevelConstant.Off)] + [TestCase(LogLevelConstant.Fatal)] + [TestCase(LogLevelConstant.Error)] + [TestCase(LogLevelConstant.Warn)] + [TestCase(LogLevelConstant.Info)] + [TestCase(LogLevelConstant.Debug)] + public void MessageWindow_FromNullToProperInstance_ForwardAllCachedMessagesToMessageWindow(LogLevelConstant logLevel) + { + // Setup + Level level = logLevel.ToLog4NetLevel(); + DateTime dataTime = DateTime.Today; + const string message = ""; + + var mocks = new MockRepository(); + var messageWindow = mocks.Stub(); + messageWindow.Expect(w => w.AddMessage(level, dataTime, message)); + mocks.ReplayAll(); + + var appender = new MessageWindowLogAppender + { + Enabled = true + }; + + var logData = new LoggingEventData + { + Level = level, + TimeStampUtc = dataTime, + Message = message + }; + var logEvent = new LoggingEvent(logData); + appender.DoAppend(logEvent); + + // Call + appender.MessageWindow = messageWindow; + + // Assert + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/MessageWindow/MessageWindowTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/MessageWindow/MessageWindowTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/MessageWindow/MessageWindowTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,578 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Data; +using System.Windows.Forms; +using log4net.Core; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; +using GuiFormsMessageWindow = Core.Gui.Forms.MessageWindow; + +namespace Core.Gui.Test.Forms.MessageWindow +{ + [TestFixture] + public class MessageWindowTest : NUnitFormTest + { + private GuiFormsMessageWindow.MessageWindowLogAppender originalValue; + + [Test] + public void ParameteredConstructor_ExpectedValues() + { + // Setup + var logAppender = new GuiFormsMessageWindow.MessageWindowLogAppender(); + + // Precondition + Assert.AreSame(logAppender, GuiFormsMessageWindow.MessageWindowLogAppender.Instance); + + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + mocks.ReplayAll(); + + // Call + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(dialogParent)) + { + // Assert + Assert.IsInstanceOf(messageWindow); + Assert.IsInstanceOf(messageWindow); + Assert.IsInstanceOf(messageWindow.Data); + Assert.AreSame(messageWindow, GuiFormsMessageWindow.MessageWindowLogAppender.Instance.MessageWindow); + } + + mocks.VerifyAll(); + } + + [Test] + public void OnLoad_ExpectedMessageWindowText() + { + // Setup + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + + // Call + form.Show(); + + // Assert + Assert.AreEqual("Berichten", messageWindow.Text); + } + } + + [Test] + public void AddMessage_LevelIsNull_ThrowsArgumentNullException() + { + // Setup + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + // Call + TestDelegate call = () => messageWindow.AddMessage(null, new DateTime(), + "Should throw exception"); + + // Assert + string paramName = Assert.Throws(call).ParamName; + Assert.AreEqual("level", paramName); + } + } + + [Test] + public void GivenMessageWindow_WhenMultipleMessagesAdded_ThenFirstColumnOnFirstRowIsSelected() + { + // Given + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + var dataGridView = (DataGridView) new ControlTester("messagesDataGridView").TheObject; + Level topLeftCellValue = Level.Info; + + // Precondition + Assert.IsNull(dataGridView.CurrentCell); + + // When + messageWindow.AddMessage(Level.Warn, new DateTime(), "DetailedWarnMessage"); + messageWindow.AddMessage(Level.Error, new DateTime(), "DetailedErrorMessage"); + messageWindow.AddMessage(topLeftCellValue, new DateTime(), "DetailedInfoMessage"); + messageWindow.Refresh(); + + // Then + Assert.IsNotNull(dataGridView.CurrentCell); + + DataGridViewCell topLeftCell = dataGridView.Rows[0].Cells[0]; + Assert.AreSame(topLeftCell, dataGridView.CurrentCell); + Assert.AreEqual(topLeftCellValue.ToString(), dataGridView.CurrentCell.Value); + } + } + + [Test] + public void ShowDetailsButton_NoMessageSelectedOnClick_DoNotShowMessageWindowDialog() + { + // Setup + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + var button = new ToolStripButtonTester("buttonShowDetails"); + + // Call + button.Click(); + + // Assert + // No dialog window shown + } + } + + [Test] + public void ShowDetailsButton_MessageSelectedOnClick_ShowMessageWindowDialogWithDetails() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + mocks.ReplayAll(); + + const string detailedMessage = "TestDetailedMessage"; + + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(dialogParent)) + { + form.Controls.Add(messageWindow); + form.Show(); + + string dialogTitle = null; + string dialogText = null; + + DialogBoxHandler = (name, wnd) => + { + var dialogTester = new FormTester(name); + dialogTitle = ((Form) dialogTester.TheObject).Text; + var testBoxTester = new TextBoxTester("textBox"); + dialogText = testBoxTester.Text; + dialogTester.Close(); + }; + messageWindow.AddMessage(Level.Warn, new DateTime(), detailedMessage); + messageWindow.Refresh(); + var buttonTester = new ToolStripButtonTester("buttonShowDetails"); + + // Call + buttonTester.Click(); + + // Assert + Assert.AreEqual("Berichtdetails", dialogTitle); + Assert.AreEqual(detailedMessage, dialogText); + } + + mocks.VerifyAll(); + } + + [Test] + public void ShowDetailsButton_NoMessageSelectedOnDoubleClick_DoNotShowMessageWindowDialog() + { + // Setup + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + var gridView = new ControlTester("messagesDataGridView"); + + // Call + gridView.DoubleClick(); + + // Assert + // No dialog window shown + } + } + + [Test] + public void ShowDetailsButton_DoubleClickOnRowHeader_DoesShowMessageWindowDialog() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + mocks.ReplayAll(); + const string detailedMessage = "TestDetailedMessage"; + + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(dialogParent)) + { + form.Controls.Add(messageWindow); + form.Show(); + + string dialogTitle = null; + string dialogText = null; + + DialogBoxHandler = (name, wnd) => + { + var dialogTester = new FormTester(name); + dialogTitle = ((Form) dialogTester.TheObject).Text; + var testBoxTester = new TextBoxTester("textBox"); + dialogText = testBoxTester.Text; + dialogTester.Close(); + }; + + var gridView = new ControlTester("messagesDataGridView"); + messageWindow.AddMessage(Level.Warn, new DateTime(), detailedMessage); + messageWindow.Refresh(); + int rowHeaderColumnIndex = ((DataGridView) gridView.TheObject).Rows[0].HeaderCell.ColumnIndex; + + // Call + gridView.FireEvent("CellMouseDoubleClick", new DataGridViewCellMouseEventArgs( + rowHeaderColumnIndex, 0, 0, 0, + new MouseEventArgs(MouseButtons.Left, 2, 0, 0, 0))); + + // Assert + Assert.AreEqual("Berichtdetails", dialogTitle); + Assert.AreEqual(detailedMessage, dialogText); + } + } + + [Test] + public void ShowDetailsButton_DoubleClickOnColumnHeader_DoNotShowMessageWindowDialog() + { + // Setup + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + var gridView = new ControlTester("messagesDataGridView"); + messageWindow.AddMessage(Level.Warn, new DateTime(), "TestDetailedMessage"); + messageWindow.Refresh(); + int columnHeaderRowIndex = ((DataGridView) gridView.TheObject).Columns[0].HeaderCell.RowIndex; + + // Call + gridView.FireEvent("CellMouseDoubleClick", new DataGridViewCellMouseEventArgs( + 0, columnHeaderRowIndex, 0, 0, + new MouseEventArgs(MouseButtons.Left, 2, 0, 0, 0))); + + // Assert + // No dialog window shown + } + } + + [Test] + [TestCase(MouseButtons.Middle)] + [TestCase(MouseButtons.None)] + [TestCase(MouseButtons.Right)] + [TestCase(MouseButtons.XButton1)] + [TestCase(MouseButtons.XButton2)] + public void ShowDetailsButton_MessageSelectedOnDoubleClickOtherThanLeft_DoNotShowMessageWindowDialog(MouseButtons mouseButton) + { + // Setup + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + var gridView = new ControlTester("messagesDataGridView"); + messageWindow.AddMessage(Level.Warn, new DateTime(), "TestDetailedMessage"); + messageWindow.Refresh(); + + // Call + gridView.FireEvent("CellMouseDoubleClick", new DataGridViewCellMouseEventArgs( + 0, 0, 0, 0, + new MouseEventArgs(mouseButton, 2, 0, 0, 0))); + + // Assert + // No dialog window shown + } + } + + [Test] + public void ShowDetailsButton_MessageSelectedOnDoubleClick_ShowMessageWindowDialogWithDetails() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + mocks.ReplayAll(); + const string detailedMessage = "TestDetailedMessage"; + + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(dialogParent)) + { + form.Controls.Add(messageWindow); + form.Show(); + + string dialogTitle = null; + string dialogText = null; + + DialogBoxHandler = (name, wnd) => + { + var dialogTester = new FormTester(name); + dialogTitle = ((Form) dialogTester.TheObject).Text; + var testBoxTester = new TextBoxTester("textBox"); + dialogText = testBoxTester.Text; + dialogTester.Close(); + }; + + var gridView = new ControlTester("messagesDataGridView"); + messageWindow.AddMessage(Level.Warn, new DateTime(), detailedMessage); + messageWindow.Refresh(); + + // Call + gridView.FireEvent("CellMouseDoubleClick", new DataGridViewCellMouseEventArgs( + 0, 0, 0, 0, + new MouseEventArgs(MouseButtons.Left, 2, 0, 0, 0))); + + // Assert + Assert.AreEqual("Berichtdetails", dialogTitle); + Assert.AreEqual(detailedMessage, dialogText); + } + + mocks.VerifyAll(); + } + + [Test] + public void ShowDetailsButton_NoMessageSelectedOnEnterKeyDown_DoNotShowMessageWindowDialog() + { + // Setup + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + var gridView = new ControlTester("messagesDataGridView"); + + // Call + gridView.FireEvent("KeyDown", new KeyEventArgs(Keys.Enter)); + + // Assert + // No dialog window shown + } + } + + [Test] + public void ShowDetailsButton_MessageSelectedOnEnterKeyDown_ShowMessageWindowDialogWithDetails() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + mocks.ReplayAll(); + const string detailedMessage = "TestDetailedMessage"; + + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(dialogParent)) + { + form.Controls.Add(messageWindow); + form.Show(); + + string dialogTitle = null; + string dialogText = null; + + DialogBoxHandler = (name, wnd) => + { + var dialogTester = new FormTester(name); + dialogTitle = ((Form) dialogTester.TheObject).Text; + var testBoxTester = new TextBoxTester("textBox"); + dialogText = testBoxTester.Text; + dialogTester.Close(); + }; + + var gridView = new ControlTester("messagesDataGridView"); + messageWindow.AddMessage(Level.Warn, new DateTime(), detailedMessage); + messageWindow.Refresh(); + + // Call + gridView.FireEvent("KeyDown", new KeyEventArgs(Keys.Enter)); + + // Assert + Assert.AreEqual("Berichtdetails", dialogTitle); + Assert.AreEqual(detailedMessage, dialogText); + } + + mocks.VerifyAll(); + } + + [Test] + public void ButtonClearAll_Click_RemovesAllMessages() + { + // Setup + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + messageWindow.AddMessage(Level.Warn, new DateTime(), "message"); + messageWindow.Refresh(); + var dataGridView = (DataGridView) new ControlTester("messagesDataGridView").TheObject; + + var button = new ToolStripItemTester("buttonClearAll"); + + // Call + button.Click(); + + // Assert + Assert.AreEqual(0, dataGridView.Rows.Count); + } + } + + [Test] + public void ButtonCopy_Click_CopiesContentToClipboard() + { + // Setup + using (var form = new Form()) + using (new ClipboardConfig()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + messageWindow.AddMessage(Level.Warn, new DateTime(), "message"); + messageWindow.Refresh(); + + var button = new ToolStripItemTester("buttonCopy"); + + // Call + button.Click(); + + // Assert + IDataObject actualDataObject = ClipboardProvider.Clipboard.GetDataObject(); + Assert.IsTrue(actualDataObject != null && actualDataObject.GetDataPresent(DataFormats.Text)); + var actualContent = (string) actualDataObject.GetData(DataFormats.Text); + Assert.AreEqual("\t00:00:00\tmessage", actualContent); + } + } + + [Test] + public void ButtonShowInfo_ButtonUnchecked_FiltersInfoMessages() + { + // Setup + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + AddMessages(messageWindow); + var dataGridView = (DataGridView) new ControlTester("messagesDataGridView").TheObject; + + var button = new ToolStripButtonTester("buttonShowInfo"); + + // Call + button.Click(); + + // Assert + Assert.IsFalse(((ToolStripButton) button.TheObject).Checked); + Assert.AreEqual(2, dataGridView.Rows.Count); + string filteredLevel = Level.Info.ToString(); + foreach (DataGridViewRow row in dataGridView.Rows) + { + Assert.AreNotEqual(filteredLevel, row.Cells[0].Value.ToString()); + } + } + } + + [Test] + public void ButtonShowWarn_ButtonUnchecked_FiltersWarningMessages() + { + // Setup + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + AddMessages(messageWindow); + var dataGridView = (DataGridView) new ControlTester("messagesDataGridView").TheObject; + var button = new ToolStripButtonTester("buttonShowWarning"); + + // Call + button.Click(); + + // Assert + Assert.IsFalse(((ToolStripButton) button.TheObject).Checked); + Assert.AreEqual(2, dataGridView.Rows.Count); + string filteredLevel = Level.Warn.ToString(); + foreach (DataGridViewRow row in dataGridView.Rows) + { + Assert.AreNotEqual(filteredLevel, row.Cells[0].Value.ToString()); + } + } + } + + [Test] + public void ButtonShowError_ButtonUnchecked_FiltersErrorMessages() + { + // Setup + using (var form = new Form()) + using (GuiFormsMessageWindow.MessageWindow messageWindow = ShowMessageWindow(null)) + { + form.Controls.Add(messageWindow); + form.Show(); + + AddMessages(messageWindow); + var dataGridView = (DataGridView) new ControlTester("messagesDataGridView").TheObject; + var button = new ToolStripButtonTester("buttonShowError"); + + // Call + button.Click(); + + // Assert + Assert.IsFalse(((ToolStripButton) button.TheObject).Checked); + Assert.AreEqual(2, dataGridView.Rows.Count); + string filteredLevel = Level.Error.ToString(); + foreach (DataGridViewRow row in dataGridView.Rows) + { + Assert.AreNotEqual(filteredLevel, row.Cells[0].Value.ToString()); + } + } + } + + public override void Setup() + { + originalValue = GuiFormsMessageWindow.MessageWindowLogAppender.Instance; + } + + public override void TearDown() + { + base.TearDown(); + GuiFormsMessageWindow.MessageWindowLogAppender.Instance = originalValue; + } + + private static void AddMessages(GuiFormsMessageWindow.MessageWindow messageWindow) + { + messageWindow.AddMessage(Level.Info, new DateTime(), "Info message"); + messageWindow.AddMessage(Level.Warn, new DateTime(), "Warn message"); + messageWindow.AddMessage(Level.Error, new DateTime(), "Error message"); + messageWindow.Refresh(); + } + + private GuiFormsMessageWindow.MessageWindow ShowMessageWindow(IWin32Window dialogParent) + { + var logAppender = new GuiFormsMessageWindow.MessageWindowLogAppender(); + + // Precondition + Assert.AreSame(logAppender, GuiFormsMessageWindow.MessageWindowLogAppender.Instance); + + return new GuiFormsMessageWindow.MessageWindow(dialogParent); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/ProgressDialog/ActivityProgressDialogTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/ProgressDialog/ActivityProgressDialogTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/ProgressDialog/ActivityProgressDialogTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,95 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Linq; +using System.Windows.Forms; +using Core.Common.Base.Service; +using Core.Common.Controls.Dialogs; +using Core.Gui.Forms.ProgressDialog; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Forms.ProgressDialog +{ + [TestFixture] + public class ActivityProgressDialogTest : NUnitFormTest + { + [Test] + public void DefaultConstructor_ExpectedValue() + { + // Setup + var mocks = new MockRepository(); + var window = mocks.Stub(); + + mocks.ReplayAll(); + + // Call + using (var dialog = new ActivityProgressDialog(window, Enumerable.Empty())) + { + // Assert + Assert.IsInstanceOf(dialog); + Assert.IsNotNull(dialog.Icon); + Assert.IsTrue(dialog.ShowIcon); + Assert.AreEqual(0, dialog.MinimumSize.Width); // Set during load + Assert.AreEqual(0, dialog.MinimumSize.Height); // Set during load + Assert.AreEqual(FormBorderStyle.FixedDialog, dialog.FormBorderStyle); + Assert.AreEqual(FormStartPosition.CenterParent, dialog.StartPosition); + Assert.IsFalse(dialog.ShowInTaskbar); + Assert.IsTrue(dialog.ControlBox); + Assert.IsFalse(dialog.MaximizeBox); + Assert.IsFalse(dialog.MinimizeBox); + Assert.IsNull(dialog.CancelButton); + } + + mocks.VerifyAll(); + } + + [Test] + public void ShowDialog_ActivityProgressDialog_MinimumSizeSet() + { + // Setup + var mocks = new MockRepository(); + var window = mocks.Stub(); + + mocks.ReplayAll(); + + DialogBoxHandler = (name, wnd) => + { + var openedDialog = new FormTester(name); + + openedDialog.Close(); + }; + + using (var dialog = new ActivityProgressDialog(window, Enumerable.Empty())) + { + // Call + dialog.ShowDialog(); + + // Assert + Assert.AreEqual(520, dialog.MinimumSize.Width); + Assert.AreEqual(150, dialog.MinimumSize.Height); + } + + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/ProjectExplorer/ProjectExplorerTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/ProjectExplorer/ProjectExplorerTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/ProjectExplorer/ProjectExplorerTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,316 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Windows.Forms; +using Core.Common.Base.Data; +using Core.Common.Controls.TreeView; +using Core.Common.TestUtil; +using Core.Common.Util.Reflection; +using Core.Gui.Commands; +using Core.Gui.Forms.ProjectExplorer; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Forms.ProjectExplorer +{ + [TestFixture] + public class ProjectExplorerTest : NUnitFormTest + { + [Test] + public void Constructor_ViewCommandsNull_ThrowsArgumentNullException() + { + // Call + void Call() => new Gui.Forms.ProjectExplorer.ProjectExplorer(null, Enumerable.Empty()); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("viewCommands", exception.ParamName); + } + + [Test] + public void Constructor_TreeNodeInfosNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var viewCommands = mocks.Stub(); + mocks.ReplayAll(); + + // Call + void Call() => new Gui.Forms.ProjectExplorer.ProjectExplorer(viewCommands, null); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("treeNodeInfos", exception.ParamName); + mocks.VerifyAll(); + } + + [Test] + public void Constructor_ExpectedValues() + { + // Setup + var mocks = new MockRepository(); + var viewCommands = mocks.StrictMock(); + mocks.ReplayAll(); + + // Call + using (var explorer = new Gui.Forms.ProjectExplorer.ProjectExplorer(viewCommands, Enumerable.Empty())) + { + // Assert + Assert.IsInstanceOf(explorer); + Assert.IsInstanceOf(explorer); + Assert.IsNull(explorer.Data); + } + + mocks.VerifyAll(); + } + + [Test] + public void Data_Always_SetTreeViewControlData() + { + // Setup + var mocks = new MockRepository(); + var viewCommands = mocks.Stub(); + var project = mocks.Stub(); + mocks.ReplayAll(); + + IEnumerable treeNodeInfos = new[] + { + new TreeNodeInfo + { + TagType = typeof(IProject) + } + }; + + using (var explorer = new Gui.Forms.ProjectExplorer.ProjectExplorer(viewCommands, treeNodeInfos)) + { + var treeViewControl = TypeUtils.GetField(explorer, "treeViewControl"); + + // Call + explorer.Data = project; + + // Assert + Assert.AreSame(project, treeViewControl.Data); + } + + mocks.VerifyAll(); + } + + [Test] + public void ProjectDataDeleted_Always_CallsRemoveAllViewsForItemWithTag() + { + // Setup + var mocks = new MockRepository(); + var project = mocks.Stub(); + var viewCommands = mocks.StrictMock(); + viewCommands.Expect(vc => vc.RemoveAllViewsForItem(project)); + mocks.ReplayAll(); + + IEnumerable treeNodeInfos = new[] + { + new TreeNodeInfo + { + TagType = typeof(IProject), + CanRemove = (item, parent) => true + } + }; + + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + messageBox.ClickOk(); + }; + + using (var explorer = new Gui.Forms.ProjectExplorer.ProjectExplorer(viewCommands, treeNodeInfos) + { + Data = project + }) + { + var treeViewControl = TypeUtils.GetField(explorer, "treeViewControl"); + + // Call + treeViewControl.TryRemoveNodeForData(project); + } + + // Assert + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void TreeViewSelectedNodeChanged_Always_SelectionChangedFired() + { + // Setup + var mocks = new MockRepository(); + var viewCommands = mocks.StrictMock(); + var project = mocks.Stub(); + mocks.ReplayAll(); + + const string stringA = "testA"; + const string stringB = "testB"; + + IEnumerable treeNodeInfos = new[] + { + new TreeNodeInfo + { + TagType = typeof(IProject), + ChildNodeObjects = o => new object[] + { + stringA, + stringB + } + }, + new TreeNodeInfo + { + TagType = typeof(string) + } + }; + + using (var explorer = new Gui.Forms.ProjectExplorer.ProjectExplorer(viewCommands, treeNodeInfos) + { + Data = project + }) + { + var treeViewControl = TypeUtils.GetField(explorer, "treeViewControl"); + + WindowsFormsTestHelper.Show(treeViewControl); + + var selectionChangedCount = 0; + explorer.SelectionChanged += (sender, args) => selectionChangedCount++; + + // Call + treeViewControl.TrySelectNodeForData(stringA); + + // Assert + Assert.AreEqual(1, selectionChangedCount); + } + + WindowsFormsTestHelper.CloseAll(); + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void TreeViewEnterPress_Always_OpenViewForSelection() + { + // Setup + const string treeIdentifier = "SomeName"; + const string formIdentifier = "SomeForm"; + + var mocks = new MockRepository(); + var viewCommands = mocks.StrictMock(); + viewCommands.Expect(a => a.OpenViewForSelection()); + var project = mocks.Stub(); + mocks.ReplayAll(); + + IEnumerable treeNodeInfos = new[] + { + new TreeNodeInfo + { + TagType = typeof(IProject) + } + }; + + using (var explorer = new Gui.Forms.ProjectExplorer.ProjectExplorer(viewCommands, treeNodeInfos) + { + Data = project + }) + { + var form = new Form + { + Name = formIdentifier + }; + form.Controls.Add(explorer); + form.Show(); + + var treeViewControl = TypeUtils.GetField(explorer, "treeViewControl"); + + TypeUtils.GetField(treeViewControl, "treeView").Name = treeIdentifier; + + // Precondition + Assert.AreSame(treeViewControl.SelectedData, project); + + var tester = new TreeViewTester(treeIdentifier); + + // Call + tester.DoubleClick(); + } + + // Assert + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Selection_Always_ReturnsSelectedNodeData() + { + // Setup + var mocks = new MockRepository(); + var viewCommands = mocks.Stub(); + var project = mocks.Stub(); + mocks.ReplayAll(); + + const string stringA = "testA"; + const string stringB = "testB"; + + IEnumerable treeNodeInfos = new[] + { + new TreeNodeInfo + { + TagType = typeof(IProject), + ChildNodeObjects = o => new object[] + { + stringA, + stringB + } + }, + new TreeNodeInfo + { + TagType = typeof(string) + } + }; + + using (var explorer = new Gui.Forms.ProjectExplorer.ProjectExplorer(viewCommands, treeNodeInfos) + { + Data = project + }) + { + var treeViewControl = TypeUtils.GetField(explorer, "treeViewControl"); + + WindowsFormsTestHelper.Show(treeViewControl); + treeViewControl.TrySelectNodeForData(stringA); + + // Call + object selection = explorer.Selection; + + // Assert + Assert.AreSame(stringA, selection); + } + + WindowsFormsTestHelper.CloseAll(); + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/PropertyGridView/PropertyGridViewTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/PropertyGridView/PropertyGridViewTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/PropertyGridView/PropertyGridViewTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,408 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Base; +using Core.Common.Controls.Views; +using Core.Gui.Forms.PropertyGridView; +using Core.Gui.PropertyBag; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Forms.PropertyGridView +{ + [TestFixture] + public class PropertyGridViewTest + { + [Test] + public void Constructor_PropertyResolverIsNull_ThrowsArgumentNullException() + { + // Call + void Call() => new Gui.Forms.PropertyGridView.PropertyGridView(null); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("propertyResolver", exception.ParamName); + } + + [Test] + public void Constructor_ValidParameters_ExpectedValues() + { + // Setup + var mockRepository = new MockRepository(); + var propertyResolver = mockRepository.Stub(); + mockRepository.ReplayAll(); + + // Call + using (var propertyGridView = new Gui.Forms.PropertyGridView.PropertyGridView(propertyResolver)) + { + // Assert + Assert.IsInstanceOf(propertyGridView); + Assert.IsInstanceOf(propertyGridView); + Assert.IsNull(propertyGridView.Data); + Assert.AreEqual(PropertySort.Categorized, propertyGridView.PropertySort); + Assert.AreEqual("PropertiesPanelGridView", propertyGridView.Name); + + ToolStrip toolStrip = propertyGridView.Controls.OfType().First(); + Assert.AreEqual("Gecategoriseerd", toolStrip.Items[0].ToolTipText); + Assert.AreEqual("Alfabetisch", toolStrip.Items[1].ToolTipText); + } + + mockRepository.VerifyAll(); + } + + [Test] + public void Show_ValidParameter_ExpectedProperties() + { + // Setup + var mockRepository = new MockRepository(); + var propertyResolver = mockRepository.Stub(); + mockRepository.ReplayAll(); + + using (var form = new Form()) + using (var propertyGridView = new Gui.Forms.PropertyGridView.PropertyGridView(propertyResolver)) + { + form.Controls.Add(propertyGridView); + + // Call + form.Show(); + + // Assert + ToolStrip toolStrip = propertyGridView.Controls.OfType().First(); + Assert.AreEqual(5, toolStrip.Items.Count); + Assert.IsTrue(toolStrip.Items[0].Visible); + Assert.IsTrue(toolStrip.Items[1].Visible); + Assert.IsFalse(toolStrip.Items[2].Visible); + Assert.IsFalse(toolStrip.Items[3].Visible); + Assert.IsFalse(toolStrip.Items[4].Visible); + } + + mockRepository.VerifyAll(); + } + + [Test] + public void Data_SetNull_UpdateView() + { + // Setup + var dataObject = new object(); + + var mockRepository = new MockRepository(); + var propertyResolver = mockRepository.StrictMock(); + propertyResolver.Expect(prs => prs.GetObjectProperties(dataObject)).Return(null); + propertyResolver.Expect(prs => prs.GetObjectProperties(null)).Return(null); + mockRepository.ReplayAll(); + + using (var propertyGridView = new TestGuiPropertyGridView(propertyResolver)) + { + propertyGridView.Data = dataObject; + + object selectedObject = propertyGridView.SelectedObject; + + // Call + propertyGridView.Data = null; + + // Assert + Assert.AreSame(selectedObject, propertyGridView.SelectedObject); + Assert.AreEqual(0, propertyGridView.RefreshCalled); + } + + mockRepository.VerifyAll(); + } + + [Test] + public void Data_SetSameDataObject_NoRedundantViewUpdate() + { + // Setup + var dataObject = new object(); + + var mockRepository = new MockRepository(); + var propertyResolver = mockRepository.StrictMock(); + propertyResolver.Expect(prs => prs.GetObjectProperties(dataObject)).Return(null); + mockRepository.ReplayAll(); + + using (var propertyGridView = new TestGuiPropertyGridView(propertyResolver)) + { + propertyGridView.Data = dataObject; + + object selectedObject = propertyGridView.SelectedObject; + + // Call + propertyGridView.Data = dataObject; + + // Assert + Assert.AreSame(selectedObject, propertyGridView.SelectedObject); + Assert.AreEqual(0, propertyGridView.RefreshCalled); + } + + mockRepository.VerifyAll(); + } + + [Test] + public void GivenPropertyGridViewWithDisposableDataSet_WhenNewDataObjectSet_ThenPreviousDataDisposed() + { + // Given + var mockRepository = new MockRepository(); + var dataObject = new object(); + object dataObjectProperties = mockRepository.StrictMultiMock(typeof(IDisposable), typeof(IObjectProperties)); + dataObjectProperties.Expect(d => ((IDisposable) d).Dispose()); + dataObjectProperties.Expect(d => ((IObjectProperties) d).RefreshRequired += null).IgnoreArguments(); + dataObjectProperties.Expect(d => ((IObjectProperties) d).RefreshRequired -= null).IgnoreArguments(); + dataObjectProperties.Stub(d => ((IObjectProperties) d).Data).Return(dataObject); + + var newDataObject = new object(); + var propertyResolver = mockRepository.StrictMock(); + propertyResolver.Expect(prs => prs.GetObjectProperties(dataObject)).Return(new DynamicPropertyBag(dataObjectProperties)); + propertyResolver.Expect(prs => prs.GetObjectProperties(newDataObject)).Return(null); + mockRepository.ReplayAll(); + + using (var propertyGridView = new TestGuiPropertyGridView(propertyResolver)) + { + propertyGridView.Data = dataObject; + + // When + propertyGridView.Data = newDataObject; + } + + // Then + mockRepository.VerifyAll(); + } + + [Test] + public void GivenPropertyGridViewWithObservableDataSet_WhenNewDataObjectSet_ThenPreviousDataObserverDetached() + { + // Given + var mockRepository = new MockRepository(); + var observableDataObject = mockRepository.StrictMock(); + observableDataObject.Expect(d => d.Attach(null)).IgnoreArguments(); + observableDataObject.Expect(d => d.Detach(null)).IgnoreArguments(); + var dataObjectProperties = mockRepository.Stub(); + dataObjectProperties.Data = observableDataObject; + + var newDataObject = new object(); + var propertyResolver = mockRepository.StrictMock(); + propertyResolver.Expect(prs => prs.GetObjectProperties(observableDataObject)).Return(new DynamicPropertyBag(dataObjectProperties)); + propertyResolver.Expect(prs => prs.GetObjectProperties(newDataObject)).Return(null); + mockRepository.ReplayAll(); + + using (var propertyGridView = new TestGuiPropertyGridView(propertyResolver)) + { + propertyGridView.Data = observableDataObject; + + // When + propertyGridView.Data = newDataObject; + } + + // Then + mockRepository.VerifyAll(); + } + + [Test] + public void GivenPropertyGridViewWithDisposableDataSet_WhenDisposing_ThenObjectPropertiesCorrectlyDisposed() + { + // Given + var mockRepository = new MockRepository(); + var dataObject = new object(); + object dataObjectProperties = mockRepository.StrictMultiMock(typeof(IDisposable), typeof(IObjectProperties)); + dataObjectProperties.Expect(d => ((IDisposable) d).Dispose()); + dataObjectProperties.Expect(d => ((IObjectProperties) d).RefreshRequired += null).IgnoreArguments(); + dataObjectProperties.Expect(d => ((IObjectProperties) d).RefreshRequired -= null).IgnoreArguments(); + dataObjectProperties.Stub(d => ((IObjectProperties) d).Data).Return(dataObject); + + var propertyResolver = mockRepository.StrictMock(); + propertyResolver.Expect(prs => prs.GetObjectProperties(dataObject)).Return(new DynamicPropertyBag(dataObjectProperties)); + mockRepository.ReplayAll(); + + var propertyGridView = new TestGuiPropertyGridView(propertyResolver) + { + Data = dataObject + }; + + // When + propertyGridView.Dispose(); + + // Then + mockRepository.VerifyAll(); + } + + [Test] + public void GivenPropertyGridViewWithDataSet_WhenRefreshRequiredEventRaised_ThenRefreshTriggered() + { + // Given + var dataObject = new object(); + + var mockRepository = new MockRepository(); + var objectProperties = mockRepository.Stub(); + var propertyResolver = mockRepository.StrictMock(); + propertyResolver.Expect(prs => prs.GetObjectProperties(dataObject)).Return(new DynamicPropertyBag(objectProperties)); + mockRepository.ReplayAll(); + + using (var propertyGridView = new TestGuiPropertyGridView(propertyResolver) + { + Data = dataObject + }) + { + // When + objectProperties.Raise(p => p.RefreshRequired += null, + objectProperties, + EventArgs.Empty); + + // Then + Assert.AreEqual(1, propertyGridView.RefreshCalled); + } + + mockRepository.VerifyAll(); + } + + [Test] + public void GivenDisposedPropertyGridViewWithDataSet_WhenRefreshRequiredEventRaised_ThenRefreshNotTriggered() + { + // Given + var dataObject = new object(); + + var mockRepository = new MockRepository(); + var objectProperties = mockRepository.Stub(); + var propertyResolver = mockRepository.StrictMock(); + propertyResolver.Expect(prs => prs.GetObjectProperties(dataObject)).Return(new DynamicPropertyBag(objectProperties)); + mockRepository.ReplayAll(); + + var propertyGridView = new TestGuiPropertyGridView(propertyResolver) + { + Data = dataObject + }; + + propertyGridView.Dispose(); + + // When + objectProperties.Raise(p => p.RefreshRequired += null, + objectProperties, + EventArgs.Empty); + + // Then + Assert.AreEqual(0, propertyGridView.RefreshCalled); + mockRepository.VerifyAll(); + } + + [Test] + public void GivenPropertyGridViewWithNewDataSet_WhenRefreshRequiredEventRaisedOnNewlySetData_ThenRefreshTriggered() + { + // Given + var dataObject1 = new object(); + var dataObject2 = new object(); + + var mockRepository = new MockRepository(); + var objectProperties1 = mockRepository.Stub(); + var objectProperties2 = mockRepository.Stub(); + var propertyResolver = mockRepository.StrictMock(); + propertyResolver.Expect(prs => prs.GetObjectProperties(dataObject1)).Return(new DynamicPropertyBag(objectProperties1)); + propertyResolver.Expect(prs => prs.GetObjectProperties(dataObject2)).Return(new DynamicPropertyBag(objectProperties2)); + mockRepository.ReplayAll(); + + using (var propertyGridView = new TestGuiPropertyGridView(propertyResolver) + { + Data = dataObject1 + }) + { + propertyGridView.Data = dataObject2; + + // When + objectProperties2.Raise(p => p.RefreshRequired += null, + objectProperties2, + EventArgs.Empty); + + // Then + Assert.AreEqual(1, propertyGridView.RefreshCalled); + } + + mockRepository.VerifyAll(); + } + + [Test] + public void GivenPropertyGridViewWithNewDataSet_WhenRefreshRequiredEventRaisedOnPreviouslySetData_ThenRefreshNotTriggered() + { + // Given + var dataObject1 = new object(); + var dataObject2 = new object(); + + var mockRepository = new MockRepository(); + var objectProperties1 = mockRepository.Stub(); + var objectProperties2 = mockRepository.Stub(); + var propertyResolver = mockRepository.StrictMock(); + propertyResolver.Expect(prs => prs.GetObjectProperties(dataObject1)).Return(new DynamicPropertyBag(objectProperties1)); + propertyResolver.Expect(prs => prs.GetObjectProperties(dataObject2)).Return(new DynamicPropertyBag(objectProperties2)); + mockRepository.ReplayAll(); + + using (var propertyGridView = new TestGuiPropertyGridView(propertyResolver) + { + Data = dataObject1 + }) + { + propertyGridView.Data = dataObject2; + + // When + objectProperties1.Raise(p => p.RefreshRequired += null, + objectProperties1, + EventArgs.Empty); + + // Then + Assert.AreEqual(0, propertyGridView.RefreshCalled); + } + + mockRepository.VerifyAll(); + } + + [Test] + public void Dispose_AlreadyDisposed_DoesNotThrowException() + { + // Setup + var mockRepository = new MockRepository(); + var propertyResolver = mockRepository.Stub(); + mockRepository.ReplayAll(); + + // Call + TestDelegate call = () => + { + using (var control = new Gui.Forms.PropertyGridView.PropertyGridView(propertyResolver)) + { + control.Dispose(); + } + }; + + // Assert + Assert.DoesNotThrow(call); + mockRepository.VerifyAll(); + } + + private class TestGuiPropertyGridView : Gui.Forms.PropertyGridView.PropertyGridView + { + public TestGuiPropertyGridView(IPropertyResolver propertyResolver) : base(propertyResolver) {} + + public int RefreshCalled { get; private set; } + + public override void Refresh() + { + RefreshCalled++; + base.Refresh(); + } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/PropertyGridView/PropertyResolverTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/PropertyGridView/PropertyResolverTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/PropertyGridView/PropertyResolverTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,261 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Linq; +using Core.Common.TestUtil; +using Core.Gui.Forms.PropertyGridView; +using Core.Gui.Plugin; +using Core.Gui.PropertyBag; +using NUnit.Framework; + +namespace Core.Gui.Test.Forms.PropertyGridView +{ + [TestFixture] + public class PropertyResolverTest + { + [Test] + public void ParameteredConstructor_ExpectedValues() + { + // Call + var resolver = new PropertyResolver(Enumerable.Empty()); + + // Assert + Assert.IsInstanceOf(resolver); + } + + [Test] + public void ParameteredConstructor_InputIsNull_ThrowArgumentNullException() + { + // Call + TestDelegate call = () => new PropertyResolver(null); + + // Assert + const string expectedMessage = "Kan geen 'PropertyResolver' maken zonder een lijst van 'PropertyInfo'."; + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(call, expectedMessage); + } + + [Test] + public void GetObjectProperties_DataIsNull_ReturnNull() + { + // Setup + var propertyInfos = new PropertyInfo[] + { + new PropertyInfo() + }; + + var resolver = new PropertyResolver(propertyInfos); + + // Call + object result = resolver.GetObjectProperties(null); + + // Assert + Assert.IsNull(result); + } + + [Test] + public void GetObjectProperties_DataMatchesSinglePropertyInfoDataTypeDirectly_ReturnNewInstanceOfCorrespondingObjectProperties() + { + // Setup + var propertyInfos = new PropertyInfo[] + { + new PropertyInfo() + }; + + var resolver = new PropertyResolver(propertyInfos); + + var source = new A(); + + // Call + object result = resolver.GetObjectProperties(source); + + // Assert + Assert.IsInstanceOf(result); + Assert.IsInstanceOf(((DynamicPropertyBag) result).WrappedObject); + Assert.AreSame(source, ((IObjectProperties) ((DynamicPropertyBag) result).WrappedObject).Data); + } + + [Test] + public void GetObjectProperties_DataMatchesInfoWithCreateInstanceForCustomData_ReturnObjectPropertiesWithDataFromInjectedDelegate() + { + // Setup + var otherObject = new B + { + Name = "" + }; + var propertyInfos = new PropertyInfo[] + { + new PropertyInfo + { + CreateInstance = a => new PropertiesForA + { + Data = otherObject + } + } + }; + + var resolver = new PropertyResolver(propertyInfos); + + var source = new A(); + + // Call + object result = resolver.GetObjectProperties(source); + + // Assert + var bag = (DynamicPropertyBag) result; + var properties = (PropertiesForA) bag.WrappedObject; + Assert.AreSame(otherObject, properties.Data); + } + + [Test] + public void GetObjectProperties_DataMatchesMultiplePropertyInfoByDataTypeInheritance_PrioritizeMostSpecialized() + { + // Setup + var propertyInfos = new PropertyInfo[] + { + new PropertyInfo(), + new PropertyInfo() + }; + + var resolver = new PropertyResolver(propertyInfos); + + var source = new InheritsFromA(); + + // Call + object result = resolver.GetObjectProperties(source); + + // Assert + Assert.IsInstanceOf(result); + Assert.IsInstanceOf(((DynamicPropertyBag) result).WrappedObject); + Assert.AreSame(source, ((IObjectProperties) ((DynamicPropertyBag) result).WrappedObject).Data); + } + + [Test] + public void GetObjectProperties_DataMatchesMultiplePropertyInfoByObjectPropertiesTypeInheritance_PrioritizeMostSpecialized() + { + // Setup + var propertyInfos = new PropertyInfo[] + { + new PropertyInfo(), + new PropertyInfo() + }; + + var resolver = new PropertyResolver(propertyInfos); + + var source = new A(); + + // Call + object result = resolver.GetObjectProperties(source); + + // Assert + Assert.IsInstanceOf(result); + Assert.IsInstanceOf(((DynamicPropertyBag) result).WrappedObject); + Assert.AreSame(source, ((IObjectProperties) ((DynamicPropertyBag) result).WrappedObject).Data); + } + + [Test] + public void GetObjectProperties_DataMatchesMultiplePropertyInfoByDataTypeAndObjectPropertiesTypeInheritance_PrioritizeMostSpecializedDataTypeFollowedByMostSpecializedObjectPropertiesType() + { + // Setup + var propertyInfos = new PropertyInfo[] + { + new PropertyInfo(), + new PropertyInfo(), + new PropertyInfo(), + new PropertyInfo() + }; + + var resolver = new PropertyResolver(propertyInfos); + + var source = new InheritsFromA(); + + // Call + object result = resolver.GetObjectProperties(source); + + // Assert + Assert.IsInstanceOf(result); + Assert.IsInstanceOf(((DynamicPropertyBag) result).WrappedObject); + Assert.AreSame(source, ((IObjectProperties) ((DynamicPropertyBag) result).WrappedObject).Data); + } + + [Test] + public void GetObjectProperties_DataMatchesPropertyInfoDataTypeBase_ReturnMatchedObjectProperties() + { + // Setup + var propertyInfos = new PropertyInfo[] + { + new PropertyInfo() + }; + + var resolver = new PropertyResolver(propertyInfos); + + var source = new InheritsFromA(); + + // Call + object result = resolver.GetObjectProperties(source); + + // Assert + Assert.IsInstanceOf(result); + Assert.IsInstanceOf(((DynamicPropertyBag) result).WrappedObject); + Assert.AreSame(source, ((IObjectProperties) ((DynamicPropertyBag) result).WrappedObject).Data); + } + + [Test] + public void GetObjectProperties_DataMatchesMultipleEqualPropertyInfos_ReturnNull() + { + // Setup + var propertyInfos = new PropertyInfo[] + { + new PropertyInfo(), + new PropertyInfo() + }; + + var resolver = new PropertyResolver(propertyInfos); + + var source = new InheritsFromA(); + + // Call + object result = resolver.GetObjectProperties(source); + + // Assert + Assert.IsNull(result); + } + + #region Nested Types: various test-case classes + + private class A {} + + private class PropertiesForA : ObjectProperties {} + + private class AlternativePropertiesForA : ObjectProperties {} + + private class InheritsFromPropertiesForA : PropertiesForA {} + + private class InheritsFromA : A {} + + private class B + { + public string Name { get; set; } + } + + #endregion + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/RichTextFileTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/RichTextFileTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/RichTextFileTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,59 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using Core.Gui.Forms; +using NUnit.Framework; + +namespace Core.Gui.Test.Forms +{ + [TestFixture] + public class RichTextFileTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var file = new RichTextFile(); + + // Assert + Assert.IsNull(file.Name); + Assert.IsNull(file.FilePath); + } + + [Test] + public void SimpleProperties_SetNewValue_GetNewlySetValue() + { + // Setup + var file = new RichTextFile(); + + const string newName = ""; + const string newPath = ""; + + // Call + file.Name = newName; + file.FilePath = newPath; + + // Assert + Assert.AreEqual(newName, file.Name); + Assert.AreEqual(newPath, file.FilePath); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/RichTextViewTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/RichTextViewTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/RichTextViewTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,45 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Windows.Forms; +using Core.Common.Controls.Views; +using Core.Gui.Forms; +using NUnit.Framework; + +namespace Core.Gui.Test.Forms +{ + [TestFixture] + public class RichTextViewTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + using (var view = new RichTextView()) + { + // Assert + Assert.IsInstanceOf(view); + Assert.IsInstanceOf(view); + Assert.IsNull(view.Data); + } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/SelectItemDialogTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/SelectItemDialogTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/SelectItemDialogTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,169 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Windows.Forms; +using Core.Common.Controls.Dialogs; +using Core.Gui.Forms; +using Core.Gui.Test.Properties; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Forms +{ + [TestFixture] + public class SelectItemDialogTest : NUnitFormTest + { + [Test] + public void Constructor_WithoutDialogParent_ThrowsArgumentNullException() + { + // Call + TestDelegate test = () => new SelectItemDialog(null, string.Empty); + + // Assert + string paramName = Assert.Throws(test).ParamName; + Assert.AreEqual("dialogParent", paramName); + } + + [Test] + public void Constructor_WithDialogParent_SetProperties() + { + // Setup + var mocks = new MockRepository(); + var parent = mocks.StrictMock(); + mocks.ReplayAll(); + + // Call + using (var dialog = new SelectItemDialog(parent, "Dialog text")) + { + // Assert + Assert.IsInstanceOf(dialog); + Assert.IsNull(dialog.SelectedItemTag); + Assert.IsNull(dialog.SelectedItemTypeName); + } + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_Always_SetMinimumSize() + { + // Setup + var mocks = new MockRepository(); + var parent = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var dialog = new SelectItemDialog(parent, "Dialog text")) + { + // Call + dialog.Show(); + + // Assert + Assert.AreEqual(320, dialog.MinimumSize.Width); + Assert.AreEqual(220, dialog.MinimumSize.Height); + } + + mocks.VerifyAll(); + } + + [Test] + public void OnLoad_Text_SetsText() + { + // Setup + var mocks = new MockRepository(); + var parent = mocks.StrictMock(); + mocks.ReplayAll(); + const string text = "Dialog text"; + + using (var dialog = new SelectItemDialog(parent, text)) + { + // Call + dialog.Show(); + + // Assert + Assert.AreEqual(text, dialog.Text); + } + + mocks.VerifyAll(); + } + + [Test] + public void ButtonOkClick_NoItemSelected_ShowDialogWithText() + { + // Setup + var mocks = new MockRepository(); + var parent = mocks.StrictMock(); + mocks.ReplayAll(); + + string messageText = null; + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + messageText = messageBox.Text; + messageBox.ClickOk(); + }; + + using (var dialog = new SelectItemDialog(parent, "Dialog text")) + { + dialog.Show(); + + // Call + var okButton = new ButtonTester("buttonOk", dialog); + okButton.Click(); + + // Assert + Assert.IsNull(dialog.SelectedItemTag); + Assert.IsNull(dialog.SelectedItemTypeName); + Assert.AreEqual("Kies een type", messageText); + Assert.AreEqual(DialogResult.None, dialog.DialogResult); + } + + mocks.VerifyAll(); + } + + [Test] + public void SelectedItemTag_ItemSelected_ReturnsSelectedItem() + { + // Setup + var mocks = new MockRepository(); + var parent = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var dialog = new SelectItemDialog(parent, "Dialog text")) + { + var tag = new object(); + dialog.AddItemType("aName", "aCategory", Resources.abacus, tag); + var listView = (ListView) new ControlTester("listViewItemTypes", dialog).TheObject; + dialog.Show(); + + // Call + listView.Items[0].Selected = true; + + // Assert + Assert.AreEqual(tag, dialog.SelectedItemTag); + Assert.AreEqual("aName", dialog.SelectedItemTypeName); + } + + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/SelectViewDialogTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/SelectViewDialogTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/SelectViewDialogTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,64 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Windows.Forms; +using Core.Gui.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Forms +{ + [TestFixture] + public class SelectViewDialogTest + { + [Test] + public void Constructor_WithoutDialogParent_ThrowsArgumentNullException() + { + // Call + TestDelegate test = () => new SelectViewDialog(null); + + // Assert + string paramName = Assert.Throws(test).ParamName; + Assert.AreEqual("dialogParent", paramName); + } + + [Test] + public void Constructor_WithDialogParent_SetProperties() + { + // Setup + var mocks = new MockRepository(); + var parent = mocks.StrictMock(); + mocks.ReplayAll(); + + // Call + using (var dialog = new SelectViewDialog(parent)) + { + // Assert + Assert.IsNull(dialog.DefaultViewName); + Assert.IsNull(dialog.SelectedItem); + Assert.IsNull(dialog.Items); + } + + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/SplashScreen/SplashScreenTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/SplashScreen/SplashScreenTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/SplashScreen/SplashScreenTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,141 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using NUnit.Framework; + +namespace Core.Gui.Test.Forms.SplashScreen +{ + [TestFixture] + public class SplashScreenTest + { + [Test] + [Apartment(ApartmentState.STA)] + public void Shutdown_SplashScreenShown_ShouldBeClosed() + { + // Setup + var screen = new Gui.Forms.SplashScreen.SplashScreen(); + var screenClosedCalled = false; + screen.Closed += (sender, args) => screenClosedCalled = true; + screen.Show(); + + // Call + screen.Shutdown(); + + // Assert + Assert.IsFalse(screen.IsVisible); + Assert.IsTrue(screenClosedCalled); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void ViewProperties_SetNewValues_ShouldSetLabelTextOfUserInterfaceElements() + { + // Setup + const string strVersion = "Version1"; + const string supportEmail = ""; + const string supportPhone = ""; + + // Call + var screen = new Gui.Forms.SplashScreen.SplashScreen + { + VersionText = strVersion, + SupportEmail = supportEmail, + SupportPhoneNumber = supportPhone + }; + screen.Show(); + + // Assert + Assert.AreEqual(strVersion, GetLabelText(screen, "LabelVersion")); + Assert.AreEqual(supportEmail, GetLabelText(screen, "LabelSupportEmailAddress")); + Assert.AreEqual(supportPhone, GetLabelText(screen, "LabelSupportPhoneNumber")); + + // Teardown + screen.Close(); + } + + [Test] + [TestCase(true, true, true)] + [TestCase(true, false, false)] + [TestCase(false, true, false)] + [TestCase(false, false, false)] + [Apartment(ApartmentState.STA)] + public void ViewPropertiesVisibility_SupportValuesSet_SupportValuesShouldBeVisible( + bool emailVisible, bool phoneVisible, + bool supportUiElementsShouldBeVisible) + { + // Setup + string supportEmail = emailVisible ? "" : string.Empty; + string supportPhone = phoneVisible ? "" : string.Empty; + + // Call + var screen = new Gui.Forms.SplashScreen.SplashScreen + { + SupportPhoneNumber = supportPhone, + SupportEmail = supportEmail + }; + screen.Show(); + + // Assert + Assert.AreEqual(supportUiElementsShouldBeVisible, GetIsControlVisible(screen, "LabelSupportTitle")); + Assert.AreEqual(supportUiElementsShouldBeVisible, GetIsControlVisible(screen, "LabelSupportPhoneNumberTitle")); + Assert.AreEqual(supportUiElementsShouldBeVisible, GetIsControlVisible(screen, "LabelSupportPhoneNumber")); + Assert.AreEqual(supportUiElementsShouldBeVisible, GetIsControlVisible(screen, "LabelSupportEmailAddressTitle")); + Assert.AreEqual(supportUiElementsShouldBeVisible, GetIsControlVisible(screen, "LabelSupportEmailAddress")); + + // Teardown + screen.Close(); + } + + private static FrameworkElement FindControlRecursively(FrameworkElement parent, string name) + { + int childrenCount = VisualTreeHelper.GetChildrenCount(parent); + FrameworkElement foundChild = null; + for (var childIndex = 0; childIndex < childrenCount; childIndex++) + { + var child = (FrameworkElement) VisualTreeHelper.GetChild(parent, childIndex); + foundChild = child.Name == name ? child : FindControlRecursively(child, name); + + if (foundChild != null) + { + break; + } + } + + return foundChild; + } + + private static string GetLabelText(FrameworkElement parent, string labelName) + { + var label = FindControlRecursively(parent, labelName) as Label; + return label?.Content.ToString() ?? ""; + } + + private static bool GetIsControlVisible(FrameworkElement parent, string ctrlName) + { + var ctrl = FindControlRecursively(parent, ctrlName) as Control; + return ctrl != null && ctrl.IsVisible; + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/ViewHost/AvalonDockViewHostTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/ViewHost/AvalonDockViewHostTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/ViewHost/AvalonDockViewHostTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,879 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Threading; +using System.Windows.Forms; +using System.Windows.Forms.Integration; +using Core.Common.Controls.Views; +using Core.Common.TestUtil; +using Core.Common.Util.Reflection; +using Core.Gui.Forms.ViewHost; +using NUnit.Framework; +using Rhino.Mocks; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Core.Gui.Test.Forms.ViewHost +{ + [TestFixture] + [Apartment(ApartmentState.STA)] + public class AvalonDockViewHostTest + { + [Test] + public void Constructor_DefaultValues() + { + // Call + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + // Assert + Assert.IsInstanceOf(avalonDockViewHost); + CollectionAssert.IsEmpty(avalonDockViewHost.DocumentViews); + CollectionAssert.IsEmpty(avalonDockViewHost.ToolViews); + Assert.IsNull(avalonDockViewHost.ActiveDocumentView); + Assert.IsFalse(IsAnyViewActive(avalonDockViewHost)); + } + } + + [Test] + public void Dispose_ViewHostWithMultipleViews_ViewsClearedActiveDocumentViewSetToNullAndActiveViewEventsFired() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + var testView3 = new TestView(); + var testView4 = new TestView(); + var activeDocumentViewChangingCounter = 0; + var activeDocumentViewChangedCounter = 0; + var activeViewChangedCounter = 0; + + var avalonDockViewHost = new AvalonDockViewHost(); + + avalonDockViewHost.AddDocumentView(testView1); + avalonDockViewHost.AddDocumentView(testView2); + avalonDockViewHost.AddToolView(testView3, ToolViewLocation.Left); + avalonDockViewHost.AddToolView(testView4, ToolViewLocation.Left); + + SetActiveView(avalonDockViewHost, testView1); + + CollectionAssert.AreEqual( + new[] + { + testView3, + testView4 + }, + avalonDockViewHost.ToolViews); + + avalonDockViewHost.ActiveDocumentViewChanging += (sender, args) => activeDocumentViewChangingCounter++; + avalonDockViewHost.ActiveDocumentViewChanged += (sender, args) => activeDocumentViewChangedCounter++; + avalonDockViewHost.ActiveViewChanged += (sender, args) => activeViewChangedCounter++; + + // Call + avalonDockViewHost.Dispose(); + + // Assert + CollectionAssert.IsEmpty(avalonDockViewHost.DocumentViews); + CollectionAssert.IsEmpty(avalonDockViewHost.ToolViews); + Assert.AreNotEqual(0, activeDocumentViewChangingCounter); + Assert.AreNotEqual(0, activeDocumentViewChangedCounter); + Assert.AreNotEqual(0, activeViewChangedCounter); + Assert.IsNull(avalonDockViewHost.ActiveDocumentView); + Assert.IsFalse(IsAnyViewActive(avalonDockViewHost)); + } + + private class TestView : UserControl, IView + { + public object Data { get; set; } + } + + #region Document views + + [Test] + public void AddDocumentView_NonControlView_ViewNotAddedAndNoViewOpenedEventFired() + { + // Setup + var mocks = new MockRepository(); + var testView = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + var viewOpenedCounter = 0; + avalonDockViewHost.ViewOpened += (sender, args) => viewOpenedCounter++; + + // Call + avalonDockViewHost.AddDocumentView(testView); + + // Assert + CollectionAssert.IsEmpty(avalonDockViewHost.DocumentViews); + Assert.IsFalse(IsDocumentViewPresent(avalonDockViewHost, testView)); + Assert.AreEqual(0, viewOpenedCounter); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(1)] + [TestCase(5)] + public void AddDocumentView_MultipleTestViews_ViewsAddedAndViewOpenedEventsFired(int numberOfViewsToAdd) + { + // Setup + var viewList = new List(); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + var viewOpenedCounter = 0; + avalonDockViewHost.ViewOpened += (sender, args) => + { + Assert.AreSame(viewList.Last(), args.View); + + viewOpenedCounter++; + }; + + for (var i = 0; i < numberOfViewsToAdd; i++) + { + var testView = new TestView(); + + viewList.Add(testView); + + // Call + avalonDockViewHost.AddDocumentView(testView); + } + + // Assert + CollectionAssert.AreEqual(viewList, avalonDockViewHost.DocumentViews); + Assert.IsTrue(viewList.All(v => IsDocumentViewPresent(avalonDockViewHost, v))); + Assert.AreEqual(numberOfViewsToAdd, viewOpenedCounter); + Assert.IsNull(avalonDockViewHost.ActiveDocumentView); + } + } + + [Test] + public void AddDocumentView_DocumentViewWasAlreadyAdded_NoDuplicationNoViewOpenedEventFired() + { + // Setup + var testView = new TestView(); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testView); + + var viewOpenedCounter = 0; + avalonDockViewHost.ViewOpened += (sender, args) => viewOpenedCounter++; + + CollectionAssert.AreEqual( + new[] + { + testView + }, + avalonDockViewHost.DocumentViews); + + // Call + avalonDockViewHost.AddDocumentView(testView); + + // Assert + CollectionAssert.AreEqual( + new[] + { + testView + }, + avalonDockViewHost.DocumentViews); + Assert.AreEqual(0, viewOpenedCounter); + } + } + + [Test] + public void Remove_DocumentViewInViewHostWithMultipleViews_ViewRemoved() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testView1); + avalonDockViewHost.AddDocumentView(testView2); + + // Precondition + CollectionAssert.AreEqual( + new[] + { + testView1, + testView2 + }, + avalonDockViewHost.DocumentViews); + Assert.IsTrue(IsDocumentViewPresent(avalonDockViewHost, testView1)); + + // Call + avalonDockViewHost.Remove(testView1); + + // Assert + CollectionAssert.AreEqual( + new[] + { + testView2 + }, + avalonDockViewHost.DocumentViews); + Assert.IsFalse(IsDocumentViewPresent(avalonDockViewHost, testView1)); + } + } + + [Test] + public void Remove_DocumentView_ViewClosedEventsFired() + { + // Setup + var testView = new TestView(); + var viewClosedCounter = 0; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testView); + + avalonDockViewHost.ViewClosed += (sender, args) => + { + Assert.AreSame(testView, args.View); + + viewClosedCounter++; + }; + + // Call + avalonDockViewHost.Remove(testView); + + // Assert + Assert.AreEqual(1, viewClosedCounter); + } + } + + [Test] + public void Remove_ActiveDocumentViewInViewHostWithNoOtherDocumentViews_ActiveDocumentViewSetToNullAndActiveDocumentViewEventsFired() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + var activeDocumentViewChangingCounter = 0; + var activeDocumentViewChangedCounter = 0; + var activeViewChangedCounter = 0; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testView1); + avalonDockViewHost.AddToolView(testView2, ToolViewLocation.Left); + SetActiveView(avalonDockViewHost, testView1); + + avalonDockViewHost.ActiveDocumentViewChanging += (sender, args) => activeDocumentViewChangingCounter++; + avalonDockViewHost.ActiveDocumentViewChanged += (sender, args) => activeDocumentViewChangedCounter++; + avalonDockViewHost.ActiveViewChanged += (sender, args) => activeViewChangedCounter++; + + // Call + avalonDockViewHost.Remove(testView1); + + // Assert + Assert.AreEqual(1, activeDocumentViewChangingCounter); + Assert.AreEqual(1, activeDocumentViewChangedCounter); + Assert.AreEqual(0, activeViewChangedCounter); + Assert.IsNull(avalonDockViewHost.ActiveDocumentView); + } + } + + [Test] + public void Remove_ActiveDocumentViewInViewHostWithMultipleOtherViews_ActiveDocumentViewSetToNullAndActiveDocumentViewEventsFired() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + var testView3 = new TestView(); + var testView4 = new TestView(); + var testView5 = new TestView(); + var activeDocumentViewChangingCounter = 0; + var activeDocumentViewChangedCounter = 0; + var activeViewChangedCounter = 0; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testView1); + avalonDockViewHost.AddDocumentView(testView2); + avalonDockViewHost.AddDocumentView(testView3); + avalonDockViewHost.AddDocumentView(testView4); + avalonDockViewHost.AddToolView(testView5, ToolViewLocation.Left); + + SetActiveView(avalonDockViewHost, testView1); + + // Precondition + Assert.AreSame(testView1, avalonDockViewHost.ActiveDocumentView); + + avalonDockViewHost.ActiveDocumentViewChanging += (sender, args) => activeDocumentViewChangingCounter++; + avalonDockViewHost.ActiveDocumentViewChanged += (sender, args) => activeDocumentViewChangedCounter++; + avalonDockViewHost.ActiveViewChanged += (sender, args) => activeViewChangedCounter++; + + // Call + avalonDockViewHost.Remove(testView1); + + // Assert + Assert.AreEqual(1, activeDocumentViewChangingCounter); + Assert.AreEqual(1, activeDocumentViewChangedCounter); + Assert.AreEqual(0, activeViewChangedCounter); + Assert.IsNull(avalonDockViewHost.ActiveDocumentView); + } + } + + [Test] + public void Remove_NotActiveDocumentViewInViewHostWithMultipleOtherViews_ActiveDocumentViewNotAffectedAndNoActiveViewEventsFired() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + var testView3 = new TestView(); + var testView4 = new TestView(); + var testView5 = new TestView(); + var activeDocumentViewChangingCounter = 0; + var activeDocumentViewChangedCounter = 0; + var activeViewChangedCounter = 0; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testView1); + avalonDockViewHost.AddDocumentView(testView2); + avalonDockViewHost.AddDocumentView(testView3); + avalonDockViewHost.AddDocumentView(testView4); + avalonDockViewHost.AddToolView(testView5, ToolViewLocation.Left); + + SetActiveView(avalonDockViewHost, testView3); + + // Precondition + Assert.AreSame(testView3, avalonDockViewHost.ActiveDocumentView); + + avalonDockViewHost.ActiveDocumentViewChanging += (sender, args) => activeDocumentViewChangingCounter++; + avalonDockViewHost.ActiveDocumentViewChanged += (sender, args) => activeDocumentViewChangedCounter++; + avalonDockViewHost.ActiveViewChanged += (sender, args) => activeViewChangedCounter++; + + // Call + avalonDockViewHost.Remove(testView1); + + // Assert + Assert.AreEqual(0, activeDocumentViewChangingCounter); + Assert.AreEqual(0, activeDocumentViewChangedCounter); + Assert.AreEqual(0, activeViewChangedCounter); + Assert.AreSame(testView3, avalonDockViewHost.ActiveDocumentView); + } + } + + [Test] + public void BringToFront_ActiveDocumentView_ViewBroughtToFrontFiredButActiveViewNotAffectedAndNoActiveViewEventsFired() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + var viewBroughtToFrontCounter = 0; + var activeDocumentViewChangingCounter = 0; + var activeDocumentViewChangedCounter = 0; + var activeViewChangedCounter = 0; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testView1); + avalonDockViewHost.AddDocumentView(testView2); + SetActiveView(avalonDockViewHost, testView1); + + avalonDockViewHost.ViewBroughtToFront += (sender, args) => viewBroughtToFrontCounter++; + avalonDockViewHost.ActiveDocumentViewChanging += (sender, args) => activeDocumentViewChangingCounter++; + avalonDockViewHost.ActiveDocumentViewChanged += (sender, args) => activeDocumentViewChangedCounter++; + avalonDockViewHost.ActiveViewChanged += (sender, args) => activeViewChangedCounter++; + + // Call + avalonDockViewHost.BringToFront(testView1); + + // Assert + Assert.AreEqual(1, viewBroughtToFrontCounter); + Assert.AreEqual(0, activeDocumentViewChangingCounter); + Assert.AreEqual(0, activeDocumentViewChangedCounter); + Assert.AreEqual(0, activeViewChangedCounter); + Assert.AreSame(testView1, avalonDockViewHost.ActiveDocumentView); + Assert.IsTrue(IsActiveView(avalonDockViewHost, testView1)); + } + } + + [Test] + public void BringToFront_NonActiveDocumentView_ViewBroughtToFrontFiredButActiveViewNotAffectedAndNoActiveViewEventsFired() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + var viewBroughtToFrontCounter = 0; + var activeDocumentViewChangingCounter = 0; + var activeDocumentViewChangedCounter = 0; + var activeViewChangedCounter = 0; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testView1); + avalonDockViewHost.AddDocumentView(testView2); + SetActiveView(avalonDockViewHost, testView2); + + avalonDockViewHost.ViewBroughtToFront += (sender, args) => viewBroughtToFrontCounter++; + avalonDockViewHost.ActiveDocumentViewChanging += (sender, args) => activeDocumentViewChangingCounter++; + avalonDockViewHost.ActiveDocumentViewChanged += (sender, args) => activeDocumentViewChangedCounter++; + avalonDockViewHost.ActiveViewChanged += (sender, args) => activeViewChangedCounter++; + + // Call + avalonDockViewHost.BringToFront(testView1); + + // Assert + Assert.AreEqual(1, viewBroughtToFrontCounter); + Assert.AreEqual(0, activeDocumentViewChangingCounter); + Assert.AreEqual(0, activeDocumentViewChangedCounter); + Assert.AreEqual(0, activeViewChangedCounter); + Assert.AreSame(testView2, avalonDockViewHost.ActiveDocumentView); + Assert.IsTrue(IsActiveView(avalonDockViewHost, testView2)); + } + } + + [Test] + public void SetImage_DocumentView_ImageSet() + { + // Setup + var testView = new TestView(); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testView); + + // Precondition + Assert.IsFalse(IsImageSet(avalonDockViewHost, testView)); + + // Call + avalonDockViewHost.SetImage(testView, new Bitmap(16, 16)); + + // Assert + Assert.IsTrue(IsImageSet(avalonDockViewHost, testView)); + } + } + + #endregion + + #region Tool views + + [Test] + public void AddToolView_NonControlView_ViewNotAddedAndNoViewOpenedEventFired() + { + // Setup + var mocks = new MockRepository(); + var testView = mocks.StrictMock(); + mocks.ReplayAll(); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + var viewOpenedCounter = 0; + avalonDockViewHost.ViewOpened += (sender, args) => viewOpenedCounter++; + + // Call + avalonDockViewHost.AddToolView(testView, ToolViewLocation.Left); + + // Assert + CollectionAssert.IsEmpty(avalonDockViewHost.ToolViews); + Assert.IsFalse(IsToolViewPresent(avalonDockViewHost, testView, ToolViewLocation.Left)); + Assert.AreEqual(0, viewOpenedCounter); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(ToolViewLocation.Left)] + [TestCase(ToolViewLocation.Right)] + [TestCase(ToolViewLocation.Bottom)] + public void AddToolView_TestViews_ViewAddedAndViewOpenedEventFired(ToolViewLocation toolViewLocation) + { + // Setup + var testView = new TestView(); + IEnumerable otherToolViewLocations = Enum.GetValues(typeof(ToolViewLocation)) + .Cast() + .Except(new[] + { + toolViewLocation + }); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + var viewOpenedCounter = 0; + avalonDockViewHost.ViewOpened += (sender, args) => + { + Assert.AreSame(testView, args.View); + + viewOpenedCounter++; + }; + + // Call + avalonDockViewHost.AddToolView(testView, toolViewLocation); + + // Assert + CollectionAssert.AreEqual( + new[] + { + testView + }, + avalonDockViewHost.ToolViews); + Assert.IsTrue(IsToolViewPresent(avalonDockViewHost, testView, toolViewLocation)); + Assert.IsFalse(otherToolViewLocations.Any(tvl => IsToolViewPresent(avalonDockViewHost, testView, tvl))); + Assert.AreEqual(1, viewOpenedCounter); + } + } + + [Test] + public void AddToolView_InvalidPosition_ThrowsInvalidEnumArgumentException() + { + // Setup + const int invalidLocation = 4; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + using (var testView = new TestView()) + { + // Call + TestDelegate test = () => avalonDockViewHost.AddToolView(testView, (ToolViewLocation) invalidLocation); + + // Assert + string expectedMessage = $"The value of argument 'toolViewLocation' ({invalidLocation}) is invalid for Enum type 'ToolViewLocation'."; + string parameter = TestHelper.AssertThrowsArgumentExceptionAndTestMessage( + test, + expectedMessage).ParamName; + Assert.AreEqual("toolViewLocation", parameter); + } + } + + [Test] + public void AddToolView_DocumentViewSetAsActiveView_ActiveDocumentViewNotAffected() + { + // Setup + var testToolView = new TestView(); + var testDocumentView = new TestView(); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testDocumentView); + SetActiveView(avalonDockViewHost, testDocumentView); + + // Call + avalonDockViewHost.AddToolView(testToolView, ToolViewLocation.Left); + + // Assert + Assert.AreSame(testDocumentView, avalonDockViewHost.ActiveDocumentView); + Assert.IsTrue(IsActiveView(avalonDockViewHost, testDocumentView)); + } + } + + [Test] + public void AddToolView_ToolViewWasAlreadyAdded_NoDuplicationNoViewOpenedEventFired() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddToolView(testView1, ToolViewLocation.Left); + avalonDockViewHost.AddToolView(testView2, ToolViewLocation.Left); + + var viewOpenedCounter = 0; + avalonDockViewHost.ViewOpened += (sender, args) => viewOpenedCounter++; + + // Call + avalonDockViewHost.AddToolView(testView1, ToolViewLocation.Right); + + // Assert + CollectionAssert.AreEqual( + new[] + { + testView1, + testView2 + }, + avalonDockViewHost.ToolViews); + Assert.AreEqual(0, viewOpenedCounter); + } + } + + [Test] + public void Remove_ToolViewInViewHostWithMultipleViews_ViewRemoved() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddToolView(testView1, ToolViewLocation.Left); + avalonDockViewHost.AddToolView(testView2, ToolViewLocation.Left); + + // Precondition + CollectionAssert.AreEqual( + new[] + { + testView1, + testView2 + }, + avalonDockViewHost.ToolViews); + + // Call + avalonDockViewHost.Remove(testView1); + + // Assert + CollectionAssert.AreEqual( + new[] + { + testView2 + }, + avalonDockViewHost.ToolViews); + } + } + + [Test] + public void Remove_ToolView_ViewClosedEventsFired() + { + // Setup + var testView = new TestView(); + var viewClosedCounter = 0; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddToolView(testView, ToolViewLocation.Left); + + avalonDockViewHost.ViewClosed += (sender, args) => + { + Assert.AreSame(testView, args.View); + + viewClosedCounter++; + }; + + // Call + avalonDockViewHost.Remove(testView); + + // Assert + Assert.AreEqual(1, viewClosedCounter); + } + } + + [Test] + public void Remove_ToolViewInViewHostWithMultipleOtherViews_ActiveDocumentViewNotAffectedAndNoActiveViewEventsFired() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + var testView3 = new TestView(); + var testView4 = new TestView(); + var testView5 = new TestView(); + var activeDocumentViewChangingCounter = 0; + var activeDocumentViewChangedCounter = 0; + var activeViewChangedCounter = 0; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddDocumentView(testView1); + avalonDockViewHost.AddDocumentView(testView2); + avalonDockViewHost.AddDocumentView(testView3); + avalonDockViewHost.AddDocumentView(testView4); + avalonDockViewHost.AddToolView(testView5, ToolViewLocation.Left); + + SetActiveView(avalonDockViewHost, testView3); + SetActiveView(avalonDockViewHost, testView5); + + // Precondition + Assert.AreSame(testView3, avalonDockViewHost.ActiveDocumentView); + + avalonDockViewHost.ActiveDocumentViewChanging += (sender, args) => activeDocumentViewChangingCounter++; + avalonDockViewHost.ActiveDocumentViewChanged += (sender, args) => activeDocumentViewChangedCounter++; + avalonDockViewHost.ActiveViewChanged += (sender, args) => activeViewChangedCounter++; + + // Call + avalonDockViewHost.Remove(testView5); + + // Assert + Assert.AreEqual(0, activeDocumentViewChangingCounter); + Assert.AreEqual(0, activeDocumentViewChangedCounter); + Assert.AreEqual(0, activeViewChangedCounter); + Assert.AreSame(testView3, avalonDockViewHost.ActiveDocumentView); + } + } + + [Test] + public void BringToFront_ActiveToolView_ViewBroughtToFrontFiredButActiveViewNotAffectedAndNoActiveViewEventsFired() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + var viewBroughtToFrontCounter = 0; + var activeDocumentViewChangingCounter = 0; + var activeDocumentViewChangedCounter = 0; + var activeViewChangedCounter = 0; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddToolView(testView1, ToolViewLocation.Left); + avalonDockViewHost.AddToolView(testView2, ToolViewLocation.Bottom); + SetActiveView(avalonDockViewHost, testView1); + + avalonDockViewHost.ViewBroughtToFront += (sender, args) => viewBroughtToFrontCounter++; + avalonDockViewHost.ActiveDocumentViewChanging += (sender, args) => activeDocumentViewChangingCounter++; + avalonDockViewHost.ActiveDocumentViewChanged += (sender, args) => activeDocumentViewChangedCounter++; + avalonDockViewHost.ActiveViewChanged += (sender, args) => activeViewChangedCounter++; + + // Call + avalonDockViewHost.BringToFront(testView1); + + // Assert + Assert.AreEqual(1, viewBroughtToFrontCounter); + Assert.AreEqual(0, activeDocumentViewChangingCounter); + Assert.AreEqual(0, activeDocumentViewChangedCounter); + Assert.AreEqual(0, activeViewChangedCounter); + Assert.IsTrue(IsActiveView(avalonDockViewHost, testView1)); + } + } + + [Test] + public void BringToFront_NonActiveToolView_ViewBroughtToFrontFiredButActiveViewNotAffectedAndNoActiveViewEventsFired() + { + // Setup + var testView1 = new TestView(); + var testView2 = new TestView(); + var viewBroughtToFrontCounter = 0; + var activeDocumentViewChangingCounter = 0; + var activeDocumentViewChangedCounter = 0; + var activeViewChangedCounter = 0; + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddToolView(testView1, ToolViewLocation.Left); + avalonDockViewHost.AddToolView(testView2, ToolViewLocation.Bottom); + SetActiveView(avalonDockViewHost, testView2); + + avalonDockViewHost.ViewBroughtToFront += (sender, args) => viewBroughtToFrontCounter++; + avalonDockViewHost.ActiveDocumentViewChanging += (sender, args) => activeDocumentViewChangingCounter++; + avalonDockViewHost.ActiveDocumentViewChanged += (sender, args) => activeDocumentViewChangedCounter++; + avalonDockViewHost.ActiveViewChanged += (sender, args) => activeViewChangedCounter++; + + // Call + avalonDockViewHost.BringToFront(testView1); + + // Assert + Assert.AreEqual(1, viewBroughtToFrontCounter); + Assert.AreEqual(0, activeDocumentViewChangingCounter); + Assert.AreEqual(0, activeDocumentViewChangedCounter); + Assert.AreEqual(0, activeViewChangedCounter); + Assert.IsTrue(IsActiveView(avalonDockViewHost, testView2)); + } + } + + [Test] + public void SetImage_ToolView_ImageSet() + { + // Setup + var testView = new TestView(); + + using (var avalonDockViewHost = new AvalonDockViewHost()) + { + avalonDockViewHost.AddToolView(testView, ToolViewLocation.Left); + + // Precondition + Assert.IsFalse(IsImageSet(avalonDockViewHost, testView)); + + // Call + avalonDockViewHost.SetImage(testView, new Bitmap(16, 16)); + + // Assert + Assert.IsTrue(IsImageSet(avalonDockViewHost, testView)); + } + } + + #endregion + + #region Helper methods + + private static bool IsDocumentViewPresent(AvalonDockViewHost avalonDockViewHost, IView documentView) + { + var layoutDocumentPaneGroup = TypeUtils.GetField(avalonDockViewHost, "LayoutDocumentPaneGroup"); + + return layoutDocumentPaneGroup.Descendents() + .OfType() + .First() + .Children + .Any(c => ((WindowsFormsHost) c.Content).Child == documentView); + } + + private static bool IsToolViewPresent(AvalonDockViewHost avalonDockViewHost, IView toolView, ToolViewLocation toolViewLocation) + { + string paneField; + + switch (toolViewLocation) + { + case ToolViewLocation.Left: + paneField = "LeftLayoutAnchorablePaneGroup"; + break; + case ToolViewLocation.Right: + paneField = "RightLayoutAnchorablePaneGroup"; + break; + case ToolViewLocation.Bottom: + paneField = "BottomLayoutAnchorablePaneGroup"; + break; + default: + paneField = ""; + break; + } + + var layoutAnchorablePaneGroup = TypeUtils.GetField(avalonDockViewHost, paneField); + + return layoutAnchorablePaneGroup.Descendents() + .OfType() + .First() + .Children + .Any(c => ((WindowsFormsHost) c.Content).Child == toolView); + } + + private static bool IsActiveView(AvalonDockViewHost avalonDockViewHost, IView view) + { + return ((WindowsFormsHost) avalonDockViewHost.DockingManager.ActiveContent).Child == view; + } + + private static bool IsAnyViewActive(AvalonDockViewHost avalonDockViewHost) + { + return avalonDockViewHost.DockingManager.ActiveContent != null; + } + + private static bool IsImageSet(AvalonDockViewHost avalonDockViewHost, IView view) + { + return avalonDockViewHost.DockingManager + .Layout + .Descendents() + .OfType() + .First(lc => ((WindowsFormsHost) lc.Content).Child == view).IconSource != null; + } + + private static void SetActiveView(AvalonDockViewHost avalonDockViewHost, IView view) + { + avalonDockViewHost.DockingManager.Layout.Descendents() + .OfType() + .First(d => ((WindowsFormsHost) d.Content).Child == view) + .IsActive = true; + } + + #endregion + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/ViewHost/DocumentViewControllerTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/ViewHost/DocumentViewControllerTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/ViewHost/DocumentViewControllerTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,1067 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Controls.Views; +using Core.Gui.Forms.ViewHost; +using Core.Gui.Plugin; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Forms.ViewHost +{ + [TestFixture] + public class DocumentViewControllerTest : NUnitFormTest + { + [Test] + public void ParameteredConstructor_ExpectedValues() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + + mocks.ReplayAll(); + + // Call + using (var documentViewController = new DocumentViewController(viewHost, + Enumerable.Empty(), + dialogParent)) + { + // Assert + Assert.IsInstanceOf(documentViewController); + CollectionAssert.IsEmpty(documentViewController.DefaultViewTypes); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void OpenViewForData_DataIsNull_ReturnFalse(bool forceShowDialog) + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + // Call + bool result = documentViewController.OpenViewForData(null, forceShowDialog); + + // Assert + Assert.IsFalse(result); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void OpenViewForData_NoViewInfoRegistered_ReturnFalse(bool forceShowDialog) + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[0]; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + // Call + bool result = documentViewController.OpenViewForData(new object(), forceShowDialog); + + // Assert + Assert.IsFalse(result); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_DataHasSingleMatch_ReturnTrueAndAddToViewHost() + { + // Setup + TestView view = null; + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { view = invocation.Arguments[0] as TestView; }); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + + mocks.ReplayAll(); + + var data = new object(); + const string viewData = ""; + const string viewName = ""; + var afterCreateCalled = false; + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo + { + GetViewData = o => + { + Assert.AreSame(data, o); + return viewData; + }, + AfterCreate = (v, o) => + { + Assert.IsInstanceOf(v); + Assert.AreSame(data, o); + afterCreateCalled = true; + }, + GetViewName = (v, o) => + { + Assert.IsInstanceOf(v); + Assert.AreSame(data, o); + return viewName; + } + }, + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + // Call + bool result = documentViewController.OpenViewForData(data); + + // Assert + Assert.IsTrue(result); + Assert.AreEqual(viewData, view.Data); + Assert.AreEqual(viewName, view.Text); + Assert.IsTrue(afterCreateCalled); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_DataHasSingleMatchOnBaseType_ReturnTrueAndAddToViewHost() + { + // Setup + TestView view = null; + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { view = invocation.Arguments[0] as TestView; }); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + + mocks.ReplayAll(); + + var data = new InheritedFromA(); + const string viewName = ""; + var afterCreateCalled = false; + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo + { + AfterCreate = (v, o) => + { + Assert.IsInstanceOf(v); + Assert.AreSame(data, o); + afterCreateCalled = true; + }, + GetViewName = (v, o) => + { + Assert.IsInstanceOf(v); + Assert.AreSame(data, o); + return viewName; + } + }, + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + // Call + bool result = documentViewController.OpenViewForData(data); + + // Assert + Assert.IsTrue(result); + Assert.AreEqual(data, view.Data); + Assert.AreEqual(viewName, view.Text); + Assert.IsTrue(afterCreateCalled); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_DataHasMultipleMatchesOnType_ResolveToMostSpecializedAndReturnTrueAndAddToViewHost() + { + // Setup + TestViewDerivative view = null; + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { view = invocation.Arguments[0] as TestViewDerivative; }); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + + mocks.ReplayAll(); + + var data = new InheritedFromA(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + // Call + bool result = documentViewController.OpenViewForData(data); + + // Assert + Assert.IsTrue(result); + Assert.AreEqual(data, view.Data); + Assert.IsEmpty(view.Text); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_ViewInfosForInheritedData_ResolveToMostSpecializedForDataAndReturnTrueAndAddToViewHost() + { + // Setup + TestView view = null; + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { view = invocation.Arguments[0] as TestView; }); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + + mocks.ReplayAll(); + + var data = new A(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), // Should not be matched as A does not inherit from InheritedFromA! + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + // Call + bool result = documentViewController.OpenViewForData(data); + + // Assert + Assert.IsTrue(result); + Assert.AreEqual(data, view.Data); + Assert.IsEmpty(view.Text); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_DataHasMultipleSingleMatches_UseAdditionalDataCheckAndReturnTrueAndAddToViewHost() + { + // Setup + TestViewDerivative view = null; + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { view = invocation.Arguments[0] as TestViewDerivative; }); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + + mocks.ReplayAll(); + + var data = new object(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo + { + AdditionalDataCheck = o => true + }, + new ViewInfo + { + AdditionalDataCheck = o => false + } + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + // Call + bool result = documentViewController.OpenViewForData(data); + + // Assert + Assert.IsTrue(result); + Assert.AreEqual(data, view.Data); + Assert.IsEmpty(view.Text); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_ClickCancelInOpenedDialog_ReturnFalseAndNoViewAddedToViewHost() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + + mocks.ReplayAll(); + + var data = new object(); + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + DialogBoxHandler = (name, wnd) => + { + var buttonCancel = new ControlTester("buttonCancel"); + + buttonCancel.Click(); + }; + + // Call + bool result = documentViewController.OpenViewForData(data); + + // Assert + Assert.IsFalse(result); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_ClickOkInOpenedDialog_ReturnTrueAndViewAddedToViewHost() + { + // Setup + TestView view = null; + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { view = invocation.Arguments[0] as TestView; }); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + + mocks.ReplayAll(); + + var data = new object(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + DialogBoxHandler = (name, wnd) => + { + var buttonOk = new ControlTester("buttonOk"); + + buttonOk.Click(); + }; + + // Call + bool result = documentViewController.OpenViewForData(data); + + // Assert + Assert.IsTrue(result); + Assert.AreEqual(data, view.Data); + Assert.IsEmpty(view.Text); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_MarkAsDefaultViewAndClickOkInOpenedDialog_ReturnTrueViewAddedToViewHostAndDefaultViewTypesUpdated() + { + // Setup + TestView view = null; + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { view = invocation.Arguments[0] as TestView; }); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + + mocks.ReplayAll(); + + var data = new object(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + DialogBoxHandler = (name, wnd) => + { + var buttonOk = new ControlTester("buttonOk"); + var checkbox = new CheckBoxTester("checkBoxDefault"); + + checkbox.Check(); + buttonOk.Click(); + }; + + // Precondition + Assert.IsFalse(documentViewController.DefaultViewTypes.ContainsKey(typeof(object))); + + // Call + bool result = documentViewController.OpenViewForData(data); + + // Assert + Assert.IsTrue(result); + Assert.AreEqual(data, view.Data); + Assert.IsEmpty(view.Text); + Assert.IsTrue(documentViewController.DefaultViewTypes.ContainsKey(typeof(object))); + Assert.AreEqual(documentViewController.DefaultViewTypes[typeof(object)], typeof(TestView)); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_SelectDifferentDefaultViewAndClickOkInOpenedDialog_ReturnTrueViewAddedToViewHostAndDefaultViewTypesUpdated() + { + // Setup + TestView view = null; + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { view = invocation.Arguments[0] as TestView; }); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + + mocks.ReplayAll(); + + var data = new object(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + documentViewController.DefaultViewTypes[typeof(object)] = typeof(TestViewDerivative); + + DialogBoxHandler = (name, wnd) => + { + var buttonOk = new ControlTester("buttonOk"); + var listBox = new ListBoxTester("listBox"); + var checkBox = new CheckBoxTester("checkBoxDefault"); + + listBox.SetSelected(0, true); + checkBox.Check(); + buttonOk.Click(); + }; + + // Call + bool result = documentViewController.OpenViewForData(data, true); + + // Assert + Assert.IsTrue(result); + Assert.AreEqual(data, view.Data); + Assert.IsEmpty(view.Text); + Assert.IsTrue(documentViewController.DefaultViewTypes.ContainsKey(typeof(object))); + Assert.AreEqual(documentViewController.DefaultViewTypes[typeof(object)], typeof(TestView)); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_DataHasMultipleMatchesAndRegisteredDefaultView_ReturnTrueAndAddDefaultViewToViewHost() + { + // Setup + TestViewDerivative view = null; + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { view = invocation.Arguments[0] as TestViewDerivative; }); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + + mocks.ReplayAll(); + + var data = new object(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + documentViewController.DefaultViewTypes[typeof(object)] = typeof(TestViewDerivative); + + // Call + bool result = documentViewController.OpenViewForData(data); + + // Assert + Assert.IsTrue(result); + Assert.AreEqual(data, view.Data); + Assert.IsEmpty(view.Text); + } + + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_OpenSameViewForTwoDifferentDataInstances_OpenTwoViews() + { + // Setup + var data1 = new object(); + var data2 = new object(); + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new IView[0]); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Matches(c => c.Data == data1))); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Matches(c => c.Data == data2))); + viewHost.Stub(vh => vh.SetImage(null, null)).IgnoreArguments(); + + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + // Call + documentViewController.OpenViewForData(data1); + documentViewController.OpenViewForData(data2); + } + + // Assert + mocks.VerifyAll(); + } + + [Test] + public void OpenViewForData_OpeningViewForAlreadyOpenedButInactiveView_ActivateDocumentView() + { + // Setup + var viewList = new List(); + var data = new object(); + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(viewList); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => viewList.Add(invocation.Arguments[0] as TestView)); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + viewHost.Expect(vh => vh.BringToFront(Arg.Matches(c => c == viewList.First()))); + + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + // Open view + documentViewController.OpenViewForData(data); + + // Call + documentViewController.OpenViewForData(data); + } + + // Assert + mocks.VerifyAll(); + } + + [Test] + public void GetViewInfosFor_NoViewInfosRegistered_ReturnEmpty() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + + mocks.ReplayAll(); + + using (var documentViewController = new DocumentViewController(viewHost, Enumerable.Empty(), dialogParent)) + { + var data = new object(); + + // Call + IEnumerable matchedViewInfos = documentViewController.GetViewInfosFor(data); + + // Assert + CollectionAssert.IsEmpty(matchedViewInfos); + } + + mocks.VerifyAll(); + } + + [Test] + public void GetViewInfosFor_SingleDirectMatch_ReturnSingleMatchingViewInfo() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + const int data = default(int); + + // Call + ViewInfo[] matchedViewInfos = documentViewController.GetViewInfosFor(data).ToArray(); + + // Assert + CollectionAssert.AreEqual(new[] + { + viewInfos[1] + }, matchedViewInfos); + } + + mocks.VerifyAll(); + } + + [Test] + public void GetViewInfosFor_ViewInfosWithInheritance_ReturnMatchesBasedOnInheritaceDataType() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + var data = new A(); + + // Call + ViewInfo[] matchedViewInfos = documentViewController.GetViewInfosFor(data).ToArray(); + + // Assert + ViewInfo[] expected = + { + viewInfos[0], + viewInfos[2] + }; + CollectionAssert.AreEqual(expected, matchedViewInfos); + } + + mocks.VerifyAll(); + } + + [Test] + public void GetViewInfosFor_ViewInfosWithAdditionalDataCheck_ReturnMatchesWithAdditionalDataCheckTrue() + { + // Setup + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo + { + AdditionalDataCheck = a => true + }, + new ViewInfo(), + new ViewInfo + { + AdditionalDataCheck = o => false + } + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + var data = new InheritedFromA(); + + // Call + ViewInfo[] matchedViewInfos = documentViewController.GetViewInfosFor(data).ToArray(); + + // Assert + ViewInfo[] expected = + { + viewInfos[0], + viewInfos[1] + }; + CollectionAssert.AreEqual(expected, matchedViewInfos); + } + + mocks.VerifyAll(); + } + + [Test] + public void CloseAllViewsFor_DataIsNull_DoNothing() + { + // Setup + var data1 = new A(); + var data2 = new InheritedFromA(); + var testView = new TestView + { + Data = data1 + }; + var testViewDerivative = new TestViewDerivative + { + Data = data2 + }; + + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(new[] + { + testView, + testViewDerivative + }); + + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + // Call + documentViewController.CloseAllViewsFor(null); + } + + // Assert + mocks.VerifyAll(); + } + + [Test] + public void CloseAllViewsFor_DataDoesNotCorrespondToOpenedViews_DoNothing() + { + // Setup + var data1 = new A(); + var data2 = new InheritedFromA(); + + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + var documentViews = new List(); + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(documentViews); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { documentViews.Add(invocation.Arguments[0] as TestView); }).Repeat.Twice(); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments().Repeat.Twice(); + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + documentViewController.OpenViewForData(data1); + documentViewController.OpenViewForData(data2); + + // Call + documentViewController.CloseAllViewsFor(new object()); + } + + // Assert + mocks.VerifyAll(); + } + + [Test] + public void CloseAllViewsFor_DataCorrespondsToOpenedView_RemoveThatView() + { + // Setup + var data1 = new A(); + var data2 = new InheritedFromA(); + + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + var documentViews = new List(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(documentViews); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { documentViews.Add(invocation.Arguments[0] as TestView); }).Repeat.Twice(); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments().Repeat.Twice(); + viewHost.Expect(vh => vh.Remove(Arg.Is.NotNull)).WhenCalled(invocation => { documentViews.Remove(invocation.Arguments[0] as TestView); }); + + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo(), + new ViewInfo() + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + documentViewController.OpenViewForData(data1); + documentViewController.OpenViewForData(data2); + + // Call + documentViewController.CloseAllViewsFor(data1); + } + + // Assert + mocks.VerifyAll(); + } + + [Test] + public void CloseAllViewsFor_DataDoesNotCorrespondToOpenedViewsButCloseForDataReturnsTrue_RemoveViews() + { + // Setup + var data1 = new A(); + var data2 = new InheritedFromA(); + var unusedViewData = new object(); + + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + var documentViews = new List(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(documentViews); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { documentViews.Add(invocation.Arguments[0] as TestView); }).Repeat.Twice(); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments().Repeat.Twice(); + viewHost.Expect(vh => vh.Remove(Arg.Is.NotNull)).WhenCalled(invocation => { documentViews.Remove(invocation.Arguments[0] as TestView); }).Repeat.Twice(); + mocks.ReplayAll(); + + var viewInfos = new ViewInfo[] + { + new ViewInfo + { + CloseForData = (view, o) => + { + Assert.IsInstanceOf(view); + Assert.AreSame(data1, view.Data); + Assert.AreSame(unusedViewData, o); + return true; + } + }, + new ViewInfo + { + CloseForData = (view, o) => + { + Assert.IsInstanceOf(view); + Assert.AreSame(data2, view.Data); + Assert.AreSame(unusedViewData, o); + return true; + } + } + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + documentViewController.OpenViewForData(data1); + documentViewController.OpenViewForData(data2); + + // Call + documentViewController.CloseAllViewsFor(unusedViewData); + } + + // Assert + mocks.VerifyAll(); + } + + [Test] + public void CloseAllViewsFor_DataCorrespondsToOpenedViewWithViewInfoThatBindsToSameViews_RemoveCorrectView() + { + // Setup + var data = new A(); + var viewData = new object(); + + var mocks = new MockRepository(); + var dialogParent = mocks.Stub(); + var viewHost = mocks.StrictMock(); + var documentViews = new List(); + + viewHost.Stub(vh => vh.ViewClosed += null).IgnoreArguments(); + viewHost.Stub(vh => vh.ViewClosed -= null).IgnoreArguments(); + viewHost.Stub(vh => vh.DocumentViews).Return(documentViews); + viewHost.Expect(vm => vm.AddDocumentView(Arg.Is.NotNull)).WhenCalled(invocation => { documentViews.Add(invocation.Arguments[0] as TestView); }); + viewHost.Expect(vh => vh.SetImage(null, null)).IgnoreArguments(); + viewHost.Expect(vh => vh.Remove(Arg.Is.NotNull)).WhenCalled(invocation => { documentViews.Remove(invocation.Arguments[0] as TestView); }); + + mocks.ReplayAll(); + + var viewClosed = false; + var viewInfos = new ViewInfo[] + { + new ViewInfo + { + CloseForData = (v, o) => + { + Assert.Fail("Incorrect CloseForData called."); + return true; + } + }, + new ViewInfo + { + CloseForData = (v, o) => + { + if (o == viewData) + { + viewClosed = true; + return true; + } + + return false; + } + } + }; + + using (var documentViewController = new DocumentViewController(viewHost, viewInfos, dialogParent)) + { + documentViewController.OpenViewForData(data); + + // Call + documentViewController.CloseAllViewsFor(viewData); + } + + // Assert + Assert.IsTrue(viewClosed); + mocks.VerifyAll(); + } + + private class A {} + + private class B {} + + private class InheritedFromA : A {} + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/ViewHost/TestView.Designer.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/ViewHost/TestView.Designer.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/ViewHost/TestView.Designer.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,77 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +namespace Core.Gui.Test.Forms.ViewHost +{ + partial class TestView + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.textBox1 = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(3, 3); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(74, 20); + this.textBox1.TabIndex = 0; + // + // TestView + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.textBox1); + this.Name = "TestView"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textBox1; + } +} Index: Core/Gui/test/Core.Gui.Test/Forms/ViewHost/TestView.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/ViewHost/TestView.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/ViewHost/TestView.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,38 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Windows.Forms; +using Core.Common.Controls.Views; + +namespace Core.Gui.Test.Forms.ViewHost +{ + public partial class TestView : UserControl, IView + { + public TestView() + { + InitializeComponent(); + } + + public object Data { get; set; } + } + + public class TestViewDerivative : TestView {} +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/ViewHost/TestView.resx =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/ViewHost/TestView.resx (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/ViewHost/TestView.resx (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Forms/ViewHost/ViewChangeEventArgsTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Forms/ViewHost/ViewChangeEventArgsTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Forms/ViewHost/ViewChangeEventArgsTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,55 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using Core.Common.Controls.Views; +using Core.Gui.Forms.ViewHost; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Forms.ViewHost +{ + [TestFixture] + public class ViewChangeEventArgsTest + { + [Test] + public void Constructor_WithoutView_ViewSet() + { + // Call + var args = new ViewChangeEventArgs(null); + + // Assert + Assert.IsNull(args.View); + } + + [Test] + public void Constructor_WithView_ViewSet() + { + // Setup + var view = new MockRepository().StrictMock(); + + // Call + var args = new ViewChangeEventArgs(view); + + // Assert + Assert.AreSame(view, args.View); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/GuiCoreTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/GuiCoreTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/GuiCoreTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,1649 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Windows.Forms; +using System.Windows.Forms.Integration; +using Core.Common.Base.Data; +using Core.Common.Base.Storage; +using Core.Common.Controls.TreeView; +using Core.Common.Controls.Views; +using Core.Common.TestUtil; +using Core.Common.Util.Settings; +using Core.Gui.Commands; +using Core.Gui.ContextMenu; +using Core.Gui.Forms.MainWindow; +using Core.Gui.Forms.MessageWindow; +using Core.Gui.Forms.ProjectExplorer; +using Core.Gui.Forms.PropertyGridView; +using Core.Gui.Forms.ViewHost; +using Core.Gui.Plugin; +using Core.Gui.Settings; +using log4net; +using log4net.Appender; +using log4net.Repository.Hierarchy; +using NUnit.Framework; +using Rhino.Mocks; +using Xceed.Wpf.AvalonDock.Layout; + +namespace Core.Gui.Test +{ + [TestFixture] + public class GuiCoreTest + { + private MessageWindowLogAppender originalMessageWindowLogAppender; + private IViewCommands originalViewPropertyEditor; + + [SetUp] + public void SetUp() + { + originalMessageWindowLogAppender = MessageWindowLogAppender.Instance; + MessageWindowLogAppender.Instance = new MessageWindowLogAppender(); + + originalViewPropertyEditor = ViewPropertyEditor.ViewCommands; + } + + [TearDown] + public void TearDown() + { + MessageWindowLogAppender.Instance = originalMessageWindowLogAppender; + ViewPropertyEditor.ViewCommands = originalViewPropertyEditor; + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Constructor_ValidArguments_ExpectedValues() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var projectFactory = mocks.Stub(); + var project = mocks.Stub(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(project); + mocks.ReplayAll(); + + var guiCoreSettings = new GuiCoreSettings(); + + // Call + using (var mainWindow = new MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, guiCoreSettings)) + { + // Assert + Assert.AreEqual(null, gui.PropertyResolver); + + Assert.IsNull(gui.ProjectFilePath); + Assert.AreSame(project, gui.Project); + + Assert.AreEqual(null, gui.Selection); + + Assert.IsInstanceOf(gui.StorageCommands); + Assert.IsInstanceOf(gui.ViewCommands); + Assert.AreEqual(null, gui.ApplicationCommands); + + Assert.AreEqual(null, gui.ViewHost); + Assert.AreEqual(null, gui.DocumentViewController); + + Assert.AreSame(guiCoreSettings, gui.FixedSettings); + + CollectionAssert.IsEmpty(gui.Plugins); + + Assert.AreEqual(mainWindow, gui.MainWindow); + + Assert.AreSame(ViewPropertyEditor.ViewCommands, gui.ViewCommands); + + Assert.AreSame(projectStore, gui.ProjectStore); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Constructor_MainWindowNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var guiCoreSettings = new GuiCoreSettings(); + + // Call + void Call() => new GuiCore(null, projectStore, projectMigrator, projectFactory, guiCoreSettings); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("mainWindow", exception.ParamName); + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Constructor_ProjectMigratorNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var guiCoreSettings = new GuiCoreSettings(); + + using (var mainWindow = new MainWindow()) + { + // Call + void Call() => new GuiCore(mainWindow, projectStore, null, projectFactory, guiCoreSettings); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("projectMigrator", exception.ParamName); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Constructor_ProjectStoreNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var guiCoreSettings = new GuiCoreSettings(); + + using (var mainWindow = new MainWindow()) + { + // Call + void Call() => new GuiCore(mainWindow, null, projectMigrator, projectFactory, guiCoreSettings); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("projectStore", exception.ParamName); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Constructor_ProjectFactoryNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + mocks.ReplayAll(); + + var guiCoreSettings = new GuiCoreSettings(); + + using (var mainWindow = new MainWindow()) + { + // Call + void Call() => new GuiCore(mainWindow, projectStore, projectMigrator, null, guiCoreSettings); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("projectFactory", exception.ParamName); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Constructor_FixedSettingsNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var mainWindow = new MainWindow()) + { + // Call + void Call() => new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, null); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("fixedSettings", exception.ParamName); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Constructor_ConstructedAfterAnotherInstanceHasBeenCreated_ThrowsInvalidOperationException() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var guiCoreSettings = new GuiCoreSettings(); + + using (var mainWindow = new MainWindow()) + using (new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, guiCoreSettings)) + { + // Call + void Call() + { + using (new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, guiCoreSettings)) {} + } + + // Assert + Assert.Throws(Call); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void SetProject_SetNull_ThrowsArgumentNullException() + { + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var plugin = mocks.Stub(); + plugin.Expect(p => p.Deactivate()); + plugin.Expect(p => p.Dispose()); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(plugin); + + // Call + void Call() => gui.SetProject(null, null); + + // Assert + Assert.Throws(Call); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Dispose_PluginsAdded_PluginsDisabledAndRemovedAndDisposed() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var plugin = mocks.Stub(); + plugin.Expect(p => p.Deactivate()); + plugin.Expect(p => p.Dispose()); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings()); + gui.Plugins.Add(plugin); + + // Call + gui.Dispose(); + + // Assert + Assert.IsNull(gui.Plugins); + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Dispose_PluginAddedButThrowsExceptionDuringDeactivation_LogErrorAndStillDisposeAndRemove() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + var plugin = mocks.Stub(); + plugin.Expect(p => p.Deactivate()).Throw(new Exception("Bad stuff happening!")); + plugin.Expect(p => p.Dispose()); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings()); + gui.Plugins.Add(plugin); + + // Call + void Call() => gui.Dispose(); + + // Assert + TestHelper.AssertLogMessageIsGenerated(Call, "Kritieke fout opgetreden tijdens deactivering van de grafische interface plugin.", 1); + Assert.IsNull(gui.Plugins); + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Dispose_HasSelection_ClearSelection() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings()) + { + Selection = new object() + }; + + // Call + gui.Dispose(); + + // Assert + Assert.IsNull(gui.Selection); + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Dispose_HasMainWindow_DisposeOfMainWindow() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var mainWindow = new MainWindow()) + { + var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, new GuiCoreSettings()); + + // Call + gui.Dispose(); + + // Assert + Assert.IsTrue(mainWindow.IsWindowDisposed); + Assert.IsNull(gui.MainWindow); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Dispose_HasInitializedMessageWindowForLogAppender_ClearMessageWindow() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var messageWindowLogAppender = new MessageWindowLogAppender(); + + Logger rootLogger = ((Hierarchy) LogManager.GetRepository()).Root; + rootLogger.AddAppender(messageWindowLogAppender); + + try + { + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + + // Precondition: + Assert.IsNotNull(MessageWindowLogAppender.Instance.MessageWindow); + Assert.IsNotNull(messageWindowLogAppender.MessageWindow); + + // Call + gui.Dispose(); + + // Assert + Assert.IsNull(MessageWindowLogAppender.Instance.MessageWindow); + Assert.IsNull(messageWindowLogAppender.MessageWindow); + CollectionAssert.DoesNotContain(rootLogger.Appenders, messageWindowLogAppender); + } + } + finally + { + rootLogger.RemoveAppender(messageWindowLogAppender); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Dispose_HasOpenedToolView_ToolViewsClearedAndViewsDisposed() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var toolView = new TestView()) + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + + gui.ViewHost.AddToolView(toolView, ToolViewLocation.Left); + + // Call + gui.Dispose(); + + // Assert + CollectionAssert.IsEmpty(gui.ViewHost.ToolViews); + Assert.IsTrue(toolView.IsDisposed); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Dispose_HasOpenedDocumentView_DocumentViewsClearedAndViewsDisposed() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var documentView = new TestView()) + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + + gui.ViewHost.AddDocumentView(documentView); + + // Call + gui.Dispose(); + + // Assert + CollectionAssert.IsEmpty(gui.ViewHost.DocumentViews); + Assert.IsNull(gui.DocumentViewController); + Assert.IsTrue(documentView.IsDisposed); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_NoMessageWindowLogAppender_AddNewLogAppender() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + Logger rootLogger = ((Hierarchy) LogManager.GetRepository()).Root; + IAppender[] originalAppenders = rootLogger.Appenders.ToArray(); + rootLogger.RemoveAllAppenders(); + + try + { + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + + // Call + gui.Run(); + + // Assert + Assert.AreEqual(1, rootLogger.Appenders.Count); + IAppender appender = rootLogger.Appenders[0]; + Assert.IsInstanceOf(appender); + Assert.AreSame(appender, MessageWindowLogAppender.Instance); + Assert.IsTrue(rootLogger.Repository.Configured); + + Assert.IsTrue(MessageWindowLogAppender.Instance.Enabled); + } + } + finally + { + rootLogger.RemoveAllAppenders(); + foreach (IAppender appender in originalAppenders) + { + rootLogger.AddAppender(appender); + } + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_AlreadyHasMessageWindowLogAppender_NoChangesToLogAppenders() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var appender = new MessageWindowLogAppender(); + + Logger rootLogger = ((Hierarchy) LogManager.GetRepository()).Root; + IAppender[] originalAppenders = rootLogger.Appenders.ToArray(); + rootLogger.RemoveAllAppenders(); + rootLogger.AddAppender(appender); + bool rootLoggerConfigured = rootLogger.Repository.Configured; + + try + { + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + + // Call + gui.Run(); + + // Assert + Assert.AreEqual(1, rootLogger.Appenders.Count); + Assert.AreSame(appender, rootLogger.Appenders[0]); + Assert.AreSame(appender, MessageWindowLogAppender.Instance); + Assert.AreEqual(rootLoggerConfigured, rootLogger.Repository.Configured); + + Assert.IsTrue(MessageWindowLogAppender.Instance.Enabled); + } + } + finally + { + rootLogger.RemoveAllAppenders(); + foreach (IAppender originalAppender in originalAppenders) + { + rootLogger.AddAppender(originalAppender); + } + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_WithFile_LoadProjectFromFile() + { + // Setup + const string fileName = "SomeFile"; + var testFile = $"{fileName}.rtd"; + + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + projectMigrator.Stub(m => m.ShouldMigrate(testFile)).Return(MigrationRequired.No); + var deserializedProject = mocks.Stub(); + projectStore.Expect(ps => ps.LoadProject(testFile)).Return(deserializedProject); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var fixedSettings = new GuiCoreSettings + { + MainWindowTitle = "
" + }; + + using (var mainWindow = new MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, fixedSettings)) + { + gui.Plugins.Add(new TestPlugin()); + + // Call + void Call() => gui.Run(testFile); + + // Assert + Tuple[] expectedMessages = + { + Tuple.Create("Openen van project is gestart.", LogLevelConstant.Info), + Tuple.Create("Openen van project is gelukt.", LogLevelConstant.Info) + }; + TestHelper.AssertLogMessagesWithLevelAreGenerated(Call, expectedMessages); + Assert.AreEqual(testFile, gui.ProjectFilePath); + Assert.AreSame(deserializedProject, gui.Project); + Assert.AreEqual(fileName, gui.Project.Name, + "Project name should be updated to the name of the file."); + + var expectedTitle = $"{fileName} - {fixedSettings.MainWindowTitle} {SettingsHelper.Instance.ApplicationVersion}"; + Assert.AreEqual(expectedTitle, mainWindow.Title); + Assert.AreSame(gui.Project, mainWindow.ProjectExplorer.Data); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_LoadingFromOutdatedFileAndMigrationCancelled_LoadDefaultProjectInstead() + { + // Setup + const string fileName = "SomeFile"; + var testFile = $"{fileName}.rtd"; + + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + + var projectMigrator = mocks.Stub(); + projectMigrator.Stub(pm => pm.ShouldMigrate(testFile)).Return(MigrationRequired.Yes); + projectMigrator.Stub(pm => pm.DetermineMigrationLocation(testFile)).Return(null); + + const string expectedProjectName = "Project"; + var project = mocks.Stub(); + project.Name = expectedProjectName; + var projectFactory = mocks.Stub(); + projectFactory.Stub(ph => ph.CreateNewProject()).Return(project); + + mocks.ReplayAll(); + + var fixedSettings = new GuiCoreSettings + { + MainWindowTitle = "
" + }; + + using (var mainWindow = new MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, fixedSettings)) + { + gui.Plugins.Add(new TestPlugin()); + + // Call + gui.Run(testFile); + + // Assert + Assert.IsNull(gui.ProjectFilePath); + var expectedTitle = $"{expectedProjectName} - {fixedSettings.MainWindowTitle} {SettingsHelper.Instance.ApplicationVersion}"; + Assert.AreEqual(expectedTitle, mainWindow.Title); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_LoadingFromOutdatedAndShouldMigrateThrowsArgumentException_LogErrorAndLoadDefaultProjectInstead() + { + // Setup + const string fileName = "SomeFile"; + var testFile = $"{fileName}.rtd"; + + const string expectedErrorMessage = "You shall not migrate!"; + + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + + var projectMigrator = mocks.Stub(); + projectMigrator.Stub(pm => pm.ShouldMigrate(testFile)) + .Throw(new ArgumentException(expectedErrorMessage)); + + const string expectedProjectName = "Project"; + var project = mocks.Stub(); + project.Name = expectedProjectName; + var projectFactory = mocks.Stub(); + projectFactory.Stub(ph => ph.CreateNewProject()).Return(project); + + mocks.ReplayAll(); + + var fixedSettings = new GuiCoreSettings + { + MainWindowTitle = "
" + }; + + using (var mainWindow = new MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, fixedSettings)) + { + gui.Plugins.Add(new TestPlugin()); + + // Call + void Call() => gui.Run(testFile); + + // Assert + TestHelper.AssertLogMessageWithLevelIsGenerated(Call, Tuple.Create(expectedErrorMessage, LogLevelConstant.Error)); + + Assert.IsNull(gui.ProjectFilePath); + string expectedTitle = $"{expectedProjectName} - {fixedSettings.MainWindowTitle} {SettingsHelper.Instance.ApplicationVersion}"; + Assert.AreEqual(expectedTitle, mainWindow.Title); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_LoadingFromOutdatedAndMigrateThrowsArgumentException_LogErrorAndLoadDefaultProjectInstead() + { + // Setup + const string fileName = "SomeFile"; + var testFile = $"{fileName}.rtd"; + var targetFile = $"{fileName}_17_1.rtd"; + + const string expectedErrorMessage = "You shall not migrate!"; + + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + + var projectMigrator = mocks.Stub(); + projectMigrator.Stub(pm => pm.ShouldMigrate(testFile)).Return(MigrationRequired.Yes); + projectMigrator.Stub(pm => pm.DetermineMigrationLocation(testFile)).Return(targetFile); + projectMigrator.Stub(pm => pm.Migrate(testFile, targetFile)) + .Throw(new ArgumentException(expectedErrorMessage)); + + const string expectedProjectName = "Project"; + var project = mocks.Stub(); + project.Name = expectedProjectName; + var projectFactory = mocks.Stub(); + projectFactory.Stub(ph => ph.CreateNewProject()).Return(project); + + mocks.ReplayAll(); + + var fixedSettings = new GuiCoreSettings + { + MainWindowTitle = "
" + }; + + using (var mainWindow = new MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, fixedSettings)) + { + gui.Plugins.Add(new TestPlugin()); + + // Call + void Call() => gui.Run(testFile); + + // Assert + Tuple[] expectedMessages = + { + Tuple.Create("Openen van project is gestart.", LogLevelConstant.Info), + Tuple.Create(expectedErrorMessage, LogLevelConstant.Error), + Tuple.Create("Openen van project is mislukt.", LogLevelConstant.Error) + }; + TestHelper.AssertLogMessagesWithLevelAreGenerated(Call, expectedMessages); + + Assert.IsNull(gui.ProjectFilePath); + var expectedTitle = $"{expectedProjectName} - {fixedSettings.MainWindowTitle} {SettingsHelper.Instance.ApplicationVersion}"; + Assert.AreEqual(expectedTitle, mainWindow.Title); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_LoadingFromFileThrowsStorageException_LogErrorAndLoadDefaultProjectInstead() + { + // Setup + const string fileName = "SomeFile"; + var testFile = $"{fileName}.rtd"; + + const string storageExceptionText = ""; + + var mocks = new MockRepository(); + var projectStore = mocks.Stub(); + var projectMigrator = mocks.Stub(); + projectMigrator.Stub(m => m.ShouldMigrate(testFile)).Return(MigrationRequired.No); + projectStore.Expect(ps => ps.LoadProject(testFile)).Throw(new StorageException(storageExceptionText)); + const string expectedProjectName = "Project"; + var project = mocks.Stub(); + project.Name = expectedProjectName; + var projectFactory = mocks.Stub(); + projectFactory.Stub(ph => ph.CreateNewProject()).Return(project); + + mocks.ReplayAll(); + + var fixedSettings = new GuiCoreSettings + { + MainWindowTitle = "
" + }; + + using (var mainWindow = new MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, fixedSettings)) + { + gui.Plugins.Add(new TestPlugin()); + + // Call + void Call() => gui.Run(testFile); + + // Assert + Tuple[] expectedMessages = + { + Tuple.Create("Openen van project is gestart.", LogLevelConstant.Info), + Tuple.Create(storageExceptionText, LogLevelConstant.Error), + Tuple.Create("Openen van project is mislukt.", LogLevelConstant.Error) + }; + TestHelper.AssertLogMessagesWithLevelAreGenerated(Call, expectedMessages); + + Assert.IsNull(gui.ProjectFilePath); + var expectedTitle = $"{expectedProjectName} - {fixedSettings.MainWindowTitle} {SettingsHelper.Instance.ApplicationVersion}"; + Assert.AreEqual(expectedTitle, mainWindow.Title); + } + + mocks.VerifyAll(); + } + + [Test] + [TestCase("")] + [TestCase(" ")] + [TestCase(null)] + [Apartment(ApartmentState.STA)] + public void Run_WithoutFile_DefaultProjectStillSet(string path) + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.StrictMock(); + var projectMigrator = mocks.Stub(); + + const string expectedProjectName = "Project"; + var project = mocks.Stub(); + project.Name = expectedProjectName; + var projectFactory = mocks.Stub(); + projectFactory.Stub(ph => ph.CreateNewProject()).Return(project); + mocks.ReplayAll(); + + var fixedSettings = new GuiCoreSettings + { + MainWindowTitle = "" + }; + + using (var mainWindow = new MainWindow()) + using (var gui = new GuiCore(mainWindow, projectStore, projectMigrator, projectFactory, fixedSettings)) + { + gui.Plugins.Add(new TestPlugin()); + + // Call + gui.Run(path); + + // Assert + Assert.IsNull(gui.ProjectFilePath); + Assert.AreSame(project, gui.Project); + var expectedTitle = $"{expectedProjectName} - {fixedSettings.MainWindowTitle} {SettingsHelper.Instance.ApplicationVersion}"; + Assert.AreEqual(expectedTitle, mainWindow.Title); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_WithPlugins_SetGuiAndActivatePlugins() + { + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + // Setup + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + var plugin = new TestPlugin(); + gui.Plugins.Add(plugin); + + // Call + gui.Run(); + + // Assert + Assert.AreSame(gui, plugin.Gui); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_WithPluginThatThrowsExceptionWhenActivated_DeactivateAndDisposePlugin() + { + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + var plugin = mocks.Stub<PluginBase>(); + plugin.Stub(p => p.GetViewInfos()).Return(Enumerable.Empty<ViewInfo>()); + plugin.Stub(p => p.GetPropertyInfos()).Return(Enumerable.Empty<PropertyInfo>()); + plugin.Stub(p => p.GetTreeNodeInfos()).Return(new TreeNodeInfo[] + { + new TreeNodeInfo<IProject>() + }); + plugin.Stub(p => p.Activate()).Throw(new Exception("ERROR!")); + plugin.Expect(p => p.Deactivate()); + plugin.Expect(p => p.Dispose()); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + // Setup + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(plugin); + + // Call + gui.Run(); + } + + // Assert + mocks.VerifyAll(); // Expect calls on plugin + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_WithPluginThatThrowsExceptionWhenActivatedAndDeactivated_LogErrorForDeactivatingThenDispose() + { + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + var plugin = mocks.Stub<PluginBase>(); + plugin.Stub(p => p.GetViewInfos()).Return(Enumerable.Empty<ViewInfo>()); + plugin.Stub(p => p.GetPropertyInfos()).Return(Enumerable.Empty<PropertyInfo>()); + plugin.Stub(p => p.GetTreeNodeInfos()).Return(new TreeNodeInfo[] + { + new TreeNodeInfo<IProject>() + }); + plugin.Stub(p => p.Activate()).Throw(new Exception("ERROR!")); + plugin.Stub(p => p.Deactivate()).Throw(new Exception("MORE ERROR!")); + plugin.Expect(p => p.Dispose()); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + // Setup + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(plugin); + + // Call + void Call() => gui.Run(); + + // Assert + const string expectedMessage = "Kritieke fout opgetreden tijdens deactivering van de grafische interface plugin."; + Tuple<string, LogLevelConstant> expectedMessageAndLogLevel = Tuple.Create(expectedMessage, LogLevelConstant.Error); + TestHelper.AssertLogMessageWithLevelIsGenerated(Call, expectedMessageAndLogLevel); + } + + mocks.VerifyAll(); // Expect Dispose call on plugin + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_InitializesViewController() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + + // Call + gui.Run(); + + // Assert + CollectionAssert.IsEmpty(gui.ViewHost.DocumentViews); + Assert.IsNull(gui.ViewHost.ActiveDocumentView); + + Assert.AreEqual(3, gui.ViewHost.ToolViews.Count()); + Assert.AreEqual(1, gui.ViewHost.ToolViews.Count(v => v is ProjectExplorer)); + Assert.AreEqual(1, gui.ViewHost.ToolViews.Count(v => v is PropertyGridView)); + Assert.AreEqual(1, gui.ViewHost.ToolViews.Count(v => v is MessageWindow)); + + Assert.IsNotNull(gui.DocumentViewController); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetAllDataWithViewDefinitionsRecursively_DataHasNoViewDefinitions_ReturnEmpty() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + var rootData = new object(); + + // Call + IEnumerable dataInstancesWithViewDefinitions = gui.GetAllDataWithViewDefinitionsRecursively(rootData); + + // Assert + CollectionAssert.IsEmpty(dataInstancesWithViewDefinitions); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetAllDataWithViewDefinitionsRecursively_MultiplePluginsHaveViewDefinitionsForRoot_ReturnRootObject() + { + // Setup + var rootData = new object(); + + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + + var plugin1 = mocks.StrictMock<PluginBase>(); + plugin1.Expect(p => p.GetChildDataWithViewDefinitions(rootData)) + .Return(new[] + { + rootData + }); + plugin1.Stub(p => p.Dispose()); + plugin1.Stub(p => p.Deactivate()); + var plugin2 = mocks.StrictMock<PluginBase>(); + plugin2.Expect(p => p.GetChildDataWithViewDefinitions(rootData)) + .Return(new[] + { + rootData + }); + plugin2.Stub(p => p.Dispose()); + plugin2.Stub(p => p.Deactivate()); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(plugin1); + gui.Plugins.Add(plugin2); + + // Call + object[] dataInstancesWithViewDefinitions = gui.GetAllDataWithViewDefinitionsRecursively(rootData).OfType<object>().ToArray(); + + // Assert + object[] expectedDataDefinitions = + { + rootData + }; + CollectionAssert.AreEquivalent(expectedDataDefinitions, dataInstancesWithViewDefinitions); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetAllDataWithViewDefinitionsRecursively_MultiplePluginsHaveViewDefinitionsForRootAndChild_ReturnRootAndChild() + { + // Setup + object rootData = 1; + object rootChild = 2; + + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + var plugin1 = mocks.StrictMock<PluginBase>(); + plugin1.Expect(p => p.GetChildDataWithViewDefinitions(rootData)) + .Return(new[] + { + rootData, + rootChild + }); + plugin1.Expect(p => p.GetChildDataWithViewDefinitions(rootChild)) + .Return(new[] + { + rootChild + }); + plugin1.Stub(p => p.Dispose()); + plugin1.Stub(p => p.Deactivate()); + var plugin2 = mocks.StrictMock<PluginBase>(); + plugin2.Expect(p => p.GetChildDataWithViewDefinitions(rootData)) + .Return(new[] + { + rootChild, + rootData + }); + plugin2.Expect(p => p.GetChildDataWithViewDefinitions(rootChild)) + .Return(new[] + { + rootChild + }); + plugin2.Stub(p => p.Dispose()); + plugin2.Stub(p => p.Deactivate()); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(plugin1); + gui.Plugins.Add(plugin2); + + // Call + object[] dataInstancesWithViewDefinitions = gui.GetAllDataWithViewDefinitionsRecursively(rootData).OfType<object>().ToArray(); + + // Assert + object[] expectedDataDefinitions = + { + rootData, + rootChild + }; + CollectionAssert.AreEquivalent(expectedDataDefinitions, dataInstancesWithViewDefinitions); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetTreeNodeInfos_NoPluginsConfigured_EmptyList() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + // Call + IEnumerable<TreeNodeInfo> result = gui.GetTreeNodeInfos(); + + // Assert + CollectionAssert.IsEmpty(result); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetTreeNodeInfos_MultiplePluginsConfigured_RetrievesTreeNodeInfosFromPlugins() + { + // Setup + var nodesPluginA = new[] + { + new TreeNodeInfo(), + new TreeNodeInfo() + }; + var nodesPluginB = new[] + { + new TreeNodeInfo() + }; + var nodesPluginC = new[] + { + new TreeNodeInfo(), + new TreeNodeInfo(), + new TreeNodeInfo() + }; + + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + + var pluginA = mocks.Stub<PluginBase>(); + pluginA.Stub(p => p.GetTreeNodeInfos()).Return(nodesPluginA); + pluginA.Stub(p => p.Dispose()); + pluginA.Stub(p => p.Deactivate()); + var pluginB = mocks.Stub<PluginBase>(); + pluginB.Stub(p => p.GetTreeNodeInfos()).Return(nodesPluginB); + pluginB.Stub(p => p.Dispose()); + pluginB.Stub(p => p.Deactivate()); + var pluginC = mocks.Stub<PluginBase>(); + pluginC.Stub(p => p.GetTreeNodeInfos()).Return(nodesPluginC); + pluginC.Stub(p => p.Dispose()); + pluginC.Stub(p => p.Deactivate()); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(pluginA); + gui.Plugins.Add(pluginB); + gui.Plugins.Add(pluginC); + + // Call + IEnumerable<TreeNodeInfo> result = gui.GetTreeNodeInfos(); + + // Assert + IEnumerable<TreeNodeInfo> expected = nodesPluginA.Concat(nodesPluginB).Concat(nodesPluginC); + CollectionAssert.AreEquivalent(expected, result); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Get_GuiHasNotRunYet_ThrowsInvalidOperationException() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var treeView = new TreeViewControl()) + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + // Call + void Call() => gui.Get(new object(), treeView); + + // Assert + string message = Assert.Throws<InvalidOperationException>(Call).Message; + Assert.AreEqual("Call IGui.Run in order to initialize dependencies before getting the ContextMenuBuilder.", message); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Get_GuiIsRunning_ReturnsContextMenuBuilder() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + using (var treeView = new TreeViewControl()) + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + + // Call + IContextMenuBuilder builder = gui.Get(new object(), treeView); + + // Assert + ContextMenuStrip contextMenu = builder.AddRenameItem() + .AddCollapseAllItem() + .AddDeleteItem() + .AddExpandAllItem() + .AddImportItem() + .AddExportItem() + .AddOpenItem() + .AddSeparator() + .AddPropertiesItem() + .Build(); + Assert.AreEqual(9, contextMenu.Items.Count); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void SetProject_SetNewValue_FireProjectOpenedEvents() + { + // Setup + var mocks = new MockRepository(); + var storeProject = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + var oldProject = mocks.Stub<IProject>(); + var newProject = mocks.Stub<IProject>(); + var projectFactory = mocks.Stub<IProjectFactory>(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(oldProject); + mocks.ReplayAll(); + + using (var gui = new GuiCore(new MainWindow(), storeProject, projectMigrator, projectFactory, new GuiCoreSettings())) + { + var openedCallCount = 0; + var beforeOpenCallCount = 0; + gui.BeforeProjectOpened += project => + { + Assert.AreSame(oldProject, project); + beforeOpenCallCount++; + }; + gui.ProjectOpened += project => + { + Assert.AreSame(newProject, project); + openedCallCount++; + }; + + // Call + gui.SetProject(newProject, null); + + // Assert + Assert.AreEqual(1, openedCallCount); + Assert.AreEqual(1, beforeOpenCallCount); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithoutSelection_WhenSelectionProviderSetAsActiveView_ThenSelectionSynced() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var selectionProvider = new TestSelectionProvider(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + gui.ViewHost.AddDocumentView(selectionProvider); + + // Precondition + Assert.IsNull(gui.Selection); + + // When + SetActiveView((AvalonDockViewHost) gui.ViewHost, selectionProvider); + + // Then + Assert.AreSame(selectionProvider.Selection, gui.Selection); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithRandomSelection_WhenSelectionProviderSetAsActiveView_ThenSelectionSynced() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var selectionProvider = new TestSelectionProvider(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + gui.ViewHost.AddDocumentView(selectionProvider); + + gui.Selection = new object(); + + // When + SetActiveView((AvalonDockViewHost) gui.ViewHost, selectionProvider); + + // Then + Assert.AreSame(selectionProvider.Selection, gui.Selection); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithRandomSelection_WhenSelectionChangedOnActiveSelectionProvider_ThenSelectionSynced() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var selectionProvider = new TestSelectionProvider(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + gui.ViewHost.AddDocumentView(selectionProvider); + SetActiveView((AvalonDockViewHost) gui.ViewHost, selectionProvider); + + gui.Selection = new object(); + + // When + selectionProvider.ChangeSelection(); + + // Then + Assert.AreSame(selectionProvider.Selection, gui.Selection); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithRandomSelection_WhenSelectionChangedOnRemovedSelectionProvider_ThenSelectionNoLongerSynced() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var selection = new object(); + var selectionProvider = new TestSelectionProvider(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + gui.ViewHost.AddDocumentView(selectionProvider); + SetActiveView((AvalonDockViewHost) gui.ViewHost, selectionProvider); + + gui.ViewHost.Remove(selectionProvider); + + gui.Selection = selection; + + // When + selectionProvider.ChangeSelection(); + + // Then + Assert.AreSame(selection, gui.Selection); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithRandomSelection_WhenNonSelectionProviderSetAsActiveView_ThenSelectionPreserved() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var testView = new TestView(); + var selection = new object(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + gui.ViewHost.AddDocumentView(testView); + + gui.Selection = selection; + + // When + SetActiveView((AvalonDockViewHost) gui.ViewHost, testView); + + // Then + Assert.AreSame(selection, gui.Selection); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithRandomSelection_WhenSelectionProviderRemoved_ThenSelectionPreserved() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var testView = new TestView(); + var selection = new object(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + gui.ViewHost.AddDocumentView(testView); + + gui.Selection = selection; + + // When + gui.ViewHost.Remove(testView); + + // Then + Assert.AreSame(selection, gui.Selection); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithSelectionFromSelectionProvider_WhenSelectionProviderRemoved_ThenSelectionCleared() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var selectionProvider = new TestSelectionProvider(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + gui.ViewHost.AddDocumentView(selectionProvider); + SetActiveView((AvalonDockViewHost) gui.ViewHost, selectionProvider); + + // Precondition + Assert.AreSame(selectionProvider.Selection, gui.Selection); + + // When + gui.ViewHost.Remove(selectionProvider); + + // Then + Assert.IsNull(gui.Selection); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GivenGuiWithRandomSelection_WhenGuiDisposed_ThenSelectionNoLongerSynced() + { + // Given + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + IProjectFactory projectFactory = CreateProjectFactory(mocks); + mocks.ReplayAll(); + + var selectionProvider = new TestSelectionProvider(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + gui.ViewHost.AddDocumentView(selectionProvider); + SetActiveView((AvalonDockViewHost) gui.ViewHost, selectionProvider); + + gui.Dispose(); + + // Precondition + Assert.IsNull(gui.Selection); + + // When + selectionProvider.ChangeSelection(); + + // Then + Assert.IsNull(gui.Selection); + } + + mocks.VerifyAll(); + } + + private static void SetActiveView(AvalonDockViewHost avalonDockViewHost, IView view) + { + avalonDockViewHost.DockingManager.Layout.Descendents() + .OfType<LayoutContent>() + .First(d => ((WindowsFormsHost) d.Content).Child == view) + .IsActive = true; + } + + private static IProjectFactory CreateProjectFactory(MockRepository mocks) + { + var projectFactory = mocks.Stub<IProjectFactory>(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(mocks.Stub<IProject>()); + + return projectFactory; + } + + private class TestSelectionProvider : Control, ISelectionProvider, IView + { + public event EventHandler<EventArgs> SelectionChanged; + + public TestSelectionProvider() + { + Selection = new object(); + } + + public object Selection { get; private set; } + + public object Data { get; set; } + + public void ChangeSelection() + { + Selection = new object(); + + SelectionChanged?.Invoke(this, new EventArgs()); + } + } + + private class TestView : Control, IView + { + public object Data { get; set; } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Helpers/DialogBasedInquiryHelperTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Helpers/DialogBasedInquiryHelperTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Helpers/DialogBasedInquiryHelperTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,342 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.IO; +using System.Threading; +using System.Windows.Forms; +using Core.Common.TestUtil; +using Core.Common.Util; +using Core.Gui.Helpers; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Helpers +{ + [TestFixture] + public class DialogBasedInquiryHelperTest : NUnitFormTest + { + private IWin32Window dialogParent; + private MockRepository mocks; + + [Test] + public void Constructor_WithoutDialogParent_ThrowsArgumentNullException() + { + // Setup + mocks.ReplayAll(); + + // Call + TestDelegate test = () => new DialogBasedInquiryHelper(null); + + // Assert + var exception = Assert.Throws<ArgumentNullException>(test); + Assert.AreEqual("dialogParent", exception.ParamName); + } + + [Test] + public void Constructor_WithParent_CreatesNewInquiryHelper() + { + // Setup + mocks.ReplayAll(); + + // Call + var helper = new DialogBasedInquiryHelper(dialogParent); + + // Assert + Assert.IsInstanceOf<IInquiryHelper>(helper); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetSourceFileLocation_Always_ShowsOpenFileDialog() + { + // Setup + dialogParent.Expect(d => d.Handle).Repeat.AtLeastOnce().Return(default(IntPtr)); + mocks.ReplayAll(); + + var helper = new DialogBasedInquiryHelper(dialogParent); + + string windowName = null; + DialogBoxHandler = (name, wnd) => + { + var tester = new OpenFileDialogTester(wnd); + windowName = name; + tester.ClickCancel(); + }; + + // Call + helper.GetSourceFileLocation(new FileFilterGenerator().Filter); + + // Assert + Assert.AreEqual("Openen", windowName); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetSourceFileLocation_CancelClicked_ResultFileSelectedIsFalse() + { + // Setup + dialogParent.Expect(d => d.Handle).Repeat.AtLeastOnce().Return(default(IntPtr)); + mocks.ReplayAll(); + + var helper = new DialogBasedInquiryHelper(dialogParent); + + DialogBoxHandler = (name, wnd) => + { + var tester = new OpenFileDialogTester(wnd); + tester.ClickCancel(); + }; + + // Call + string result = helper.GetSourceFileLocation(new FileFilterGenerator().Filter); + + // Assert + Assert.IsNull(result); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetSourceFileLocation_ExistingFileSelected_ResultFileSelectedIsTrueFileNameSet() + { + // Setup + dialogParent.Expect(d => d.Handle).Repeat.AtLeastOnce().Return(default(IntPtr)); + mocks.ReplayAll(); + + var helper = new DialogBasedInquiryHelper(dialogParent); + string expectedFilePath = Path.GetFullPath(Path.GetRandomFileName()); + + DialogBoxHandler = (name, wnd) => + { + var tester = new OpenFileDialogTester(wnd); + tester.OpenFile(expectedFilePath); + }; + + using (new FileDisposeHelper(expectedFilePath)) + { + // Call + string result = helper.GetSourceFileLocation(new FileFilterGenerator().Filter); + + // Assert + Assert.AreEqual(expectedFilePath, result); + } + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetTargetFileLocation_Always_ShowsOpenFileDialog() + { + // Setup + dialogParent.Expect(d => d.Handle).Repeat.AtLeastOnce().Return(default(IntPtr)); + mocks.ReplayAll(); + + var helper = new DialogBasedInquiryHelper(dialogParent); + + string windowName = null; + DialogBoxHandler = (name, wnd) => + { + var tester = new OpenFileDialogTester(wnd); + windowName = name; + tester.ClickCancel(); + }; + + // Call + helper.GetTargetFileLocation(new FileFilterGenerator().Filter, null); + + // Assert + Assert.AreEqual("Opslaan als", windowName); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetTargetFileLocation_CancelClicked_ResultFileSelectedIsFalse() + { + // Setup + dialogParent.Expect(d => d.Handle).Repeat.AtLeastOnce().Return(default(IntPtr)); + mocks.ReplayAll(); + + var helper = new DialogBasedInquiryHelper(dialogParent); + + DialogBoxHandler = (name, wnd) => + { + var tester = new SaveFileDialogTester(wnd); + tester.ClickCancel(); + }; + + // Call + string result = helper.GetTargetFileLocation(new FileFilterGenerator().Filter, null); + + // Assert + Assert.IsNull(result); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetTargetFileLocation_FileSelected_ResultFileSelectedIsTrueFileNameSet() + { + // Setup + dialogParent.Expect(d => d.Handle).Repeat.AtLeastOnce().Return(default(IntPtr)); + mocks.ReplayAll(); + + var helper = new DialogBasedInquiryHelper(dialogParent); + string expectedFilePath = Path.GetFullPath(Path.GetRandomFileName()); + + DialogBoxHandler = (name, wnd) => + { + var tester = new SaveFileDialogTester(wnd); + tester.SaveFile(expectedFilePath); + }; + + // Call + string result = helper.GetTargetFileLocation(new FileFilterGenerator().Filter, null); + + // Assert + Assert.AreEqual(expectedFilePath, result); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void GetTargetFolderLocation_Always_ShowsFolderBrowserDialog() + { + // Setup + dialogParent.Expect(d => d.Handle).Repeat.AtLeastOnce().Return(default(IntPtr)); + mocks.ReplayAll(); + + var helper = new DialogBasedInquiryHelper(dialogParent); + + string windowName = null; + DialogBoxHandler = (name, wnd) => + { + var tester = new FileDialogTester(wnd); + windowName = name; + tester.ClickCancel(); + }; + + // Call + helper.GetTargetFolderLocation(); + + // Assert + Assert.AreEqual("Browse For Folder", windowName); + } + + [Test] + [Apartment(ApartmentState.STA)] + [TestCase(true)] + [TestCase(false)] + public void InquireContinuation_OkOrCancelClicked_ReturnExpectedResult(bool confirm) + { + // Setup + dialogParent.Expect(d => d.Handle).Repeat.AtLeastOnce().Return(default(IntPtr)); + mocks.ReplayAll(); + + var helper = new DialogBasedInquiryHelper(dialogParent); + + const string expectedQuery = "Are you sure you want to do this?"; + const string expectedTitle = "Bevestigen"; + string query = null; + string title = null; + + DialogBoxHandler = (name, wnd) => + { + var tester = new MessageBoxTester(wnd); + query = tester.Text; + title = tester.Title; + if (confirm) + { + tester.ClickOk(); + } + else + { + tester.ClickCancel(); + } + }; + + // Call + bool result = helper.InquireContinuation(expectedQuery); + + // Assert + Assert.AreEqual(expectedQuery, query); + Assert.AreEqual(expectedTitle, title); + Assert.AreEqual(confirm, result); + } + + [Test] + [TestCase(DialogResult.Cancel, OptionalStepResult.Cancel)] + [TestCase(DialogResult.Yes, OptionalStepResult.PerformOptionalStep)] + [TestCase(DialogResult.No, OptionalStepResult.SkipOptionalStep)] + public void InquirePerformOptionalStep_VariousScenarios_ReturnExpectedValue(DialogResult clickedResult, + OptionalStepResult expectedResult) + { + // Setup + dialogParent.Expect(d => d.Handle).Repeat.AtLeastOnce().Return(default(IntPtr)); + mocks.ReplayAll(); + + var helper = new DialogBasedInquiryHelper(dialogParent); + + string actualQuery = null; + string title = null; + + DialogBoxHandler = (name, wnd) => + { + var tester = new MessageBoxTester(wnd); + actualQuery = tester.Text; + title = tester.Title; + + switch (clickedResult) + { + case DialogResult.Yes: + tester.SendCommand(MessageBoxTester.Command.Yes); + break; + case DialogResult.No: + tester.SendCommand(MessageBoxTester.Command.No); + break; + case DialogResult.Cancel: + tester.SendCommand(MessageBoxTester.Command.Cancel); + break; + } + }; + + const string description = "A"; + const string query = "B"; + + // Call + OptionalStepResult result = helper.InquirePerformOptionalStep(description, query); + + // Assert + Assert.AreEqual(expectedResult, result); + + Assert.AreEqual(description, title); + Assert.AreEqual(query, actualQuery); + mocks.VerifyAll(); + } + + public override void Setup() + { + mocks = new MockRepository(); + dialogParent = mocks.StrictMock<IWin32Window>(); + } + + public override void TearDown() + { + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Helpers/ExportHelperTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Helpers/ExportHelperTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Helpers/ExportHelperTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,114 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Common.Util; +using Core.Gui.Helpers; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Helpers +{ + [TestFixture] + public class ExportHelperTest + { + [Test] + public void GetFilePath_InquiryHelperNull_ThrowsArgumentNullException() + { + // Call + void Call() => ExportHelper.GetFilePath(null, new FileFilterGenerator()); + + // Assert + var exception = Assert.Throws<ArgumentNullException>(Call); + Assert.AreEqual("inquiryHelper", exception.ParamName); + } + + [Test] + public void GetFilePath_FileFilterGeneratorNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var inquiryHelper = mocks.Stub<IInquiryHelper>(); + mocks.ReplayAll(); + + // Call + void Call() => ExportHelper.GetFilePath(inquiryHelper, null); + + // Assert + var exception = Assert.Throws<ArgumentNullException>(Call); + Assert.AreEqual("fileFilterGenerator", exception.ParamName); + mocks.VerifyAll(); + } + + [Test] + [TestCase(null)] + [TestCase("C:/test")] + public void GetFilePath_Always_ReturnsSelectedFilePath(string expectedFilePath) + { + // Setup + var fileFilterGenerator = new FileFilterGenerator("testExtension", "testDescription"); + + var mocks = new MockRepository(); + var inquiryHelper = mocks.StrictMock<IInquiryHelper>(); + inquiryHelper.Expect(ih => ih.GetTargetFileLocation(fileFilterGenerator.Filter, null)) + .Return(expectedFilePath); + mocks.ReplayAll(); + + // Call + string filePath = ExportHelper.GetFilePath(inquiryHelper, fileFilterGenerator); + + // Assert + Assert.AreEqual(expectedFilePath, filePath); + mocks.VerifyAll(); + } + + [Test] + public void GetFolderPath_InquiryHelperNull_ThrowsArgumentNullException() + { + // Call + void Call() => ExportHelper.GetFolderPath(null); + + // Assert + var exception = Assert.Throws<ArgumentNullException>(Call); + Assert.AreEqual("inquiryHelper", exception.ParamName); + } + + [Test] + [TestCase(null)] + [TestCase("C:/test")] + public void GetFolderPath_Always_ReturnsSelectedFolderPath(string expectedFilePath) + { + // Setup + var mocks = new MockRepository(); + var inquiryHelper = mocks.StrictMock<IInquiryHelper>(); + inquiryHelper.Expect(ih => ih.GetTargetFolderLocation()) + .Return(expectedFilePath); + mocks.ReplayAll(); + + // Call + string filePath = ExportHelper.GetFolderPath(inquiryHelper); + + // Assert + Assert.AreEqual(expectedFilePath, filePath); + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/OpenProjectActivityTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/OpenProjectActivityTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/OpenProjectActivityTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,1235 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.IO; +using Core.Common.Base.Data; +using Core.Common.Base.Service; +using Core.Common.Base.Storage; +using Core.Common.TestUtil; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test +{ + [TestFixture] + public class OpenProjectActivityTest + { + [Test] + public void Constructor_ExpectedValues() + { + // Setup + var mocks = new MockRepository(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectStorage = mocks.Stub<IStoreProject>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + // Call + var activity = new OpenProjectActivity(openProjectProperties); + + // Assert + Assert.IsInstanceOf<Activity>(activity); + Assert.AreEqual("Openen van project", activity.Description); + Assert.IsNull(activity.ProgressText); + Assert.AreEqual(ActivityState.None, activity.State); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_OpenProjectConstructionPropertiesNull_ThrowArgumentNullException() + { + // Call + TestDelegate call = () => new OpenProjectActivity(null); + + // Assert + string paramName = Assert.Throws<ArgumentNullException>(call).ParamName; + Assert.AreEqual("requiredOpenProjectProperties", paramName); + } + + [Test] + public void Constructor_FilePathNull_ThrowArgumentException() + { + // Setup + var mocks = new MockRepository(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectStorage = mocks.Stub<IStoreProject>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = null, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + // Call + TestDelegate call = () => new OpenProjectActivity(openProjectProperties); + + // Assert + const string expectedMessage = "Filepath should be set."; + string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage<ArgumentException>(call, expectedMessage).ParamName; + Assert.AreEqual("requiredOpenProjectProperties", paramName); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_ProjectOwnerNull_ThrowArgumentException() + { + // Setup + var mocks = new MockRepository(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectStorage = mocks.Stub<IStoreProject>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectOwner = null, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + // Call + TestDelegate call = () => new OpenProjectActivity(openProjectProperties); + + // Assert + const string expectedMessage = "Project owner should be set."; + string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage<ArgumentException>(call, expectedMessage).ParamName; + Assert.AreEqual("requiredOpenProjectProperties", paramName); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_ProjectFactoryNull_ThrowArgumentException() + { + // Setup + var mocks = new MockRepository(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var projectStorage = mocks.Stub<IStoreProject>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectOwner = projectOwner, + ProjectFactory = null, + ProjectStorage = projectStorage + }; + + // Call + TestDelegate call = () => new OpenProjectActivity(openProjectProperties); + + // Assert + const string expectedMessage = "Project factory should be set."; + string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage<ArgumentException>(call, expectedMessage).ParamName; + Assert.AreEqual("requiredOpenProjectProperties", paramName); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_StoreProjectNull_ThrowArgumentException() + { + // Setup + var mocks = new MockRepository(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var projectFactory = mocks.Stub<IProjectFactory>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = null + }; + + // Call + TestDelegate call = () => new OpenProjectActivity(openProjectProperties); + + // Assert + const string expectedMessage = "Project storage should be set."; + string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage<ArgumentException>(call, expectedMessage).ParamName; + Assert.AreEqual("requiredOpenProjectProperties", paramName); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_MigrationFilePathNull_ThrowArgumentException() + { + // Setup + var mocks = new MockRepository(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectStorage = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var migrateProjectProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + MigrationFilePath = null, + Migrator = projectMigrator + }; + + // Call + TestDelegate call = () => new OpenProjectActivity(openProjectProperties, migrateProjectProperties); + + // Assert + const string expectedMessage = "Migration target file path should be set."; + string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage<ArgumentException>(call, expectedMessage).ParamName; + Assert.AreEqual("optionalProjectMigrationProperties", paramName); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_MigrateProjectNull_ThrowArgumentException() + { + // Setup + var mocks = new MockRepository(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectStorage = mocks.Stub<IStoreProject>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var migrateProjectProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + MigrationFilePath = "", + Migrator = null + }; + + // Call + TestDelegate call = () => new OpenProjectActivity(openProjectProperties, migrateProjectProperties); + + // Assert + const string expectedMessage = "Project migrator should be set."; + string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage<ArgumentException>(call, expectedMessage).ParamName; + Assert.AreEqual("optionalProjectMigrationProperties", paramName); + + mocks.VerifyAll(); + } + + [Test] + public void Run_StoreProjectLoadProjectDoesNotThrow_ActivityExecutedWithoutAdditionalLogMessages() + { + // Setup + const string someFilePath = "<path to some file>"; + + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + + var projectStorage = mocks.Stub<IStoreProject>(); + projectStorage.Expect(ps => ps.LoadProject(someFilePath)) + .Return(project); + + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var activity = new OpenProjectActivity(openProjectProperties); + + // Call + Action call = () => activity.Run(); + + // Assert + TestHelper.AssertLogMessageIsGenerated(call, "Openen van project is gestart.", 1); + + Assert.AreEqual(ActivityState.Executed, activity.State); + + mocks.VerifyAll(); + } + + [Test] + public void Run_StoreProjectLoadProjectReturnsNull_ActivityFailedWithoutAdditionalLogMessages() + { + // Setup + const string someFilePath = "<path to some file>"; + + var mocks = new MockRepository(); + var projectStorage = mocks.Stub<IStoreProject>(); + projectStorage.Expect(ps => ps.LoadProject(someFilePath)) + .Return(null); + + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var activity = new OpenProjectActivity(openProjectProperties); + + // Call + Action call = () => activity.Run(); + + // Assert + TestHelper.AssertLogMessageIsGenerated(call, "Openen van project is gestart.", 1); + + Assert.AreEqual(ActivityState.Failed, activity.State); + + mocks.VerifyAll(); + } + + [Test] + public void Run_StoreProjectLoadProjectThrowsStorageException_ActivityFailedWithAdditionalLogMessages() + { + // Setup + const string someFilePath = "<path to some file>"; + + const string message = "<some exception message>"; + var innerException = new Exception("A"); + + var mocks = new MockRepository(); + var projectStorage = mocks.Stub<IStoreProject>(); + projectStorage.Expect(ps => ps.LoadProject(someFilePath)) + .Throw(new StorageException(message, innerException)); + + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var activity = new OpenProjectActivity(openProjectProperties); + + // Call + Action call = () => activity.Run(); + + // Assert + TestHelper.AssertLogMessagesAreGenerated(call, new[] + { + "Openen van project is gestart.", + message + }, 2); + + Assert.AreEqual(ActivityState.Failed, activity.State); + + mocks.VerifyAll(); + } + + [Test] + public void Run_StoreProjectLoadProjectThrowsArgumentException_ActivityFailedWithoutAdditionalLogMessages() + { + // Setup + const string someFilePath = "<path to some file>"; + + var mocks = new MockRepository(); + var projectStorage = mocks.Stub<IStoreProject>(); + projectStorage.Expect(ps => ps.LoadProject(someFilePath)) + .Throw(new ArgumentException()); + + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var activity = new OpenProjectActivity(openProjectProperties); + + // Call + Action call = () => activity.Run(); + + // Assert + TestHelper.AssertLogMessageIsGenerated(call, "Openen van project is gestart.", 1); + + Assert.AreEqual(ActivityState.Failed, activity.State); + + mocks.VerifyAll(); + } + + [Test] + public void Run_SuccessfulMigrateAndLoadProject_ActivityExecutedWithoutAdditionalLogMessages() + { + // Setup + const string someFilePath = "<path to some file>"; + const string someMigrationFilePath = "<path to some migrated file>"; + + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + + var projectStorage = mocks.Stub<IStoreProject>(); + projectStorage.Expect(ps => ps.LoadProject(someMigrationFilePath)) + .Return(project); + + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + + var projectMigrator = mocks.Stub<IMigrateProject>(); + projectMigrator.Expect(m => m.Migrate(someFilePath, someMigrationFilePath)) + .Return(true); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var migrateProjectProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + MigrationFilePath = someMigrationFilePath, + Migrator = projectMigrator + }; + + var activity = new OpenProjectActivity(openProjectProperties, migrateProjectProperties); + + // Call + Action call = () => activity.Run(); + + // Assert + TestHelper.AssertLogMessageIsGenerated(call, "Openen van project is gestart.", 1); + + Assert.AreEqual(ActivityState.Executed, activity.State); + + mocks.VerifyAll(); + } + + [Test] + public void Run_FailedToMigrate_ActivityFailedWithoutAdditionalLogMessages() + { + // Setup + const string someFilePath = "<path to some file>"; + const string someMigrationFilePath = "<path to some migrated file>"; + + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + + var projectStorage = mocks.Stub<IStoreProject>(); + projectStorage.Expect(ps => ps.LoadProject(someMigrationFilePath)) + .Return(project) + .Repeat.Never(); + + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + + var projectMigrator = mocks.Stub<IMigrateProject>(); + projectMigrator.Expect(m => m.Migrate(someFilePath, someMigrationFilePath)) + .Return(false); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var migrateProjectProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + MigrationFilePath = someMigrationFilePath, + Migrator = projectMigrator + }; + + var activity = new OpenProjectActivity(openProjectProperties, migrateProjectProperties); + + // Call + Action call = () => activity.Run(); + + // Assert + TestHelper.AssertLogMessageIsGenerated(call, "Openen van project is gestart.", 1); + + Assert.AreEqual(ActivityState.Failed, activity.State); + + mocks.VerifyAll(); + } + + [Test] + public void Run_MigrateThrowsArgumentException_ActivityFailedWithAdditionalLogMessages() + { + // Setup + const string someFilePath = "<path to some file>"; + const string someMigrationFilePath = "<path to some migrated file>"; + const string exceptionMessage = "<some exception message>"; + + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + + var projectStorage = mocks.StrictMock<IStoreProject>(); + projectStorage.Expect(ps => ps.LoadProject(someMigrationFilePath)) + .Return(project) + .Repeat.Never(); + + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + + var projectMigrator = mocks.StrictMock<IMigrateProject>(); + projectMigrator.Expect(m => m.Migrate(someFilePath, someMigrationFilePath)) + .Throw(new ArgumentException(exceptionMessage)); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var migrateProjectProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + MigrationFilePath = someMigrationFilePath, + Migrator = projectMigrator + }; + + var activity = new OpenProjectActivity(openProjectProperties, migrateProjectProperties); + + // Call + Action call = () => activity.Run(); + + // Assert + TestHelper.AssertLogMessagesAreGenerated(call, new[] + { + "Openen van project is gestart.", + exceptionMessage + }, 2); + + Assert.AreEqual(ActivityState.Failed, activity.State); + + mocks.VerifyAll(); + } + + [Test] + public void Run_WithMigration_ExpectedProgressNotifications() + { + // Setup + var mocks = new MockRepository(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.Stub<IStoreProject>(); + var migrateProject = mocks.Stub<IMigrateProject>(); + migrateProject.Stub(pm => pm.Migrate(null, null)) + .IgnoreArguments() + .Return(true); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectFactory = projectFactory, + ProjectOwner = projectOwner, + ProjectStorage = storeProject + }; + var migrateProjectProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + MigrationFilePath = "", + Migrator = migrateProject + }; + var activity = new OpenProjectActivity(openProjectProperties, + migrateProjectProperties); + + var progressMessages = new List<string>(); + activity.ProgressChanged += (sender, args) => + { + Assert.AreSame(activity, sender); + Assert.AreEqual(EventArgs.Empty, args); + + progressMessages.Add(activity.ProgressText); + }; + + // Call + activity.Run(); + + // Assert + var expectedProgressMessages = new[] + { + "Stap 1 van 3 | Migreren van project", + "Stap 2 van 3 | Inlezen van project" + }; + CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); + mocks.VerifyAll(); + } + + [Test] + public void Run_WithoutMigration_ExpectedProgressNotifications() + { + // Setup + var mocks = new MockRepository(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.Stub<IStoreProject>(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectFactory = projectFactory, + ProjectOwner = projectOwner, + ProjectStorage = storeProject + }; + var activity = new OpenProjectActivity(openProjectProperties); + + var progressMessages = new List<string>(); + activity.ProgressChanged += (sender, args) => + { + Assert.AreSame(activity, sender); + Assert.AreEqual(EventArgs.Empty, args); + + progressMessages.Add(activity.ProgressText); + }; + + // Call + activity.Run(); + + // Assert + var expectedProgressMessages = new[] + { + "Stap 1 van 2 | Inlezen van project" + }; + CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); + mocks.VerifyAll(); + } + + [Test] + public void GivenSuccessfullyExecutedOpenProjectActivity_WhenFinishingOpenProjectActivity_ThenProjectOwnerAndNewProjectUpdatedWithLogMessage() + { + // Given + const string someFilePath = @"c:\\folder\someFilePath.rtd"; + + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + project.Expect(p => p.NotifyObservers()); + + var projectStorage = mocks.Stub<IStoreProject>(); + projectStorage.Stub(ps => ps.LoadProject(someFilePath)) + .Return(project); + + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + projectOwner.Expect(po => po.SetProject(project, someFilePath)); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var activity = new OpenProjectActivity(openProjectProperties); + + activity.Run(); + + // Precondition + Assert.AreEqual(ActivityState.Executed, activity.State); + + // When + Action call = () => + { + activity.LogState(); + activity.Finish(); + }; + + // Then + const string expectedMessage = "Openen van project is gelukt."; + TestHelper.AssertLogMessageIsGenerated(call, expectedMessage, 1); + + Assert.AreEqual(ActivityState.Finished, activity.State); + + Assert.AreEqual(Path.GetFileNameWithoutExtension(someFilePath), project.Name); + + mocks.VerifyAll(); + } + + [Test] + public void GivenOpenProjectActivityAndFailedDueToNoProject_WhenFinishingOpenProjectActivity_ThenProjectOwnerHasNewEmptyProjectWithLogMessage() + { + // Given + const string someFilePath = @"c:\\folder\someFilePath.rtd"; + + var mocks = new MockRepository(); + var projectStorage = mocks.Stub<IStoreProject>(); + projectStorage.Stub(ps => ps.LoadProject(someFilePath)) + .Return(null); + + var project = mocks.Stub<IProject>(); + + var projectFactory = mocks.Stub<IProjectFactory>(); + projectFactory.Expect(f => f.CreateNewProject()) + .Return(project); + var projectOwner = mocks.Stub<IProjectOwner>(); + projectOwner.Expect(po => po.SetProject(project, null)); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var activity = new OpenProjectActivity(openProjectProperties); + + activity.Run(); + + // Precondition + Assert.AreEqual(ActivityState.Failed, activity.State); + + // When + Action call = () => + { + activity.LogState(); + activity.Finish(); + }; + + // Then + Tuple<string, LogLevelConstant> expectedMessage = Tuple.Create("Openen van project is mislukt.", + LogLevelConstant.Error); + TestHelper.AssertLogMessageWithLevelIsGenerated(call, expectedMessage, 1); + + Assert.AreEqual(ActivityState.Failed, activity.State); + + mocks.VerifyAll(); + } + + [Test] + [TestCaseSource(nameof(ExceptionCases))] + public void GivenOpenProjectActivityFailedDueToException_WhenFinishingOpenProjectActivity_ThenProjectOwnerHasNewEmptyProjectWithLogMessage(Exception exceptionToThrow) + { + // Given + const string someFilePath = @"c:\\folder\someFilePath.rtd"; + + var mocks = new MockRepository(); + var projectStorage = mocks.Stub<IStoreProject>(); + projectStorage.Stub(ps => ps.LoadProject(someFilePath)) + .Throw(exceptionToThrow); + + var project = mocks.Stub<IProject>(); + + var projectFactory = mocks.Stub<IProjectFactory>(); + projectFactory.Expect(f => f.CreateNewProject()) + .Return(project); + var projectOwner = mocks.Stub<IProjectOwner>(); + projectOwner.Expect(po => po.SetProject(project, null)); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var activity = new OpenProjectActivity(openProjectProperties); + + activity.Run(); + + // Precondition + Assert.AreEqual(ActivityState.Failed, activity.State); + + // When + Action call = () => + { + activity.LogState(); + activity.Finish(); + }; + + // Then + Tuple<string, LogLevelConstant> expectedMessage = Tuple.Create("Openen van project is mislukt.", + LogLevelConstant.Error); + TestHelper.AssertLogMessageWithLevelIsGenerated(call, expectedMessage, 1); + + Assert.AreEqual(ActivityState.Failed, activity.State); + + mocks.VerifyAll(); + } + + [Test] + public void LogState_ActivityCancelled_ProjectOwnerNotUpdatedWithLogMessage() + { + // Setup + const string someFilePath = @"c:\\folder\someFilePath.rtd"; + + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + project.Expect(p => p.NotifyObservers()) + .Repeat.Never(); + + var projectStorage = mocks.Stub<IStoreProject>(); + projectStorage.Stub(ps => ps.LoadProject(someFilePath)) + .Return(project); + + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + projectOwner.Expect(po => po.SetProject(project, someFilePath)) + .Repeat.Never(); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = someFilePath, + ProjectOwner = projectOwner, + ProjectFactory = projectFactory, + ProjectStorage = projectStorage + }; + + var activity = new OpenProjectActivity(openProjectProperties); + + activity.Run(); + activity.Cancel(); + + // Precondition + Assert.AreEqual(ActivityState.Canceled, activity.State); + + // Call + Action call = () => activity.LogState(); + + // Assert + Tuple<string, LogLevelConstant> expectedMessage = Tuple.Create("Openen van project is geannuleerd.", + LogLevelConstant.Warn); + TestHelper.AssertLogMessageWithLevelIsGenerated(call, expectedMessage, 1); + + Assert.AreEqual(ActivityState.Canceled, activity.State); + + mocks.VerifyAll(); + } + + [Test] + public void Finish_ProjectMigratedAndOpened_ExpectedProgressText() + { + // Setup + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.Stub<IStoreProject>(); + storeProject.Stub(sp => sp.LoadProject(null)) + .IgnoreArguments() + .Return(project); + var migrateProject = mocks.Stub<IMigrateProject>(); + migrateProject.Stub(pm => pm.Migrate(null, null)) + .IgnoreArguments() + .Return(true); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectFactory = projectFactory, + ProjectOwner = projectOwner, + ProjectStorage = storeProject + }; + var migrateProjectProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + MigrationFilePath = "", + Migrator = migrateProject + }; + + var activity = new OpenProjectActivity(openProjectProperties, + migrateProjectProperties); + activity.Run(); + + // Precondition + Assert.AreEqual(ActivityState.Executed, activity.State); + + var progressMessages = new List<string>(); + activity.ProgressChanged += (sender, args) => + { + Assert.AreSame(activity, sender); + Assert.AreEqual(EventArgs.Empty, args); + + progressMessages.Add(activity.ProgressText); + }; + + // Call + activity.Finish(); + + // Assert + var expectedProgressMessages = new[] + { + "Stap 3 van 3 | Initialiseren van geopend project" + }; + CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); + + mocks.VerifyAll(); + } + + [Test] + public void Finish_OnlyProjectOpened_ExpectedProgressText() + { + // Setup + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.Stub<IStoreProject>(); + storeProject.Stub(sp => sp.LoadProject(null)) + .IgnoreArguments() + .Return(project); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectFactory = projectFactory, + ProjectOwner = projectOwner, + ProjectStorage = storeProject + }; + + var activity = new OpenProjectActivity(openProjectProperties); + activity.Run(); + + // Precondition + Assert.AreEqual(ActivityState.Executed, activity.State); + + var progressMessages = new List<string>(); + activity.ProgressChanged += (sender, args) => + { + Assert.AreSame(activity, sender); + Assert.AreEqual(EventArgs.Empty, args); + + progressMessages.Add(activity.ProgressText); + }; + + // Call + activity.Finish(); + + // Assert + var expectedProgressMessages = new[] + { + "Stap 2 van 2 | Initialiseren van geopend project" + }; + CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); + + mocks.VerifyAll(); + } + + [Test] + public void Finish_ProjectMigrationFailed_ExpectedProgressText() + { + // Setup + var mocks = new MockRepository(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.Stub<IStoreProject>(); + var migrateProject = mocks.Stub<IMigrateProject>(); + migrateProject.Stub(pm => pm.Migrate(null, null)) + .IgnoreArguments() + .Throw(new ArgumentException()); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectFactory = projectFactory, + ProjectOwner = projectOwner, + ProjectStorage = storeProject + }; + var migrateProjectProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + MigrationFilePath = "", + Migrator = migrateProject + }; + + var activity = new OpenProjectActivity(openProjectProperties, + migrateProjectProperties); + activity.Run(); + + // Precondition + Assert.AreEqual(ActivityState.Failed, activity.State); + + var progressMessages = new List<string>(); + activity.ProgressChanged += (sender, args) => + { + Assert.AreSame(activity, sender); + Assert.AreEqual(EventArgs.Empty, args); + + progressMessages.Add(activity.ProgressText); + }; + + // Call + activity.Finish(); + + // Assert + var expectedProgressMessages = new[] + { + "Stap 3 van 3 | Initialiseren van leeg project" + }; + CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); + + mocks.VerifyAll(); + } + + [Test] + public void Finish_OnlyProjectOpenFailed_ExpectedProgressText() + { + // Setup + var mocks = new MockRepository(); + var projectFactory = mocks.Stub<IProjectFactory>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.Stub<IStoreProject>(); + storeProject.Stub(s => s.LoadProject(null)) + .IgnoreArguments() + .Throw(new StorageException()); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectFactory = projectFactory, + ProjectOwner = projectOwner, + ProjectStorage = storeProject + }; + + var activity = new OpenProjectActivity(openProjectProperties); + activity.Run(); + + // Precondition + Assert.AreEqual(ActivityState.Failed, activity.State); + + var progressMessages = new List<string>(); + activity.ProgressChanged += (sender, args) => + { + Assert.AreSame(activity, sender); + Assert.AreEqual(EventArgs.Empty, args); + + progressMessages.Add(activity.ProgressText); + }; + + // Call + activity.Finish(); + + // Assert + var expectedProgressMessages = new[] + { + "Stap 2 van 2 | Initialiseren van leeg project" + }; + CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); + + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GivenActivityMigratingAndOpeningProject_WhenCancellingDuringMigration_DoNotLoadProject(bool migrationSuccessful) + { + // Setup + var mocks = new MockRepository(); + var projectFactory = mocks.StrictMock<IProjectFactory>(); + var storeProject = mocks.StrictMock<IStoreProject>(); + var projectOwner = mocks.StrictMock<IProjectOwner>(); + var migrateProject = mocks.Stub<IMigrateProject>(); + migrateProject.Stub(mp => mp.Migrate(null, null)) + .IgnoreArguments() + .Return(migrationSuccessful); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectFactory = projectFactory, + ProjectStorage = storeProject, + ProjectOwner = projectOwner + }; + var migrateProjectProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + MigrationFilePath = "", + Migrator = migrateProject + }; + var activity = new OpenProjectActivity(openProjectProperties, + migrateProjectProperties); + + // When + activity.ProgressChanged += (sender, args) => activity.Cancel(); + activity.Run(); + activity.Finish(); + + // Assert + Assert.AreEqual(ActivityState.Canceled, activity.State); + mocks.VerifyAll(); + } + + [Test] + public void GivenActivityMigratinProject_WhenCancellingAndMigrationThrowsException_DoNotLoadProject() + { + // Setup + var mocks = new MockRepository(); + var projectFactory = mocks.StrictMock<IProjectFactory>(); + var storeProject = mocks.StrictMock<IStoreProject>(); + var projectOwner = mocks.StrictMock<IProjectOwner>(); + var migrateProject = mocks.Stub<IMigrateProject>(); + migrateProject.Stub(mp => mp.Migrate(null, null)) + .IgnoreArguments() + .Throw(new ArgumentException()); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectFactory = projectFactory, + ProjectStorage = storeProject, + ProjectOwner = projectOwner + }; + var migrateProjectProperties = new OpenProjectActivity.ProjectMigrationConstructionProperties + { + MigrationFilePath = "", + Migrator = migrateProject + }; + var activity = new OpenProjectActivity(openProjectProperties, + migrateProjectProperties); + + // When + activity.ProgressChanged += (sender, args) => activity.Cancel(); + activity.Run(); + activity.Finish(); + + // Assert + Assert.AreEqual(ActivityState.Canceled, activity.State); + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GivenActivityOpeningProject_WhenCancellingDuringLoadProject_DoNotSetProject(bool loadProjectSuccessful) + { + // Setup + var mocks = new MockRepository(); + IProject project = loadProjectSuccessful ? mocks.Stub<IProject>() : null; + var projectFactory = mocks.StrictMock<IProjectFactory>(); + var projectOwner = mocks.StrictMock<IProjectOwner>(); + var storeProject = mocks.Stub<IStoreProject>(); + storeProject.Stub(s => s.LoadProject(null)) + .IgnoreArguments() + .Return(project); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectFactory = projectFactory, + ProjectStorage = storeProject, + ProjectOwner = projectOwner + }; + var activity = new OpenProjectActivity(openProjectProperties); + + // When + activity.ProgressChanged += (sender, args) => activity.Cancel(); + activity.Run(); + activity.Finish(); + + // Assert + Assert.AreEqual(ActivityState.Canceled, activity.State); + mocks.VerifyAll(); + } + + [Test] + public void GivenActivityOpeningProject_WhenCancellingWhileLoadProjectThrowsStorageException_DoNotSetProject() + { + // Setup + var mocks = new MockRepository(); + var projectFactory = mocks.StrictMock<IProjectFactory>(); + var projectOwner = mocks.StrictMock<IProjectOwner>(); + var storeProject = mocks.Stub<IStoreProject>(); + storeProject.Stub(s => s.LoadProject(null)) + .IgnoreArguments() + .Throw(new StorageException()); + mocks.ReplayAll(); + + var openProjectProperties = new OpenProjectActivity.OpenProjectConstructionProperties + { + FilePath = "", + ProjectFactory = projectFactory, + ProjectStorage = storeProject, + ProjectOwner = projectOwner + }; + var activity = new OpenProjectActivity(openProjectProperties); + + // When + activity.ProgressChanged += (sender, args) => activity.Cancel(); + activity.Run(); + activity.Finish(); + + // Assert + Assert.AreEqual(ActivityState.Canceled, activity.State); + mocks.VerifyAll(); + } + + private static IEnumerable<TestCaseData> ExceptionCases() + { + yield return new TestCaseData(new StorageException()); + yield return new TestCaseData(new ArgumentException()); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Plugin/ExportInfoTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Plugin/ExportInfoTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Plugin/ExportInfoTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,142 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Drawing; +using Core.Common.Base.IO; +using Core.Common.TestUtil; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Plugin +{ + [TestFixture] + public class ExportInfoTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var info = new ExportInfo(); + + // Assert + Assert.IsNull(info.DataType); + Assert.IsNull(info.CreateFileExporter); + Assert.IsNull(info.IsEnabled); + Assert.IsNull(info.Name); + Assert.IsNull(info.Extension); + Assert.AreEqual("Algemeen", info.Category); + TestHelper.AssertImagesAreEqual(Resources.ExportIcon, info.Image); + Assert.IsNull(info.GetExportPath); + } + + [Test] + public void DefaultGenericConstructor_ExpectedValues() + { + // Call + var info = new ExportInfo<int>(); + + // Assert + Assert.AreEqual(typeof(int), info.DataType); + Assert.IsNull(info.CreateFileExporter); + Assert.IsNull(info.IsEnabled); + Assert.IsNull(info.Name); + Assert.IsNull(info.Extension); + Assert.AreEqual("Algemeen", info.Category); + TestHelper.AssertImagesAreEqual(Resources.ExportIcon, info.Image); + Assert.IsNull(info.GetExportPath); + } + + [Test] + public void ImplicitOperator_OptionalDelegatesAndPropertiesSet_ExportInfoFullyConverted() + { + // Setup + var mocks = new MockRepository(); + var fileExporter = mocks.StrictMock<IFileExporter>(); + mocks.ReplayAll(); + + const string name = "name"; + const string extension = ".txt"; + const string category = "category"; + var image = new Bitmap(16, 16); + const string exportPath = "C:/path"; + + var info = new ExportInfo<int> + { + CreateFileExporter = (data, filePath) => fileExporter, + IsEnabled = data => false, + Name = name, + Extension = extension, + Category = category, + Image = image, + GetExportPath = () => exportPath + }; + + // Precondition + Assert.IsInstanceOf<ExportInfo<int>>(info); + + // Call + ExportInfo convertedInfo = info; + + // Assert + Assert.IsInstanceOf<ExportInfo>(convertedInfo); + Assert.AreEqual(typeof(int), convertedInfo.DataType); + Assert.IsNotNull(convertedInfo.CreateFileExporter); + Assert.AreSame(fileExporter, convertedInfo.CreateFileExporter(12, string.Empty)); + Assert.IsNotNull(convertedInfo.IsEnabled); + Assert.IsFalse(convertedInfo.IsEnabled(12)); + Assert.AreEqual(name, info.Name); + Assert.AreEqual(extension, info.Extension); + Assert.AreEqual(category, info.Category); + Assert.AreSame(image, info.Image); + Assert.AreEqual(exportPath, info.GetExportPath()); + + mocks.VerifyAll(); + } + + [Test] + public void ImplicitOperator_NoneOfTheOptionalDelegatesAndPropertiesSet_ExportInfoFullyConverted() + { + // Setup + var info = new ExportInfo<int>(); + + // Precondition + Assert.IsInstanceOf<ExportInfo<int>>(info); + + // Call + ExportInfo convertedInfo = info; + + // Assert + Assert.IsInstanceOf<ExportInfo>(convertedInfo); + Assert.AreEqual(typeof(int), convertedInfo.DataType); + Assert.IsNotNull(convertedInfo.CreateFileExporter); + Assert.IsNull(convertedInfo.CreateFileExporter(new object(), string.Empty)); + Assert.IsNotNull(convertedInfo.IsEnabled); + Assert.IsTrue(convertedInfo.IsEnabled(new object())); + Assert.IsNull(info.Name); + Assert.IsNull(info.Extension); + Assert.AreEqual("Algemeen", info.Category); + TestHelper.AssertImagesAreEqual(Resources.ExportIcon, info.Image); + Assert.IsNull(info.GetExportPath); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Plugin/ImportInfoTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Plugin/ImportInfoTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Plugin/ImportInfoTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,143 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Drawing; +using Core.Common.Base.IO; +using Core.Common.TestUtil; +using Core.Common.Util; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Plugin +{ + [TestFixture] + public class ImportInfoTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var info = new ImportInfo(); + + // Assert + Assert.IsNull(info.DataType); + Assert.IsNull(info.CreateFileImporter); + Assert.IsNull(info.IsEnabled); + Assert.IsNull(info.Name); + Assert.AreEqual("Importeren gegevens", info.Category); + TestHelper.AssertImagesAreEqual(Resources.brick, info.Image); + Assert.IsNull(info.FileFilterGenerator); + Assert.IsNull(info.VerifyUpdates); + } + + [Test] + public void DefaultGenericConstructor_ExpectedValues() + { + // Call + var info = new ImportInfo<int>(); + + // Assert + Assert.AreEqual(typeof(int), info.DataType); + Assert.IsNull(info.CreateFileImporter); + Assert.IsNull(info.IsEnabled); + Assert.IsNull(info.Name); + Assert.AreEqual("Importeren gegevens", info.Category); + TestHelper.AssertImagesAreEqual(Resources.brick, info.Image); + Assert.IsNull(info.FileFilterGenerator); + Assert.IsNull(info.VerifyUpdates); + } + + [Test] + public void ImplicitOperator_OptionalDelegatesAndPropertiesSet_ImportInfoFullyConverted() + { + // Setup + var mocks = new MockRepository(); + var fileImporter = mocks.StrictMock<IFileImporter>(); + mocks.ReplayAll(); + + const string name = "name"; + const string category = "category"; + var image = new Bitmap(16, 16); + var generator = new FileFilterGenerator(); + + var info = new ImportInfo<int> + { + CreateFileImporter = (data, filePath) => fileImporter, + IsEnabled = data => false, + Name = name, + Category = category, + Image = image, + FileFilterGenerator = generator, + VerifyUpdates = i => true + }; + + // Precondition + Assert.IsInstanceOf<ImportInfo<int>>(info); + + // Call + ImportInfo convertedInfo = info; + + // Assert + Assert.IsInstanceOf<ImportInfo>(convertedInfo); + Assert.AreEqual(typeof(int), convertedInfo.DataType); + Assert.IsNotNull(convertedInfo.CreateFileImporter); + Assert.AreSame(fileImporter, convertedInfo.CreateFileImporter(12, "")); + Assert.IsNotNull(convertedInfo.IsEnabled); + Assert.IsFalse(convertedInfo.IsEnabled(12)); + Assert.AreEqual(name, info.Name); + Assert.AreEqual(category, info.Category); + Assert.AreSame(image, info.Image); + Assert.AreEqual(generator, info.FileFilterGenerator); + Assert.IsNotNull(info.VerifyUpdates); + Assert.IsTrue(convertedInfo.VerifyUpdates(12)); + + mocks.VerifyAll(); + } + + [Test] + public void ImplicitOperator_NoneOfTheOptionalDelegatesAndPropertiesSet_ImportInfoFullyConverted() + { + // Setup + var info = new ImportInfo<int>(); + + // Precondition + Assert.IsInstanceOf<ImportInfo<int>>(info); + + // Call + ImportInfo convertedInfo = info; + + // Assert + Assert.IsInstanceOf<ImportInfo>(convertedInfo); + Assert.AreEqual(typeof(int), convertedInfo.DataType); + Assert.IsNotNull(convertedInfo.CreateFileImporter); + Assert.IsNull(convertedInfo.CreateFileImporter(12, "")); + Assert.IsNotNull(convertedInfo.IsEnabled); + Assert.IsTrue(convertedInfo.IsEnabled(12)); + Assert.IsNull(info.Name); + Assert.AreEqual("Importeren gegevens", info.Category); + TestHelper.AssertImagesAreEqual(Resources.brick, info.Image); + Assert.IsNull(info.FileFilterGenerator); + Assert.IsNull(info.VerifyUpdates); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Plugin/PluginBaseTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Plugin/PluginBaseTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Plugin/PluginBaseTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,269 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using Core.Common.Controls.TreeView; +using Core.Gui.Forms.MainWindow; +using Core.Gui.Helpers; +using Core.Gui.Plugin; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Plugin +{ + [TestFixture] + public class PluginBaseTest + { + [Test] + public void Constructor_ExpectedValues() + { + // Call + using (var plugin = new SimplePlugin()) + { + // Assert + Assert.IsNull(plugin.Gui); + } + } + + [Test] + public void Gui_SetValue_GetNewlySetValue() + { + // Setup + var mocks = new MockRepository(); + var gui = mocks.Stub<IGui>(); + mocks.ReplayAll(); + + using (var plugin = new SimplePlugin()) + { + // Call + plugin.Gui = gui; + + // Assert + Assert.AreEqual(gui, plugin.Gui); + } + + mocks.VerifyAll(); + } + + [Test] + public void Activate_DoesNotThrow() + { + // Setup + using (var plugin = new SimplePlugin()) + { + // Call + TestDelegate call = () => plugin.Activate(); + + // Assert + Assert.DoesNotThrow(call); + } + } + + [Test] + public void Deactivate_DoesNotThrow() + { + // Setup + using (var plugin = new SimplePlugin()) + { + // Call + TestDelegate call = () => plugin.Deactivate(); + + // Assert + Assert.DoesNotThrow(call); + } + } + + [Test] + public void GetPropertyInfos_ReturnsEmpty() + { + // Setup + using (var plugin = new SimplePlugin()) + { + // Call + IEnumerable<PropertyInfo> infos = plugin.GetPropertyInfos(); + + // Assert + CollectionAssert.IsEmpty(infos); + } + } + + [Test] + public void GetViewInfos_ReturnsEmpty() + { + // Setup + using (var plugin = new SimplePlugin()) + { + // Call + IEnumerable<ViewInfo> infos = plugin.GetViewInfos(); + + // Assert + CollectionAssert.IsEmpty(infos); + } + } + + [Test] + public void GetTreeNodeInfos_ReturnsEmpty() + { + // Setup + using (var plugin = new SimplePlugin()) + { + // Call + IEnumerable<TreeNodeInfo> infos = plugin.GetTreeNodeInfos(); + + // Assert + CollectionAssert.IsEmpty(infos); + } + } + + [Test] + public void GetChildDataWithViewDefinitions_ReturnsEmpty() + { + // Setup + using (var plugin = new SimplePlugin()) + { + // Call + IEnumerable<object> chidrenWithViewDefinitions = plugin.GetChildDataWithViewDefinitions(null); + + // Assert + CollectionAssert.IsEmpty(chidrenWithViewDefinitions); + } + } + + [Test] + public void GetImportInfos_ReturnsEmpty() + { + // Setup + using (var plugin = new SimplePlugin()) + { + // Call + IEnumerable<ImportInfo> infos = plugin.GetImportInfos(); + + // Assert + CollectionAssert.IsEmpty(infos); + } + } + + [Test] + public void GetExportInfos_ReturnsEmpty() + { + // Setup + using (var plugin = new SimplePlugin()) + { + // Call + IEnumerable<ExportInfo> infos = plugin.GetExportInfos(); + + // Assert + CollectionAssert.IsEmpty(infos); + } + } + + [Test] + public void Dispose_SetGuiToNull() + { + // Setup + var mocks = new MockRepository(); + var gui = mocks.Stub<IGui>(); + mocks.ReplayAll(); + + var plugin = new SimplePlugin + { + Gui = gui + }; + + // Call + plugin.Dispose(); + + // Assert + Assert.IsNull(plugin.Gui); + mocks.VerifyAll(); + } + + [Test] + public void GetInquiryHelper_GuiIsNull_ThrowsInvalidOperationException() + { + // Setup + var plugin = new SimplePlugin(); + + // Call + void Call() => plugin.GetInquiryHelperFromBase(); + + // Assert + var exception = Assert.Throws<InvalidOperationException>(Call); + Assert.AreEqual("Gui cannot be null", exception.Message); + } + + [Test] + public void GetInquiryHelper_WithGui_ReturnsDialogBasedInquiryHelper() + { + // Setup + var mocks = new MockRepository(); + var mainWindow = mocks.Stub<IMainWindow>(); + var gui = mocks.Stub<IGui>(); + gui.Stub(g => g.MainWindow).Return(mainWindow); + mocks.ReplayAll(); + + var plugin = new SimplePlugin + { + Gui = gui + }; + + // Call + IInquiryHelper inquiryHelper = plugin.GetInquiryHelperFromBase(); + + // Assert + Assert.IsInstanceOf<DialogBasedInquiryHelper>(inquiryHelper); + mocks.VerifyAll(); + } + + [Test] + public void GivenPluginWithGui_WhenGetInquiryHelperCalled_ThenAlwaysSameInquiryHelperReturned() + { + // Given + var mocks = new MockRepository(); + var mainWindow = mocks.Stub<IMainWindow>(); + var gui = mocks.Stub<IGui>(); + gui.Stub(g => g.MainWindow).Return(mainWindow); + mocks.ReplayAll(); + + var plugin = new SimplePlugin + { + Gui = gui + }; + + // When + IInquiryHelper inquiryHelper1 = plugin.GetInquiryHelperFromBase(); + IInquiryHelper inquiryHelper2 = plugin.GetInquiryHelperFromBase(); + + // Then + Assert.AreSame(inquiryHelper1, inquiryHelper2); + mocks.VerifyAll(); + } + + private class SimplePlugin : PluginBase + { + public IInquiryHelper GetInquiryHelperFromBase() + { + return GetInquiryHelper(); + } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Plugin/PropertyInfoTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Plugin/PropertyInfoTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Plugin/PropertyInfoTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,127 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using Core.Gui.Plugin; +using Core.Gui.PropertyBag; +using NUnit.Framework; + +namespace Core.Gui.Test.Plugin +{ + [TestFixture] + public class PropertyInfoTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var info = new PropertyInfo(); + + // Assert + Assert.IsNull(info.DataType); + Assert.IsNull(info.PropertyObjectType); + } + + [Test] + public void SimpleProperties_SetValues_GetNewlySetValues() + { + // Setup + var info = new PropertyInfo(); + + Type newDataType = typeof(object); + Type newPropertyObjectType = typeof(TestObjectProperties); + + // Call + info.DataType = newDataType; + info.PropertyObjectType = newPropertyObjectType; + + // Assert + Assert.AreEqual(newDataType, info.DataType); + Assert.AreEqual(newPropertyObjectType, info.PropertyObjectType); + } + + [Test] + public void DefaultGenericConstructor_ExpectedValues() + { + // Call + var info = new PropertyInfo<int, TestObjectProperties>(); + + // Assert + Assert.AreEqual(typeof(int), info.DataType); + Assert.AreEqual(typeof(TestObjectProperties), info.PropertyObjectType); + } + + [Test] + public void CreateInstance_DataTypeWithDefaultConstructor_ReturnPropertiesWithDataSet() + { + // Setup + var info = new PropertyInfo + { + DataType = typeof(int), + PropertyObjectType = typeof(TestObjectProperties) + }; + int data = new Random(21).Next(); + + // Call + object properties = info.CreateInstance(data); + + // Assert + Assert.IsInstanceOf<TestObjectProperties>(properties); + var testObjectProperties = (TestObjectProperties) properties; + Assert.AreEqual(data, testObjectProperties.Data); + } + + [Test] + public void CreateInstanceGeneric_DataTypeHasDefaultConstructor_ReturnPropertiesWithDataSet() + { + // Setup + var info = new PropertyInfo<int, TestObjectProperties>(); + int data = new Random(21).Next(); + + // Call + TestObjectProperties properties = info.CreateInstance(data); + + // Assert + Assert.IsNotNull(properties); + Assert.AreEqual(data, properties.Data); + } + + [Test] + public void ImplicitOperator_Always_PropertyInfoFullyConverted() + { + // Setup + var info = new PropertyInfo<int, TestObjectProperties>(); + + // Precondition + Assert.IsInstanceOf<PropertyInfo<int, TestObjectProperties>>(info); + + // Call + PropertyInfo convertedInfo = info; + + // Assert + Assert.IsInstanceOf<PropertyInfo>(convertedInfo); + Assert.AreEqual(typeof(int), convertedInfo.DataType); + Assert.AreEqual(typeof(TestObjectProperties), convertedInfo.PropertyObjectType); + } + + private class TestObjectProperties : ObjectProperties<object> {} + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Plugin/UpdateInfoTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Plugin/UpdateInfoTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Plugin/UpdateInfoTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,150 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Drawing; +using Core.Common.Base.IO; +using Core.Common.TestUtil; +using Core.Common.Util; +using Core.Gui.Plugin; +using Core.Gui.Properties; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Plugin +{ + [TestFixture] + public class UpdateInfoTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var info = new UpdateInfo(); + + // Assert + Assert.IsNull(info.DataType); + Assert.IsNull(info.CreateFileImporter); + Assert.IsNull(info.IsEnabled); + Assert.IsNull(info.Name); + Assert.AreEqual("Bijwerken gegevens", info.Category); + TestHelper.AssertImagesAreEqual(Resources.brick, info.Image); + Assert.IsNull(info.FileFilterGenerator); + Assert.IsNull(info.CurrentPath); + Assert.IsNull(info.VerifyUpdates); + } + + [Test] + public void DefaultGenericConstructor_ExpectedValues() + { + // Call + var info = new UpdateInfo<int>(); + + // Assert + Assert.AreEqual(typeof(int), info.DataType); + Assert.IsNull(info.CreateFileImporter); + Assert.IsNull(info.IsEnabled); + Assert.IsNull(info.Name); + Assert.AreEqual("Bijwerken gegevens", info.Category); + TestHelper.AssertImagesAreEqual(Resources.brick, info.Image); + Assert.IsNull(info.FileFilterGenerator); + Assert.IsNull(info.CurrentPath); + Assert.IsNull(info.VerifyUpdates); + } + + [Test] + public void ImplicitOperator_OptionalDelegatesAndPropertiesSet_UpdateInfoFullyConverted() + { + // Setup + var mocks = new MockRepository(); + var fileUpdateer = mocks.StrictMock<IFileImporter>(); + mocks.ReplayAll(); + + const string name = "name"; + const string category = "category"; + const string path = "somePath"; + var image = new Bitmap(16, 16); + var generator = new FileFilterGenerator(); + + var info = new UpdateInfo<int> + { + CreateFileImporter = (data, filePath) => fileUpdateer, + IsEnabled = data => false, + Name = name, + Category = category, + Image = image, + FileFilterGenerator = generator, + VerifyUpdates = i => true, + CurrentPath = i => path + }; + + // Precondition + Assert.IsInstanceOf<UpdateInfo<int>>(info); + + // Call + UpdateInfo convertedInfo = info; + + // Assert + Assert.IsInstanceOf<UpdateInfo>(convertedInfo); + Assert.AreEqual(typeof(int), convertedInfo.DataType); + Assert.IsNotNull(convertedInfo.CreateFileImporter); + Assert.AreSame(fileUpdateer, convertedInfo.CreateFileImporter(12, "")); + Assert.IsNotNull(convertedInfo.IsEnabled); + Assert.IsFalse(convertedInfo.IsEnabled(12)); + Assert.AreEqual(name, info.Name); + Assert.AreEqual(category, info.Category); + Assert.AreSame(image, info.Image); + Assert.AreEqual(generator, info.FileFilterGenerator); + Assert.IsNotNull(convertedInfo.VerifyUpdates); + Assert.IsTrue(convertedInfo.VerifyUpdates(12)); + Assert.IsNotNull(convertedInfo.CurrentPath); + Assert.AreEqual(path, convertedInfo.CurrentPath(12)); + + mocks.VerifyAll(); + } + + [Test] + public void ImplicitOperator_NoneOfTheOptionalDelegatesAndPropertiesSet_UpdateInfoFullyConverted() + { + // Setup + var info = new UpdateInfo<int>(); + + // Precondition + Assert.IsInstanceOf<UpdateInfo<int>>(info); + + // Call + UpdateInfo convertedInfo = info; + + // Assert + Assert.IsInstanceOf<UpdateInfo>(convertedInfo); + Assert.AreEqual(typeof(int), convertedInfo.DataType); + Assert.IsNotNull(convertedInfo.CreateFileImporter); + Assert.IsNull(convertedInfo.CreateFileImporter(12, "")); + Assert.IsNotNull(convertedInfo.IsEnabled); + Assert.IsTrue(convertedInfo.IsEnabled(12)); + Assert.IsNull(info.Name); + Assert.AreEqual("Bijwerken gegevens", info.Category); + TestHelper.AssertImagesAreEqual(Resources.brick, info.Image); + Assert.IsNull(info.FileFilterGenerator); + Assert.IsNull(info.CurrentPath); + Assert.IsNull(info.VerifyUpdates); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Plugin/ViewInfoTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Plugin/ViewInfoTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Plugin/ViewInfoTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,321 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Drawing; +using Core.Common.Controls.Views; +using Core.Gui.Plugin; +using Core.Gui.Test.Properties; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.Plugin +{ + [TestFixture] + public class ViewInfoTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var viewInfo = new ViewInfo(); + + // Assert + Assert.IsNull(viewInfo.DataType); + Assert.IsNull(viewInfo.ViewDataType); + Assert.IsNull(viewInfo.ViewType); + Assert.IsNull(viewInfo.Description); + Assert.IsNull(viewInfo.GetViewName); + Assert.IsNull(viewInfo.Image); + Assert.IsNull(viewInfo.AdditionalDataCheck); + Assert.IsNull(viewInfo.GetViewData); + Assert.IsNull(viewInfo.AfterCreate); + Assert.IsNull(viewInfo.CloseForData); + Assert.IsNotNull(viewInfo.CreateInstance); + } + + [Test] + public void SimpleProperties_SetNewValues_GetNewlySetValues() + { + // Setup + var mocks = new MockRepository(); + var viewInstance = mocks.Stub<IView>(); + mocks.ReplayAll(); + + var viewInfo = new ViewInfo(); + + Type newDataType = typeof(int); + Type newViewDataType = typeof(string); + Type viewType = typeof(StringView); + const string newDescription = "<text>"; + Func<IView, object, string> getViewNameDelegate = (view, o) => ""; + Image icon = Resources.abacus; + Func<object, bool> additionalDataDelegate = o => true; + Func<object, object> getViewDataDelegate = o => 45; + Action<IView, object> afterCreateDelegate = (view, o) => + { + // Do something useful + }; + Func<IView, object, bool> closeViewForDataDelegate = (view, o) => true; + Func<object, IView> createInstanceDelegate = o => viewInstance; + + // Call + viewInfo.DataType = newDataType; + viewInfo.ViewDataType = newViewDataType; + viewInfo.ViewType = viewType; + viewInfo.Description = newDescription; + viewInfo.GetViewName = getViewNameDelegate; + viewInfo.Image = icon; + viewInfo.AdditionalDataCheck = additionalDataDelegate; + viewInfo.GetViewData = getViewDataDelegate; + viewInfo.AfterCreate = afterCreateDelegate; + viewInfo.CloseForData = closeViewForDataDelegate; + viewInfo.CreateInstance = createInstanceDelegate; + + // Assert + Assert.AreEqual(newDataType, viewInfo.DataType); + Assert.AreEqual(newViewDataType, viewInfo.ViewDataType); + Assert.AreEqual(viewType, viewInfo.ViewType); + Assert.AreEqual(newDescription, viewInfo.Description); + Assert.AreEqual(getViewNameDelegate, viewInfo.GetViewName); + Assert.AreEqual(icon, viewInfo.Image); + Assert.AreEqual(additionalDataDelegate, viewInfo.AdditionalDataCheck); + Assert.AreEqual(getViewDataDelegate, viewInfo.GetViewData); + Assert.AreEqual(afterCreateDelegate, viewInfo.AfterCreate); + Assert.AreEqual(closeViewForDataDelegate, viewInfo.CloseForData); + Assert.AreEqual(createInstanceDelegate, viewInfo.CreateInstance); + } + + [Test] + public void CreateInstance_ViewtypeWithDefaultConstructor_ReturnView() + { + // Setup + var viewInfo = new ViewInfo + { + DataType = typeof(int), + ViewDataType = typeof(string), + ViewType = typeof(StringView) + }; + + int data = new Random(21).Next(); + + // Call + IView view = viewInfo.CreateInstance(data); + + // Assert + Assert.IsInstanceOf<StringView>(view); + Assert.IsNull(view.Data); + } + + [Test] + public void ToString_WithRelevantFieldsInitialized_ReturnText() + { + // Setup + var viewInfo = new ViewInfo + { + DataType = typeof(int), + ViewDataType = typeof(string), + ViewType = typeof(StringView) + }; + + // Call + string text = viewInfo.ToString(); + + // Assert + string expectedText = $"{viewInfo.DataType} : {viewInfo.ViewDataType} : {viewInfo.ViewType}"; + Assert.AreEqual(expectedText, text); + } + + [Test] + public void DefaultGenericConstructor_ExpectedValues() + { + // Call + var viewInfo = new ViewInfo<int, string, StringView>(); + + // Assert + Assert.AreEqual(typeof(int), viewInfo.DataType); + Assert.AreEqual(typeof(string), viewInfo.ViewDataType); + Assert.AreEqual(typeof(StringView), viewInfo.ViewType); + Assert.IsNull(viewInfo.Description); + Assert.IsNull(viewInfo.GetViewName); + Assert.IsNull(viewInfo.Image); + Assert.IsNull(viewInfo.AdditionalDataCheck); + Assert.IsNull(viewInfo.GetViewData); + Assert.IsNull(viewInfo.AfterCreate); + Assert.IsNull(viewInfo.CloseForData); + Assert.IsNotNull(viewInfo.CreateInstance); + } + + [Test] + public void SimpleProperties_GenericViewInfoSetNewValues_GetNewlySetValues() + { + // Setup + var viewInfo = new ViewInfo<int, string, StringView>(); + + const string newDescription = "<text>"; + Func<IView, int, string> getViewNameDelegate = (view, o) => ""; + Image icon = Resources.abacus; + Func<int, bool> additionalDataDelegate = o => true; + Func<int, string> getViewDataDelegate = o => o.ToString(); + Action<IView, int> afterCreateDelegate = (view, o) => + { + // Do something useful + }; + Func<IView, object, bool> closeViewForDataDelegate = (view, o) => true; + Func<int, StringView> createInstanceDelegate = o => new StringView(); + + // Call + viewInfo.Description = newDescription; + viewInfo.GetViewName = getViewNameDelegate; + viewInfo.Image = icon; + viewInfo.AdditionalDataCheck = additionalDataDelegate; + viewInfo.GetViewData = getViewDataDelegate; + viewInfo.AfterCreate = afterCreateDelegate; + viewInfo.CloseForData = closeViewForDataDelegate; + viewInfo.CreateInstance = createInstanceDelegate; + + // Assert + Assert.AreEqual(newDescription, viewInfo.Description); + Assert.AreEqual(getViewNameDelegate, viewInfo.GetViewName); + Assert.AreEqual(icon, viewInfo.Image); + Assert.AreEqual(additionalDataDelegate, viewInfo.AdditionalDataCheck); + Assert.AreEqual(getViewDataDelegate, viewInfo.GetViewData); + Assert.AreEqual(afterCreateDelegate, viewInfo.AfterCreate); + Assert.AreEqual(closeViewForDataDelegate, viewInfo.CloseForData); + } + + [Test] + public void ToString_GenericViewInfoWithRelevantFieldsInitialized_ReturnText() + { + // Setup + var viewInfo = new ViewInfo<int, string, StringView>(); + + // Call + string text = viewInfo.ToString(); + + // Assert + string expectedText = $"{viewInfo.DataType} : {viewInfo.ViewDataType} : {viewInfo.ViewType}"; + Assert.AreEqual(expectedText, text); + } + + [Test] + public void CreateInstance_ViewTypeHasDefaultConstructor_ReturnView() + { + // Setup + var viewInfo = new ViewInfo<int, string, StringView>(); + int data = new Random(21).Next(); + + // Call + StringView view = viewInfo.CreateInstance(data); + + // Assert + Assert.IsNotNull(view); + Assert.IsNull(view.Data); + } + + [Test] + public void ImplicitOperator_WithAllMethodsSet_InfoFullyConverted() + { + // Setup + var viewInfo = new ViewInfo<int, string, StringView>(); + + var stringView = new StringView(); + const int dataObject = 11; + + const string newDescription = "<text>"; + const string newViewName = "<view name>"; + Func<IView, int, string> getViewNameDelegate = (view, o) => + { + Assert.AreSame(stringView, view); + Assert.AreEqual(dataObject, o); + return newViewName; + }; + Image icon = Resources.abacus; + Func<int, bool> additionalDataDelegate = o => + { + Assert.AreEqual(dataObject, o); + return true; + }; + Func<int, string> getViewDataDelegate = o => + { + Assert.AreEqual(dataObject, o); + return o.ToString(); + }; + var afterCreateDelegateCalled = false; + Action<IView, int> afterCreateDelegate = (view, o) => + { + Assert.AreSame(stringView, view); + Assert.AreEqual(dataObject, o); + afterCreateDelegateCalled = true; + }; + Func<IView, object, bool> closeViewForDataDelegate = (view, o) => + { + Assert.AreSame(stringView, view); + Assert.AreEqual(dataObject, o); + return true; + }; + + viewInfo.Description = newDescription; + viewInfo.GetViewName = getViewNameDelegate; + viewInfo.Image = icon; + viewInfo.AdditionalDataCheck = additionalDataDelegate; + viewInfo.GetViewData = getViewDataDelegate; + viewInfo.AfterCreate = afterCreateDelegate; + viewInfo.CloseForData = closeViewForDataDelegate; + viewInfo.CreateInstance = o => new StringView + { + Text = "A" + }; + + // Precondition + Assert.IsInstanceOf<ViewInfo<int, string, StringView>>(viewInfo); + + // Call + ViewInfo info = viewInfo; + + // Assert + Assert.IsInstanceOf<ViewInfo>(info); + Assert.AreEqual(typeof(int), info.DataType); + Assert.AreEqual(typeof(string), info.ViewDataType); + Assert.AreEqual(typeof(StringView), info.ViewType); + Assert.AreEqual(newDescription, info.Description); + Assert.AreEqual(newViewName, info.GetViewName(stringView, dataObject)); + Assert.AreEqual(icon, info.Image); + Assert.IsTrue(viewInfo.AdditionalDataCheck(dataObject)); + Assert.AreEqual(dataObject.ToString(), viewInfo.GetViewData(dataObject)); + Assert.AreEqual("A", viewInfo.CreateInstance(dataObject).Text); + + viewInfo.AfterCreate(stringView, dataObject); + Assert.IsTrue(afterCreateDelegateCalled); + } + + private class StringView : IView + { + public object Data { get; set; } + public string Text { get; set; } + + public void Dispose() + { + throw new NotImplementedException(); + } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Properties/AssemblyInfo.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Properties/AssemblyInfo.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Properties/AssemblyInfo.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,25 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Reflection; + +[assembly: AssemblyTitle("Core.Gui.Test")] +[assembly: AssemblyProduct("Core.Gui.Test")] \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Properties/Resources.Designer.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Properties/Resources.Designer.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/Properties/Resources.Designer.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,91 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.18444 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Core.Gui.Test.Properties { + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Core.Gui.Test.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// <summary> + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// </summary> + internal static System.Drawing.Bitmap abacus { + get { + object obj = ResourceManager.GetObject("abacus", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} Index: Core/Gui/test/Core.Gui.Test/Properties/Resources.resx =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/Properties/Resources.resx (revision 0) +++ Core/Gui/test/Core.Gui.Test/Properties/Resources.resx (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + <data name="abacus" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>..\Resources\abacus.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> + </data> +</root> \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/PropertyBag/DynamicPropertyBagTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/PropertyBag/DynamicPropertyBagTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/PropertyBag/DynamicPropertyBagTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,600 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.ComponentModel; +using System.Drawing.Design; +using System.Linq; +using Core.Common.TestUtil; +using Core.Gui.Attributes; +using Core.Gui.PropertyBag; +using NUnit.Framework; +using CategoryAttribute = System.ComponentModel.CategoryAttribute; + +namespace Core.Gui.Test.PropertyBag +{ + [TestFixture] + public class DynamicPropertyBagTest + { + [Test] + public void Constructor_PropertyObjectNull_ThrowArgumentNullException() + { + // Call + TestDelegate call = () => new DynamicPropertyBag(null); + + // Assert + string paramName = Assert.Throws<ArgumentNullException>(call).ParamName; + Assert.AreEqual("propertyObject", paramName); + } + + [Test] + public void ParameteredConstructor_ExpectedValues() + { + // Setup + var propertyObject = new object(); + + // Call + var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); + + // Assert + CollectionAssert.IsEmpty(dynamicPropertyBag.Properties, + "Object has no properties, therefore bag should have none too."); + Assert.AreSame(propertyObject, dynamicPropertyBag.WrappedObject); + } + + [Test] + public void Constructor_ClassWith4Properties_CorrectNumberOfPropertiesCreated() + { + // Setup + var propertyObject = new TestProperties(); + + // Call + var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); + + // Assert + Assert.AreEqual(4, dynamicPropertyBag.Properties.Count(), "Expected property count wrong"); + } + + [Test] + public void Constructor_ClassWithAttributes_PropertySpecsHaveAttributesSet() + { + // Setup + var propertyObject = new TestProperties(); + + // Call + var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); + + // Assert + PropertySpec namePropertySpec = dynamicPropertyBag.Properties.First(ps => ps.Name == "Name"); + CollectionAssert.Contains(namePropertySpec.Attributes, new CategoryAttribute("General"), + "Should have initialized Attributes of the property spec with declared Category(\"General\")."); + + PropertySpec descriptionPropertySpec = dynamicPropertyBag.Properties.First(ps => ps.Name == "Description"); + CollectionAssert.Contains(descriptionPropertySpec.Attributes, ReadOnlyAttribute.Yes, + "Should have initialized Attributes of the property spec with declared ReadOnlyAttribute."); + } + + [Test] + public void ToString_ReturnToStringFromWrappedObject() + { + // Setup + var target = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(target); + + // Call + string text = dynamicPropertyBag.ToString(); + + // Assert + Assert.AreEqual(target.ToString(), text); + } + + [Test] + public void GetAttributes_Always_ReturnEmpty() + { + // Setup + var target = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(target); + + // Call + AttributeCollection attributes = dynamicPropertyBag.GetAttributes(); + + // Assert + CollectionAssert.IsEmpty(attributes); + } + + [Test] + public void GetClassName_Always_ReturnDynamicPropertyBagClassName() + { + // Setup + var target = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(target); + + // Call + string className = dynamicPropertyBag.GetClassName(); + + // Assert + Assert.AreEqual(dynamicPropertyBag.GetType().FullName, className); + } + + [Test] + public void GetComponentName_Always_ReturnNull() + { + // Setup + var target = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(target); + + // Call + string componentName = dynamicPropertyBag.GetComponentName(); + + // Assert + Assert.IsNull(componentName); + } + + [Test] + public void GetConverter_Always_ReturnDefaultTypeConverter() + { + // Setup + var target = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(target); + + // Call + TypeConverter typeConverter = dynamicPropertyBag.GetConverter(); + + // Assert + Assert.AreEqual(TypeDescriptor.GetConverter(dynamicPropertyBag, true), typeConverter); + } + + [Test] + public void GetDefaultEvent_Always_ReturnNull() + { + // Setup + var target = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(target); + + // Call + EventDescriptor eventDescriptor = dynamicPropertyBag.GetDefaultEvent(); + + // Assert + Assert.IsNull(eventDescriptor); + } + + [Test] + public void GetEvents_Always_ReturnEmpty() + { + // Setup + var target = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(target); + + // Call + EventDescriptorCollection events = dynamicPropertyBag.GetEvents(); + + // Assert + CollectionAssert.IsEmpty(events); + } + + [Test] + public void GetEventsParametered_Always_ReturnEmpty() + { + // Setup + var target = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(target); + + // Call + EventDescriptorCollection events = dynamicPropertyBag.GetEvents(new Attribute[0]); + + // Assert + CollectionAssert.IsEmpty(events); + } + + [Test] + public void GetEditor_Always_ReturnNull() + { + // Setup + var target = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(target); + + // Call + object editor = dynamicPropertyBag.GetEditor(typeof(UITypeEditor)); + + // Assert + Assert.IsNull(editor); + } + + [Test] + public void GetDefaultProperty_ObjectHasNotProperties_ReturnNull() + { + // Setup + var dynamicPropertyBag = new DynamicPropertyBag(new object()); + + // Call + PropertyDescriptor defaultProperty = dynamicPropertyBag.GetDefaultProperty(); + + // Assert + Assert.IsNull(defaultProperty); + } + + [Test] + public void GetDefaultProperty_ObjectWithProperties_ReturnFirstFromProperties() + { + // Setup + var target = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(target); + + // Call + PropertyDescriptor defaultProperty = dynamicPropertyBag.GetDefaultProperty(); + + // Assert + Assert.NotNull(defaultProperty); + Assert.AreEqual(dynamicPropertyBag.Properties.First().Name, defaultProperty.Name); + } + + [Test] + public void GivenObjectPropertiesWithDynamicVisibleProperties_WhenPropertyShown_ThenPropertyShouldBePresentInBag() + { + // Given + var propertyObject = new TestProperties + { + Visible = true + }; + + var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); + PropertyDescriptorCollection propertyDescriptorCollection = dynamicPropertyBag.GetProperties(new Attribute[] + { + new BrowsableAttribute(true) + }); + + // When + const string dynamicallyVisiblePropertyName = nameof(TestProperties.Name); + PropertyDescriptor namePropertyDescriptor = propertyDescriptorCollection.Find(dynamicallyVisiblePropertyName, false); + + // Then + Assert.IsTrue(namePropertyDescriptor.IsBrowsable, + $"{dynamicallyVisiblePropertyName} should be visible"); + } + + [Test] + public void GivenObjectPropertiesWithDynamicVisibleProperties_WhenPropertyHidden_ThenPropertyNotPresentInBag() + { + // Setup + var propertyObject = new TestProperties + { + Visible = false + }; + + var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); + PropertyDescriptorCollection propertyDescriptorCollection = dynamicPropertyBag.GetProperties(new Attribute[] + { + new BrowsableAttribute(true) + }); + + // Call + const string dynamicallyVisiblePropertyName = nameof(TestProperties.Name); + PropertyDescriptor namePropertyDescriptor = propertyDescriptorCollection.Find(dynamicallyVisiblePropertyName, false); + + // Assert + Assert.IsNull(namePropertyDescriptor, $"{dynamicallyVisiblePropertyName} should not be visible anymore"); + } + + [Test] + public void GetProperties_SomePropertiesWithOrderAttribute_ReturnElementsInDesiredOrdering() + { + // Setup + var dynamicPropertyBag = new DynamicPropertyBag(new TestOrderedProperties()); + + // Call + PropertyDescriptorCollection propertyDescriptorCollection = dynamicPropertyBag.GetProperties(); + + // Assert + var index = 0; + Assert.AreEqual("PropSix", propertyDescriptorCollection[index++].DisplayName); + Assert.AreEqual("PropFour", propertyDescriptorCollection[index++].DisplayName); + Assert.AreEqual("PropTwo", propertyDescriptorCollection[index++].DisplayName); + Assert.AreEqual("PropOne", propertyDescriptorCollection[index++].DisplayName); + Assert.AreEqual("Description", propertyDescriptorCollection[index++].DisplayName); + Assert.AreEqual("PropFive", propertyDescriptorCollection[index++].DisplayName); + Assert.AreEqual("Name", propertyDescriptorCollection[index++].DisplayName); + + PropertyDescriptor propThreeDescriptor = propertyDescriptorCollection.Find("PropThree", false); + Assert.GreaterOrEqual(propertyDescriptorCollection.IndexOf(propThreeDescriptor), index, + "PropThree is not decorated with PropertyOrderAttribute or DynamicPropertyOrderAttribute, therefore should come after those that are."); + PropertyDescriptor propSevenDescriptor = propertyDescriptorCollection.Find("PropSeven", false); + Assert.GreaterOrEqual(propertyDescriptorCollection.IndexOf(propSevenDescriptor), index, + "PropSeven is not decorated with PropertyOrderAttribute or DynamicPropertyOrderAttribute, therefore should come after those that are."); + } + + [Test] + public void GetProperties_PropertyIsDecoratedWithExpandableObjectConverter_WrapPropertyValueInDynamicPropertyBag() + { + // Setup + var subProperties = new TestProperties + { + Name = "test" + }; + var testProperties = new TestWithNestedPropertiesClassProperties + { + SubProperties = subProperties + }; + var dynamicPropertyBag = new DynamicPropertyBag(testProperties); + + // Call + PropertyDescriptorCollection propertiesCollection = dynamicPropertyBag.GetProperties(); + + // Assert + var bag = propertiesCollection[0].GetValue(dynamicPropertyBag.WrappedObject) as DynamicPropertyBag; + Assert.NotNull(bag); + Assert.AreSame(subProperties, bag.WrappedObject); + } + + [Test] + public void GivenPropertyDescriptorFromDynamicPropertyBag_WhenSettingProperty_ThenWrappedObjectUpdated() + { + // Given + var testProperties = new TestProperties + { + Name = "name" + }; + var dynamicPropertyBag = new DynamicPropertyBag(testProperties); + + const string newName = "newName"; + + // When + dynamicPropertyBag.GetProperties()["Name"].SetValue(testProperties, newName); + + // Then + Assert.AreEqual(newName, testProperties.Name); + } + + [Test] + public void GetProperties_ClassWithPropertiesWithoutPublicSetter_PropertiesDecoratedWithReadOnlyAttribute() + { + // Setup + var dynamicPropertyBag = new DynamicPropertyBag(new TestWithoutSetterPropertyClassProperties()); + + // Call + PropertyDescriptorCollection propertyDescriptorCollection = dynamicPropertyBag.GetProperties(); + + // Assert + Assert.IsTrue(propertyDescriptorCollection[0].Attributes.Matches(ReadOnlyAttribute.Yes)); + Assert.IsTrue(propertyDescriptorCollection[1].Attributes.Matches(ReadOnlyAttribute.Yes)); + } + + [Test] + public void GetProperties_RepeatedCallForSameState_RetainSameElementOrderAndContents() + { + // Setup + var propertyObject = new TestOrderedProperties(); + + var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); + + PropertyDescriptorCollection originalProperties = dynamicPropertyBag.GetProperties(); + + // Call + for (var i = 0; i < 100; i++) + { + PropertyDescriptorCollection currentProperties = dynamicPropertyBag.GetProperties(); + + // Assert + CollectionAssert.AreEqual(originalProperties, currentProperties); + } + } + + [Test] + public void GetProperties_RepeatedConstructionsForSameState_RetainSameElementOrderAndContents() + { + // Setup + var propertyObject = new TestOrderedProperties(); + + PropertyDescriptorCollection originalProperties = new DynamicPropertyBag(propertyObject).GetProperties(); + + // Call + for (var i = 0; i < 100; i++) + { + PropertyDescriptorCollection currentProperties = new DynamicPropertyBag(propertyObject).GetProperties(); + + // Assert + CollectionAssert.AreEqual(originalProperties, currentProperties); + } + } + + [Test] + public void GetProperties_BrowsableTrueFilter_ReturnOnlyPropertiesThatAreBrowsable() + { + // Setup + var propertyObject = new TestProperties + { + Visible = false + }; + var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); + + // Call + PropertyDescriptorCollection properties = PropertiesTestHelper.GetAllVisiblePropertyDescriptors(propertyObject); + + // Assert + Assert.Less(properties.Count, dynamicPropertyBag.Properties.Count()); + Assert.IsNull(properties.Find("Name", false), + "Name is dynamically not browsable, therefore should not be returned."); + Assert.IsNotNull(properties.Find("Description", false)); + Assert.IsNotNull(properties.Find("IsNameReadOnly", false)); + Assert.IsNull(properties.Find("Visible", false), + "Visible is statically not browsable, therefore should not be returned."); + } + + [Test] + public void GetProperties_BrowsableNoFilter_ReturnOnlyPropertiesThatAreBrowsable() + { + // Setup + var propertyObject = new TestProperties + { + Visible = false + }; + var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); + + // Call + PropertyDescriptorCollection properties = dynamicPropertyBag.GetProperties(new Attribute[] + { + BrowsableAttribute.No + }); + + // Assert + Assert.Less(properties.Count, dynamicPropertyBag.Properties.Count()); + Assert.IsNotNull(properties.Find("Name", false), + "Name is dynamically not browsable, therefore should be returned."); + Assert.IsNull(properties.Find("Description", false)); + Assert.IsNull(properties.Find("IsNameReadOnly", false)); + Assert.IsNotNull(properties.Find("Visible", false), + "Visible is statically not browsable, therefore should be returned."); + } + + [Test] + public void GetPropertyOwner_Always_ReturnWrappedObject() + { + // Setup + var propertyObject = new TestProperties(); + var dynamicPropertyBag = new DynamicPropertyBag(propertyObject); + + // Call + object owner = dynamicPropertyBag.GetPropertyOwner(null); + + // Assert + Assert.AreSame(propertyObject, owner); + } + + #region Test Classes + + private class TestOrderedProperties + { + [PropertyOrder(6)] + public string Name { get; set; } + + [PropertyOrder(4)] + public string Description { get; set; } + + [PropertyOrder(3)] + public string PropOne { get; set; } + + [PropertyOrder(2)] + public string PropTwo { get; set; } + + public int PropThree { get; set; } + + [DynamicPropertyOrder] + public int PropFour { get; set; } + + [DynamicPropertyOrder] + public int PropFive { get; set; } + + [PropertyOrder(0)] + [DynamicPropertyOrder] + public int PropSix { get; set; } + + public int PropSeven { get; set; } + + [DynamicPropertyOrderEvaluationMethod] + public int PropertyOrder(string propertyName) + { + if (propertyName == "PropFour") + { + return 1; + } + + if (propertyName == "PropFive") + { + return 5; + } + + return 7; + } + } + + private class TestWithNestedPropertiesClassProperties + { + [TypeConverter(typeof(ExpandableObjectConverter))] + public TestProperties SubProperties { get; set; } + } + + private class TestProperties + { + public TestProperties() + { + Name = "my name"; + Description = "short description"; + Visible = true; + IsNameReadOnly = true; + } + + /// <summary> + /// Dynamic property. ReadOnly when IsNameReadOnly true. + /// </summary> + [DynamicReadOnly] + [DynamicVisible] + [Category("General")] + public string Name { get; set; } + + [Browsable(true)] + public bool IsNameReadOnly { get; set; } // Property needs to have a setter, otherwise some tests will fail + + [Browsable(false)] + public bool Visible { get; set; } + + [ReadOnly(true)] + public string Description { get; set; } // Property needs to have a setter, otherwise some tests will fail + + /// <summary> + /// Method checks if propertyName property is read-only (setter can be used). + /// </summary> + /// <param name="propertyName"></param> + /// <returns></returns> + [DynamicReadOnlyValidationMethod] + public bool DynamicReadOnlyValidationMethod(string propertyName) + { + Assert.IsTrue(propertyName == "Name"); + + return IsNameReadOnly; + } + + [DynamicVisibleValidationMethod] + public bool DynamicVisibleValidationMethod(string propertyName) + { + return Visible; + } + + public override string ToString() + { + return Name; + } + } + + private class TestWithoutSetterPropertyClassProperties + { + public string PrivateSetter { get; private set; } + + public string NoSetter + { + get + { + return ""; + } + } + } + + #endregion + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/PropertyBag/ObjectPropertiesTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/PropertyBag/ObjectPropertiesTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/PropertyBag/ObjectPropertiesTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,75 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.ComponentModel; +using System.Reflection; +using Core.Gui.PropertyBag; +using NUnit.Framework; + +namespace Core.Gui.Test.PropertyBag +{ + [TestFixture] + public class ObjectPropertiesTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var properties = new ObjectProperties<string>(); + + // Assert + Assert.IsInstanceOf<IObjectProperties>(properties); + Assert.IsNull(properties.Data); + } + + [Test] + public void Data_SetValue_GetNewlySetValue() + { + // Setup + var properties = new ObjectProperties<string>(); + const string text = "text"; + + // Call + properties.Data = text; + + // Assert + Assert.AreEqual(text, properties.Data); + } + + [Test] + public void Data_IsNotBrowsable() + { + // Setup + var properties = new ObjectProperties<string>(); + const string dataPropertyName = nameof(ObjectProperties<string>.Data); + PropertyInfo propertyInfo = properties.GetType().GetProperty(dataPropertyName); + + // Call + var browsableAttribute = (BrowsableAttribute) Attribute.GetCustomAttribute(propertyInfo, + typeof(BrowsableAttribute), + true); + + // Assert + Assert.AreEqual(BrowsableAttribute.No, browsableAttribute); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/PropertyBag/PropertySpecDescriptorTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/PropertyBag/PropertySpecDescriptorTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/PropertyBag/PropertySpecDescriptorTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,360 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.ComponentModel; +using System.Reflection; +using Core.Gui.Attributes; +using Core.Gui.PropertyBag; +using NUnit.Framework; + +namespace Core.Gui.Test.PropertyBag +{ + [TestFixture] + public class PropertySpecDescriptorTest + { + [Test] + public void Constructor_PropertySpecNull_ThrowArgumentNullException() + { + // Call + TestDelegate call = () => new PropertySpecDescriptor(null, new object()); + + // Assert + string paramName = Assert.Throws<ArgumentNullException>(call).ParamName; + Assert.AreEqual("propertySpec", paramName); + } + + [Test] + public void ParameteredConstructor_IsPropertyReadOnlyProperty_ExpectedValues() + { + // Setup + var instance = new ClassWithProperties(); + PropertyInfo propertyInfo = instance.GetType().GetProperty("IsPropertyReadOnly"); + var spec = new PropertySpec(propertyInfo); + + // Call + var propertyDescriptor = new PropertySpecDescriptor(spec, instance); + + // Assert + Assert.AreEqual(spec.GetType(), propertyDescriptor.ComponentType); + Assert.IsFalse(propertyDescriptor.IsReadOnly); + Assert.IsTrue(propertyDescriptor.IsBrowsable); + Assert.AreEqual(propertyInfo.PropertyType, propertyDescriptor.PropertyType); + } + + [Test] + [TestCase(false)] + [TestCase(true)] + public void IsReadOnly_PropertyHasDynamicReadOnlyProperty_ReturnExpectedValue(bool isPropertyReadOnly) + { + // Setup + var instance = new ClassWithProperties + { + IsPropertyReadOnly = isPropertyReadOnly + }; + var propertySpec = new PropertySpec(instance.GetType().GetProperty("IntegerPropertyWithDynamicReadOnly")); + var descriptor = new PropertySpecDescriptor(propertySpec, instance); + + // Call + bool isReadOnly = descriptor.IsReadOnly; + + // Assert + Assert.AreEqual(isPropertyReadOnly, isReadOnly); + } + + [Test] + public void IsReadOnly_PropertyHasReadOnlyTrueAttribute_ReturnTrue() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithReadOnlyAttribute")); + var descriptor = new PropertySpecDescriptor(spec, instance); + + // Call + bool isReadOnly = descriptor.IsReadOnly; + + // Assert + Assert.IsTrue(isReadOnly); + } + + [Test] + public void IsReadOnly_PropertyHasReadOnlyFalseAttribute_ReturnFalse() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithReadOnlyFalseAttribute")); + var descriptor = new PropertySpecDescriptor(spec, instance); + + // Call + bool isReadOnly = descriptor.IsReadOnly; + + // Assert + Assert.IsFalse(isReadOnly); + } + + [Test] + public void IsReadOnly_PropertyHasNoAttributeAndOnlyGetter_ReturnTrue() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithOnlyGetter")); + var descriptor = new PropertySpecDescriptor(spec, instance); + + // Call + bool isReadOnly = descriptor.IsReadOnly; + + // Assert + Assert.IsTrue(isReadOnly); + } + + [Test] + [TestCase(false)] + [TestCase(true)] + public void IsBrowsable_PropertyHasDynamicBrowsableProperty_ReturnExpectedValue(bool isPropertyVisible) + { + // Setup + var instance = new ClassWithProperties + { + IsPropertyBrowsable = isPropertyVisible + }; + var propertySpec = new PropertySpec(instance.GetType().GetProperty("IntegerPropertyWithDynamicVisibility")); + var descriptor = new PropertySpecDescriptor(propertySpec, instance); + + // Call + bool isBrowsable = descriptor.IsBrowsable; + + // Assert + Assert.AreEqual(isPropertyVisible, isBrowsable); + } + + [Test] + public void IsIsBrowsable_PropertyHasBrowsableTrueAttribute_ReturnTrue() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithBrowsableAttribute")); + var descriptor = new PropertySpecDescriptor(spec, instance); + + // Call + bool isBrowsable = descriptor.IsBrowsable; + + // Assert + Assert.IsTrue(isBrowsable); + } + + [Test] + public void IsBrowsable_PropertyHasBrowsableFalseAttribute_ReturnFalse() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithBrowsableFalseAttribute")); + var descriptor = new PropertySpecDescriptor(spec, instance); + + // Call + bool isBrowsable = descriptor.IsBrowsable; + + // Assert + Assert.IsFalse(isBrowsable); + } + + [Test] + public void CanResetValue_ReturnFalse() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithOnlyGetter")); + var propertyDescriptor = new PropertySpecDescriptor(spec, instance); + + // Call + bool canReset = propertyDescriptor.CanResetValue(instance); + + // Assert + Assert.IsFalse(canReset); + } + + [Test] + public void ResetValue_CanNotReset_ThrowsInvalidOperationException() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithOnlyGetter")); + var propertyDescriptor = new PropertySpecDescriptor(spec, instance); + + // Precondition + Assert.IsFalse(propertyDescriptor.CanResetValue(instance)); + + // Call + TestDelegate call = () => propertyDescriptor.ResetValue(instance); + + // Assert + Assert.Throws<InvalidOperationException>(call); + } + + [Test] + public void ShouldSerializeValue_ReturnFalse() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithOnlyGetter")); + var propertyDescriptor = new PropertySpecDescriptor(spec, instance); + + // Call + bool shouldSerializeValue = propertyDescriptor.ShouldSerializeValue(instance); + + // Assert + Assert.IsFalse(shouldSerializeValue); + } + + [Test] + public void GetValue_SimpleValueProperty_ReturnPropertyValue() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("PropertyWithOnlyGetter")); + var propertyDescriptor = new PropertySpecDescriptor(spec, instance); + + // Call + object value = propertyDescriptor.GetValue(instance); + + // Assert + Assert.AreEqual(instance.PropertyWithOnlyGetter, value); + } + + [Test] + public void GetValue_ObjectValueProperty_ReturnPropertyValue() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("ComplexSubProperty")); + var propertyDescriptor = new PropertySpecDescriptor(spec, instance); + + // Call + object value = propertyDescriptor.GetValue(instance); + + // Assert + Assert.AreSame(instance.ComplexSubProperty, value); + } + + [Test] + public void GetValue_ObjectValuePropertyWithExpandableObjectConverterAttribute_ReturnPropertyValueWrappedInDynamicPropertyBag() + { + // Setup + var instance = new ClassWithProperties(); + var spec = new PropertySpec(instance.GetType().GetProperty("ComplexSubPropertyWithExandableObjectConverter")); + var propertyDescriptor = new PropertySpecDescriptor(spec, instance); + + // Call + object value = propertyDescriptor.GetValue(instance); + + // Assert + var dynamicPropertyBag = (DynamicPropertyBag) value; + Assert.IsNotNull(dynamicPropertyBag); + Assert.AreSame(instance.ComplexSubPropertyWithExandableObjectConverter, dynamicPropertyBag.WrappedObject); + } + + private class ClassWithProperties + { + public ClassWithProperties() + { + IsPropertyReadOnly = false; + IsPropertyBrowsable = true; + ComplexSubPropertyWithExandableObjectConverter = new AnotherClassWithProperties + { + Comment = "I have nice type converter, right?" + }; + ComplexSubProperty = new AnotherClassWithProperties + { + Comment = "Don't want your type converter!" + }; + } + + [TypeConverter(typeof(ExpandableObjectConverter))] + public AnotherClassWithProperties ComplexSubPropertyWithExandableObjectConverter { get; } + + public AnotherClassWithProperties ComplexSubProperty { get; } + + #region IsReadOnly state influencing testing members + + public string PropertyWithOnlyGetter + { + get + { + return "I only have a getter."; + } + } + + public bool IsPropertyReadOnly { get; set; } + + [ReadOnly(true)] + public double PropertyWithReadOnlyAttribute { get; set; } + + [ReadOnly(false)] + public double PropertyWithReadOnlyFalseAttribute { get; set; } + + [DynamicReadOnly] + public int IntegerPropertyWithDynamicReadOnly { get; set; } + + [DynamicReadOnlyValidationMethod] + public bool IsReadOnly(string propertyName) + { + if (propertyName == "IntegerPropertyWithDynamicReadOnly") + { + return IsPropertyReadOnly; + } + + throw new NotImplementedException(); + } + + #endregion + + #region IsBrowsable state influencing testing members + + public bool IsPropertyBrowsable { get; set; } + + [Browsable(true)] + public double PropertyWithBrowsableAttribute { get; set; } + + [Browsable(false)] + public double PropertyWithBrowsableFalseAttribute { get; set; } + + [DynamicVisible] + public int IntegerPropertyWithDynamicVisibility { get; set; } + + [DynamicVisibleValidationMethod] + public bool IsVisible(string propertyName) + { + if (propertyName == "IntegerPropertyWithDynamicVisibility") + { + return IsPropertyBrowsable; + } + + throw new NotImplementedException(); + } + + #endregion + } + + private class AnotherClassWithProperties + { + public string Comment { get; set; } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/PropertyBag/PropertySpecTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/PropertyBag/PropertySpecTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/PropertyBag/PropertySpecTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,450 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using Core.Common.TestUtil; +using Core.Gui.PropertyBag; +using NUnit.Framework; + +namespace Core.Gui.Test.PropertyBag +{ + [TestFixture] + public class PropertySpecTest + { + [Test] + public void Constructor_InfoNull_ThrowArgumentNullException() + { + // Call + TestDelegate call = () => new PropertySpec(null); + + // Assert + string paramName = Assert.Throws<ArgumentNullException>(call).ParamName; + Assert.AreEqual("propertyInfo", paramName); + } + + [Test] + public void ParameteredConstructor_FromPropertyWithoutAttributesWithPublicGetSet_ExpectedValues() + { + // Setup + const string propertyName = "IntegerProperty"; + PropertyInfo propertyInfo = typeof(ClassWithProperties).GetProperty(propertyName); + + // Call + var propertySpec = new PropertySpec(propertyInfo); + + // Assert + Assert.AreEqual(propertyName, propertySpec.Name); + Assert.AreEqual(propertyInfo.PropertyType.AssemblyQualifiedName, propertySpec.TypeName); + CollectionAssert.IsEmpty(propertySpec.Attributes); + } + + [Test] + public void ParameteredConstructor_FromPropertyWithoutAttributesWithOnlyPublicGet_ExpectedValues() + { + // Setup + const string propertyName = "DoublePropertyWithOnlyPublicGet"; + PropertyInfo propertyInfo = typeof(ClassWithProperties).GetProperty(propertyName); + + // Call + var propertySpec = new PropertySpec(propertyInfo); + + // Assert + Assert.AreEqual(propertyName, propertySpec.Name); + Assert.AreEqual(propertyInfo.PropertyType.AssemblyQualifiedName, propertySpec.TypeName); + Assert.AreEqual(1, propertySpec.Attributes.Count); + var readOnlyAttribute = (ReadOnlyAttribute) propertySpec.Attributes[0]; + Assert.IsTrue(readOnlyAttribute.IsReadOnly); + } + + [Test] + public void ParameteredConstructor_FromPropertyWithAttributesWithPublicGetSet_ExpectedValues() + { + // Setup + const string propertyName = "StringPropertyWithAttributes"; + PropertyInfo propertyInfo = typeof(ClassWithProperties).GetProperty(propertyName); + + // Call + var propertySpec = new PropertySpec(propertyInfo); + + // Assert + Assert.AreEqual(propertyName, propertySpec.Name); + Assert.AreEqual(propertyInfo.PropertyType.AssemblyQualifiedName, propertySpec.TypeName); + Assert.AreEqual(2, propertySpec.Attributes.Count); + BrowsableAttribute browsableAttribute = propertySpec.Attributes.OfType<BrowsableAttribute>().Single(); + Assert.IsTrue(browsableAttribute.Browsable); + ReadOnlyAttribute readOnlyAttribute = propertySpec.Attributes.OfType<ReadOnlyAttribute>().Single(); + Assert.IsFalse(readOnlyAttribute.IsReadOnly); + } + + [Test] + public void ParameteredConstructor_FromPropertyOverridingAttributesFromBaseClass_InheritedAttributesAreInherited() + { + // Setup + const string propertyName = "StringPropertyWithAttributes"; + PropertyInfo propertyInfo = typeof(InheritorSettingPropertyToNotBrowsable).GetProperty(propertyName); + + // Call + var propertySpec = new PropertySpec(propertyInfo); + + // Assert + Assert.AreEqual(propertyName, propertySpec.Name); + Assert.AreEqual(propertyInfo.PropertyType.AssemblyQualifiedName, propertySpec.TypeName); + Assert.AreEqual(2, propertySpec.Attributes.Count); + BrowsableAttribute browsableAttribute = propertySpec.Attributes.OfType<BrowsableAttribute>().Single(); + Assert.IsFalse(browsableAttribute.Browsable, "Should have the override value."); + ReadOnlyAttribute readOnlyAttribute = propertySpec.Attributes.OfType<ReadOnlyAttribute>().Single(); + Assert.IsFalse(readOnlyAttribute.IsReadOnly, "Should have the base value."); + } + + [Test] + public void ParameteredConstructor_FromPropertyWithAttributesFromBaseClass_InheritedAttributesAreInherited() + { + // Setup + const string propertyName = "BoolPropertyWithAttributes"; + PropertyInfo propertyInfo = typeof(InheritorSettingPropertyToNotBrowsable).GetProperty(propertyName); + + // Call + var propertySpec = new PropertySpec(propertyInfo); + + // Assert + Assert.AreEqual(propertyName, propertySpec.Name); + Assert.AreEqual(propertyInfo.PropertyType.AssemblyQualifiedName, propertySpec.TypeName); + Assert.AreEqual(1, propertySpec.Attributes.Count); + BrowsableAttribute browsableAttribute = propertySpec.Attributes.OfType<BrowsableAttribute>().Single(); + Assert.IsTrue(browsableAttribute.Browsable, + "No override in 'InheritorSettingPropertyToNotBrowsable' for property 'BoolPropertyWithAttributes', so use base class."); + } + + [Test] + public void ParameteredConstructor_ForIndexProperty_ThrowArgumentException() + { + // Setup + PropertyInfo propertyInfo = new ClassWithProperties().GetType().GetProperty("Item"); + + // Call + TestDelegate call = () => new PropertySpec(propertyInfo); + + // Assert + const string expectedMessage = "Index properties are not allowed."; + TestHelper.AssertThrowsArgumentExceptionAndTestMessage<ArgumentException>(call, expectedMessage); + } + + [Test] + public void SetValue_ProperInstanceTypeAndValueType_PropertyIsUpdated() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); + + // Call + propertySpec.SetValue(target, 2); + + // Assert + Assert.AreEqual(2, target.IntegerProperty); + } + + [Test] + public void SetValue_IncorrectInstanceType_ThrowTargetException() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); + + // Call + TestDelegate call = () => propertySpec.SetValue(new object(), 2); + + // Assert + Assert.Throws<TargetException>(call); + } + + [Test] + public void SetValue_InstanceIsNull_ThrowTargetException() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); + + // Call + TestDelegate call = () => propertySpec.SetValue(null, 2); + + // Assert + Assert.Throws<TargetException>(call); + } + + [Test] + public void SetValue_SettingValueResultsInException_ThrowTargetInvocationException() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("ThrowsException")); + + // Call + TestDelegate call = () => propertySpec.SetValue(target, ""); + + // Assert + Exception innerException = Assert.Throws<TargetInvocationException>(call).InnerException; + Assert.IsInstanceOf<ArgumentException>(innerException); + } + + [Test] + public void SetValue_PropertyWithoutPublicSet_ThrowInvalidOperationException() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("DoublePropertyWithOnlyGetter")); + + // Call + TestDelegate call = () => propertySpec.SetValue(target, 2); + + // Assert + var exception = Assert.Throws<InvalidOperationException>(call); + Assert.AreEqual("Property lacks public setter!", exception.Message); + } + + [Test] + public void SetValue_SettingValueOfIncorrectType_ThrowArgumentException() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); + + // Call + TestDelegate call = () => propertySpec.SetValue(target, new object()); + + // Assert + var exception = Assert.Throws<ArgumentException>(call); + Assert.IsNull(exception.InnerException); + } + + [Test] + public void GetValue_ProperInstanceType_ReturnPropertyValue() + { + // Setup + var target = new ClassWithProperties + { + IntegerProperty = 5 + }; + + var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); + + // Call + object value = propertySpec.GetValue(target); + + // Assert + Assert.AreEqual(target.IntegerProperty, value); + } + + [Test] + public void GetValue_PropertyHasNoPublicGetter_ThrowInvalidOperationException() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("DoublePropertyWithOnlyPublicSet")); + + // Call + TestDelegate call = () => propertySpec.GetValue(target); + + // Assert + string message = Assert.Throws<InvalidOperationException>(call).Message; + Assert.AreEqual("Property lacks public getter!", message); + } + + [Test] + public void GetValue_IncorrectInstanceType_ThrowArgumentException() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); + + // Call + TestDelegate call = () => propertySpec.GetValue(new object()); + + // Assert + var exception = Assert.Throws<ArgumentException>(call); + Assert.IsInstanceOf<TargetException>(exception.InnerException); + } + + [Test] + public void GetValue_InstanceIsNull_ThrowArgumentException() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); + + // Call + TestDelegate call = () => propertySpec.GetValue(null); + + // Assert + var exception = Assert.Throws<ArgumentException>(call); + Assert.IsInstanceOf<TargetException>(exception.InnerException); + } + + [Test] + public void IsNonCustomExpandableObjectProperty_PropertyWithoutTypeConverter_ReturnFalse() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("IntegerProperty")); + + // Call + bool hasExpandableObjectTypeConverter = propertySpec.IsNonCustomExpandableObjectProperty(); + + // Assert + Assert.False(hasExpandableObjectTypeConverter); + } + + [Test] + public void IsNonCustomExpandableObjectProperty_PropertyWithExpandableObjectTypeConverter_ReturnTrue() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("StringPropertyWithExpandableObjectConverter")); + + // Call + bool hasExpandableObjectTypeConverter = propertySpec.IsNonCustomExpandableObjectProperty(); + + // Assert + Assert.True(hasExpandableObjectTypeConverter); + } + + [Test] + public void IsNonCustomExpandableObjectProperty_PropertyWithCustomExpandableObjectTypeConverter_ReturnFalse() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("StringPropertyWithCustomExpandableObjectConverter")); + + // Call + bool hasExpandableObjectTypeConverter = propertySpec.IsNonCustomExpandableObjectProperty(); + + // Assert + Assert.False(hasExpandableObjectTypeConverter, + "As we cannot copy the same behavior of a ExpandableObjectConverter with customizations, we should not recognize it as such."); + } + + [Test] + public void IsNonCustomExpandableObjectProperty_PropertyWithSomeTypeConverter_ReturnFalse() + { + // Setup + var target = new ClassWithProperties(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("StringPropertyWithSomeTypeConverter")); + + // Call + bool hasExpandableObjectTypeConverter = propertySpec.IsNonCustomExpandableObjectProperty(); + + // Assert + Assert.False(hasExpandableObjectTypeConverter); + } + + [Test] + public void IsNonCustomExpandableObjectProperty_ExpandableObjectConverterInherited_ReturnTrue() + { + // Setup + var target = new InheritorSettingPropertyToNotBrowsable(); + + var propertySpec = new PropertySpec(target.GetType().GetProperty("StringPropertyWithExpandableObjectConverter")); + + // Call + bool hasExpandableObjectTypeConverter = propertySpec.IsNonCustomExpandableObjectProperty(); + + // Assert + Assert.True(hasExpandableObjectTypeConverter); + } + + private class ClassWithProperties + { + public float this[int index] + { + get + { + return default(float); + } + set {} + } + + public int IntegerProperty { get; set; } + + public double DoublePropertyWithOnlyPublicGet { get; private set; } + + public double DoublePropertyWithOnlyPublicSet { private get; set; } + + public double DoublePropertyWithOnlyGetter + { + get + { + return 0.0; + } + } + + [Browsable(true)] + [ReadOnly(false)] + public virtual string StringPropertyWithAttributes { get; set; } + + [Browsable(true)] + public bool BoolPropertyWithAttributes { get; set; } + + [TypeConverter(typeof(ExpandableObjectConverter))] + public virtual string StringPropertyWithExpandableObjectConverter { get; set; } + + [TypeConverter(typeof(CustomExpandableObjectConverter))] + public string StringPropertyWithCustomExpandableObjectConverter { get; set; } + + [TypeConverter(typeof(SomeTypeConverter))] + public string StringPropertyWithSomeTypeConverter { get; set; } + + public string ThrowsException + { + set + { + throw new ArgumentException(); + } + } + } + + private class InheritorSettingPropertyToNotBrowsable : ClassWithProperties + { + [Browsable(false)] + public override string StringPropertyWithAttributes { get; set; } + + public override string StringPropertyWithExpandableObjectConverter { get; set; } + } + + private class SomeTypeConverter : TypeConverter {} + + private class CustomExpandableObjectConverter : ExpandableObjectConverter {} + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/PropertyBag/ReadOnlyPropertyDescriptorDecoratorTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/PropertyBag/ReadOnlyPropertyDescriptorDecoratorTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/PropertyBag/ReadOnlyPropertyDescriptorDecoratorTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,180 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.ComponentModel; +using Core.Gui.PropertyBag; +using NUnit.Framework; + +namespace Core.Gui.Test.PropertyBag +{ + [TestFixture] + public class ReadOnlyPropertyDescriptorDecoratorTest + { + [Test] + public void Constructor_ExpectedValues() + { + // Setup + var target = new SomeTestClass(); + PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(target); + + PropertyDescriptor getSetProperty = properties[0]; + + // Precondition: + Assert.IsFalse(getSetProperty.IsReadOnly); + + // Call + var readonlyPropertyDescriptor = new ReadOnlyPropertyDescriptorDecorator(getSetProperty); + + // Assert + Assert.IsInstanceOf<PropertyDescriptor>(readonlyPropertyDescriptor); + Assert.IsTrue(readonlyPropertyDescriptor.IsReadOnly); + + Assert.AreEqual(getSetProperty.ComponentType, readonlyPropertyDescriptor.ComponentType); + Assert.AreEqual(getSetProperty.PropertyType, readonlyPropertyDescriptor.PropertyType); + Assert.AreEqual(getSetProperty.Attributes, readonlyPropertyDescriptor.Attributes); + Assert.AreEqual(getSetProperty.Category, readonlyPropertyDescriptor.Category); + Assert.AreEqual(getSetProperty.Converter, readonlyPropertyDescriptor.Converter); + Assert.AreEqual(getSetProperty.Description, readonlyPropertyDescriptor.Description); + Assert.AreEqual(getSetProperty.DesignTimeOnly, readonlyPropertyDescriptor.DesignTimeOnly); + Assert.AreEqual(getSetProperty.DisplayName, readonlyPropertyDescriptor.DisplayName); + Assert.AreEqual(getSetProperty.IsBrowsable, readonlyPropertyDescriptor.IsBrowsable); + Assert.AreEqual(getSetProperty.IsLocalizable, readonlyPropertyDescriptor.IsLocalizable); + Assert.AreEqual(getSetProperty.Name, readonlyPropertyDescriptor.Name); + Assert.AreEqual(getSetProperty.SerializationVisibility, readonlyPropertyDescriptor.SerializationVisibility); + Assert.AreEqual(getSetProperty.SupportsChangeEvents, readonlyPropertyDescriptor.SupportsChangeEvents); + } + + [Test] + public void CanResetValue_Always_DelegateToWrappedPropertyDescriptor() + { + // Setup + var component = new SomeTestClass(); + PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(component); + + PropertyDescriptor getSetProperty = properties[0]; + var wrappedProperty = new ReadOnlyPropertyDescriptorDecorator(getSetProperty); + + // Call + bool result = wrappedProperty.CanResetValue(component); + + // Assert + Assert.AreEqual(getSetProperty.CanResetValue(component), result); + } + + [Test] + public void GetValue_Always_DelegateToWrappedPropertyDescriptor() + { + // Setup + var component = new SomeTestClass + { + SomeEditableProperty = 1.1 + }; + + PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(component); + PropertyDescriptor getSetProperty = properties[0]; + + var wrappedProperty = new ReadOnlyPropertyDescriptorDecorator(getSetProperty); + + // Call + object result = wrappedProperty.GetValue(component); + + // Assert + Assert.AreEqual(getSetProperty.GetValue(component), result); + Assert.AreEqual(component.SomeEditableProperty, result); + } + + [Test] + public void ResetValue_Always_DelegateToWrappedPropertyDescriptor() + { + // Setup + const double originalPropertyValue = 1.1; + var component = new SomeTestClass + { + SomeEditableProperty = originalPropertyValue + }; + + PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(component); + PropertyDescriptor getSetProperty = properties[0]; + + getSetProperty.ResetValue(component); + double expectedPropertyValueAfterReset = component.SomeEditableProperty; + + var wrappedProperty = new ReadOnlyPropertyDescriptorDecorator(getSetProperty); + component.SomeEditableProperty = originalPropertyValue; + + // Call + wrappedProperty.ResetValue(component); + + // Assert + Assert.AreEqual(expectedPropertyValueAfterReset, component.SomeEditableProperty); + } + + [Test] + public void SetValue_Always_DelegateToWrappedPropertyDescriptor() + { + // Setup + const double originalPropertyValue = 1.1; + const double newValue = 2.2; + var component = new SomeTestClass + { + SomeEditableProperty = originalPropertyValue + }; + + PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(component); + PropertyDescriptor getSetProperty = properties[0]; + + getSetProperty.SetValue(component, newValue); + double expectedPropertyValueAfterSet = component.SomeEditableProperty; + + var wrappedProperty = new ReadOnlyPropertyDescriptorDecorator(getSetProperty); + component.SomeEditableProperty = originalPropertyValue; + + // Call + wrappedProperty.SetValue(component, newValue); + + // Assert + Assert.AreEqual(expectedPropertyValueAfterSet, component.SomeEditableProperty); + } + + [Test] + public void ShouldSerializeValue_Always_DelegateToWrappedPropertyDescriptor() + { + // Setup + var component = new SomeTestClass(); + PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(component); + + PropertyDescriptor getSetProperty = properties[0]; + var wrappedProperty = new ReadOnlyPropertyDescriptorDecorator(getSetProperty); + + // Call + bool result = wrappedProperty.ShouldSerializeValue(component); + + // Assert + Assert.AreEqual(getSetProperty.ShouldSerializeValue(component), result); + } + + private class SomeTestClass + { + [ReadOnly(false)] + public double SomeEditableProperty { get; set; } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/Resources/abacus.png =================================================================== diff -u Binary files differ Index: Core/Gui/test/Core.Gui.Test/SaveProjectActivityTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/SaveProjectActivityTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/SaveProjectActivityTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,580 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using Core.Common.Base.Data; +using Core.Common.Base.Service; +using Core.Common.Base.Storage; +using Core.Common.TestUtil; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test +{ + [TestFixture] + public class SaveProjectActivityTest + { + [Test] + [TestCase(true)] + [TestCase(false)] + public void Constructor_ExpectedValues(bool savingExistingProject) + { + // Setup + var mocks = new MockRepository(); + var storeProject = mocks.Stub<IStoreProject>(); + var project = mocks.Stub<IProject>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + mocks.ReplayAll(); + + // Call + var activity = new SaveProjectActivity(project, "", savingExistingProject, storeProject, projectOwner); + + // Assert + Assert.IsInstanceOf<Activity>(activity); + Assert.IsNull(activity.ProgressText); + Assert.AreEqual(ActivityState.None, activity.State); + + string exitingPrefix = savingExistingProject ? "bestaand " : ""; + string expectedName = $"Opslaan van {exitingPrefix}project"; + Assert.AreEqual(expectedName, activity.Description); + + mocks.VerifyAll(); + } + + [Test] + public void Constructor_FilePathNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var storeProject = mocks.Stub<IStoreProject>(); + var project = mocks.Stub<IProject>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + mocks.ReplayAll(); + + // Call + TestDelegate call = () => new SaveProjectActivity(project, null, true, storeProject, projectOwner); + + // Assert + string paramName = Assert.Throws<ArgumentNullException>(call).ParamName; + Assert.AreEqual("filePath", paramName); + mocks.VerifyAll(); + } + + [Test] + public void Constructor_ProjectNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var storeProject = mocks.Stub<IStoreProject>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + mocks.ReplayAll(); + + // Call + TestDelegate call = () => new SaveProjectActivity(null, "", true, storeProject, projectOwner); + + // Assert + string paramName = Assert.Throws<ArgumentNullException>(call).ParamName; + Assert.AreEqual("project", paramName); + mocks.VerifyAll(); + } + + [Test] + public void Constructor_StoreProjectNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + mocks.ReplayAll(); + + // Call + TestDelegate call = () => new SaveProjectActivity(project, "", true, null, projectOwner); + + // Assert + string paramName = Assert.Throws<ArgumentNullException>(call).ParamName; + Assert.AreEqual("storeProject", paramName); + } + + [Test] + public void Constructor_ProjectOwnerNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var storeProject = mocks.Stub<IStoreProject>(); + mocks.ReplayAll(); + + // Call + TestDelegate call = () => new SaveProjectActivity(project, "", true, storeProject, null); + + // Assert + string paramName = Assert.Throws<ArgumentNullException>(call).ParamName; + Assert.AreEqual("projectOwner", paramName); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void Run_UnstagedProject_StageAndSaveProjectWithoutAdditionalLogMessages(bool saveExistingProject) + { + // Setup + const string filePath = "A"; + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.StrictMock<IStoreProject>(); + storeProject.Stub(sp => sp.HasStagedProject) + .Return(false); + using (mocks.Ordered()) + { + storeProject.Expect(sp => sp.StageProject(project)); + storeProject.Expect(sp => sp.SaveProjectAs(filePath)); + } + + mocks.ReplayAll(); + + var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); + + // Call + Action call = () => activity.Run(); + + // Assert + string prefix = saveExistingProject ? "bestaand " : ""; + TestHelper.AssertLogMessageIsGenerated(call, $"Opslaan van {prefix}project is gestart.", 1); + Assert.AreEqual(ActivityState.Executed, activity.State); + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void Run_AlreadyStagedProject_SaveProjectWithoutAdditionalLogMessages(bool saveExistingProject) + { + // Setup + const string filePath = "A"; + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.StrictMock<IStoreProject>(); + storeProject.Stub(sp => sp.HasStagedProject) + .Return(true); + storeProject.Expect(sp => sp.SaveProjectAs(filePath)); + mocks.ReplayAll(); + + var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); + + // Call + Action call = () => activity.Run(); + + // Assert + string prefix = saveExistingProject ? "bestaand " : ""; + TestHelper.AssertLogMessageIsGenerated(call, $"Opslaan van {prefix}project is gestart.", 1); + Assert.AreEqual(ActivityState.Executed, activity.State); + mocks.VerifyAll(); + } + + [Test] + [TestCaseSource(nameof(GetExceptions))] + public void Run_SaveProjectAsThrowsException_FailedWithAdditionalLogMessages(Exception exception, string errorMessage) + { + // Setup + const string filePath = "A"; + + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.Stub<IStoreProject>(); + storeProject.Stub(sp => sp.HasStagedProject) + .Return(true); + storeProject.Stub(sp => sp.SaveProjectAs(filePath)) + .Throw(exception); + mocks.ReplayAll(); + + var activity = new SaveProjectActivity(project, filePath, false, storeProject, projectOwner); + + // Call + Action call = () => activity.Run(); + + // Assert + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, + new[] + { + Tuple.Create("Opslaan van project is gestart.", LogLevelConstant.Info), + Tuple.Create(errorMessage, LogLevelConstant.Error) + }, 2); + Assert.AreEqual(ActivityState.Failed, activity.State); + mocks.VerifyAll(); + } + + [Test] + [TestCaseSource(nameof(GetExceptions))] + public void Run_SaveExistingProjectAsThrowsException_FailedWithAdditionalLogMessages(Exception exception, string errorMessage) + { + // Setup + const string filePath = "A"; + + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.Stub<IStoreProject>(); + storeProject.Stub(sp => sp.HasStagedProject) + .Return(true); + storeProject.Stub(sp => sp.SaveProjectAs(filePath)) + .Throw(exception); + mocks.ReplayAll(); + + var activity = new SaveProjectActivity(project, filePath, true, storeProject, projectOwner); + + // Call + Action call = () => activity.Run(); + + // Assert + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, + new[] + { + Tuple.Create("Opslaan van bestaand project is gestart.", LogLevelConstant.Info), + Tuple.Create(errorMessage, LogLevelConstant.Error) + }, 2); + Assert.AreEqual(ActivityState.Failed, activity.State); + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void Run_UnstagedProject_ExpectedProgressMessages(bool saveExistingProject) + { + // Setup + const string filePath = "A"; + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.StrictMock<IStoreProject>(); + storeProject.Stub(sp => sp.HasStagedProject) + .Return(false); + using (mocks.Ordered()) + { + storeProject.Expect(sp => sp.StageProject(project)); + storeProject.Expect(sp => sp.SaveProjectAs(filePath)); + } + + mocks.ReplayAll(); + + var progressMessages = new List<string>(); + + var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); + activity.ProgressChanged += (sender, args) => + { + Assert.AreSame(activity, sender); + Assert.AreEqual(EventArgs.Empty, args); + + progressMessages.Add(activity.ProgressText); + }; + + // Call + activity.Run(); + + // Assert + int totalSteps = saveExistingProject ? 2 : 3; + string[] expectedProgressMessages = + { + $"Stap 1 van {totalSteps} | Voorbereidingen opslaan", + $"Stap 2 van {totalSteps} | Project opslaan" + }; + CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void Run_AlreadyStagedProject_ExpectedProgressMessages(bool saveExistingProject) + { + // Setup + const string filePath = "A"; + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var projectOwner = mocks.Stub<IProjectOwner>(); + var storeProject = mocks.StrictMock<IStoreProject>(); + storeProject.Stub(sp => sp.HasStagedProject) + .Return(true); + storeProject.Expect(sp => sp.SaveProjectAs(filePath)); + mocks.ReplayAll(); + + var progressMessages = new List<string>(); + + var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); + activity.ProgressChanged += (sender, args) => + { + Assert.AreSame(activity, sender); + Assert.AreEqual(EventArgs.Empty, args); + + progressMessages.Add(activity.ProgressText); + }; + + // Call + activity.Run(); + + // Assert + int totalSteps = saveExistingProject ? 1 : 2; + string[] expectedProgressMessages = + { + $"Stap 1 van {totalSteps} | Project opslaan" + }; + CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); + mocks.VerifyAll(); + } + + [Test] + public void GivenSaveProjectActivityAndSuccessfullySavedNewProject_WhenFinishingSaveProjectActivity_ThenUpdateProjectAndProjectOwnerWithMessage() + { + // Given + const string fileName = "A"; + string filePath = $@"C:\\folder\{fileName}.rtd"; + + var mocks = new MockRepository(); + var storeProject = mocks.Stub<IStoreProject>(); + + var project = mocks.Stub<IProject>(); + project.Expect(p => p.NotifyObservers()); + + var projectOwner = mocks.StrictMock<IProjectOwner>(); + projectOwner.Expect(po => po.SetProject(project, filePath)); + mocks.ReplayAll(); + + var activity = new SaveProjectActivity(project, filePath, false, storeProject, projectOwner); + activity.Run(); + + // Precondition + Assert.AreEqual(ActivityState.Executed, activity.State); + + // When + Action call = () => + { + activity.LogState(); + activity.Finish(); + }; + + // Then + Tuple<string, LogLevelConstant> expectedMessage = Tuple.Create("Opslaan van project is gelukt.", + LogLevelConstant.Info); + TestHelper.AssertLogMessageWithLevelIsGenerated(call, expectedMessage, 1); + Assert.AreEqual(ActivityState.Finished, activity.State); + Assert.AreEqual(fileName, project.Name); + mocks.VerifyAll(); + } + + [Test] + public void GivenSaveProjectActivityAndSuccessfullySavedExistingProject_WhenFinishingSaveProjectActivity_ThenDoNotUpdateProjectAndProjectOwnerWithMessage() + { + // Given + const string fileName = "A"; + string filePath = $@"C:\\folder\{fileName}.rtd"; + + var mocks = new MockRepository(); + var storeProject = mocks.Stub<IStoreProject>(); + var project = mocks.StrictMock<IProject>(); + var projectOwner = mocks.StrictMock<IProjectOwner>(); + mocks.ReplayAll(); + + var activity = new SaveProjectActivity(project, filePath, true, storeProject, projectOwner); + activity.Run(); + + // Precondition + Assert.AreEqual(ActivityState.Executed, activity.State); + + // When + Action call = () => + { + activity.LogState(); + activity.Finish(); + }; + + // Assert + Tuple<string, LogLevelConstant> expectedMessage = Tuple.Create("Opslaan van bestaand project is gelukt.", + LogLevelConstant.Info); + TestHelper.AssertLogMessageWithLevelIsGenerated(call, expectedMessage, 1); + Assert.AreEqual(ActivityState.Finished, activity.State); + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void Finish_SuccessfullySavedNewProject_ExpectedProgressMessages(bool hasStagedProject) + { + // Setup + const string fileName = "A"; + string filePath = $@"C:\\folder\{fileName}.rtd"; + + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var storeProject = mocks.Stub<IStoreProject>(); + storeProject.Stub(sp => sp.HasStagedProject).Return(hasStagedProject); + storeProject.Stub(sp => sp.StageProject(project)); + storeProject.Stub(sp => sp.SaveProjectAs(filePath)); + + var projectOwner = mocks.Stub<IProjectOwner>(); + mocks.ReplayAll(); + + var activity = new SaveProjectActivity(project, filePath, false, storeProject, projectOwner); + activity.Run(); + + // Precondition + Assert.AreEqual(ActivityState.Executed, activity.State); + + var progressMessages = new List<string>(); + activity.ProgressChanged += (sender, args) => + { + Assert.AreSame(activity, sender); + Assert.AreEqual(EventArgs.Empty, args); + + progressMessages.Add(activity.ProgressText); + }; + + // Call + activity.Finish(); + + // Assert + int totalSteps = hasStagedProject ? 2 : 3; + string[] expectedProgressMessages = + { + $"Stap {totalSteps} van {totalSteps} | Initialiseren van opgeslagen project" + }; + CollectionAssert.AreEqual(expectedProgressMessages, progressMessages); + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GivenActivityStagingProject_WhenCancelling_ThenProjectNotSavedWithAdditionalLogMessages(bool saveExistingProject) + { + // Given + const string filePath = "A"; + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + var projectOwner = mocks.StrictMock<IProjectOwner>(); + var storeProject = mocks.StrictMock<IStoreProject>(); + storeProject.Stub(sp => sp.HasStagedProject) + .Return(false); + using (mocks.Ordered()) + { + storeProject.Expect(sp => sp.StageProject(project)); + storeProject.Expect(sp => sp.SaveProjectAs(filePath)) + .Repeat.Never(); + } + + mocks.ReplayAll(); + + var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); + activity.ProgressChanged += (sender, args) => activity.Cancel(); + + // When + Action call = () => + { + activity.Run(); // Cancel called mid-progress + activity.LogState(); + activity.Finish(); + }; + + // Then + string prefix = saveExistingProject ? "bestaand " : ""; + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, + new[] + { + Tuple.Create($"Opslaan van {prefix}project is gestart.", + LogLevelConstant.Info), + Tuple.Create($"Opslaan van {prefix}project is geannuleerd.", + LogLevelConstant.Warn) + }, 2); + + Assert.AreEqual(ActivityState.Canceled, activity.State); + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void GivenActivitySavingStagedProject_WhenCancelling_ThenProjectSavedWithAdditionalLogMessage(bool saveExistingProject) + { + // Given + const string filePath = "A"; + var mocks = new MockRepository(); + var project = mocks.Stub<IProject>(); + + var projectOwner = mocks.Stub<IProjectOwner>(); + if (!saveExistingProject) + { + projectOwner.Expect(po => po.SetProject(project, filePath)); + } + + var storeProject = mocks.StrictMock<IStoreProject>(); + storeProject.Stub(sp => sp.HasStagedProject) + .Return(true); + storeProject.Expect(sp => sp.SaveProjectAs(filePath)); + mocks.ReplayAll(); + + var calledCancel = false; + var activity = new SaveProjectActivity(project, filePath, saveExistingProject, storeProject, projectOwner); + activity.ProgressChanged += (sender, args) => + { + if (calledCancel) + { + activity.Cancel(); + calledCancel = true; + } + }; + + // When + Action call = () => + { + activity.Run(); // Cancel called mid-progress but beyond 'point of no return' + activity.LogState(); + activity.Finish(); + }; + + // Then + string prefix = saveExistingProject ? "bestaand " : ""; + TestHelper.AssertLogMessagesWithLevelAreGenerated(call, + new[] + { + Tuple.Create($"Opslaan van {prefix}project is gestart.", + LogLevelConstant.Info), + Tuple.Create($"Opslaan van {prefix}project is gelukt.", + LogLevelConstant.Info) + }, 2); + + Assert.AreEqual(ActivityState.Finished, activity.State); + mocks.VerifyAll(); + } + + private static IEnumerable<TestCaseData> GetExceptions() + { + const string exceptionMessage = "I am an error message"; + + yield return new TestCaseData(new ArgumentException(exceptionMessage), exceptionMessage); + yield return new TestCaseData(new CouldNotConnectException(exceptionMessage), exceptionMessage); + yield return new TestCaseData(new StorageValidationException(exceptionMessage), exceptionMessage); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/UITypeEditors/ColorEditorTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/UITypeEditors/ColorEditorTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/UITypeEditors/ColorEditorTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,82 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Drawing.Design; +using Core.Gui.UITypeEditors; +using NUnit.Extensions.Forms; +using NUnit.Framework; + +namespace Core.Gui.Test.UITypeEditors +{ + [TestFixture] + public class ColorEditorTest : NUnitFormTest + { + [Test] + public void DefaultConstructor_ReturnsNewInstance() + { + // Call + var editor = new ColorEditor(); + + // Assert + Assert.IsInstanceOf<UITypeEditor>(editor); + } + + [Test] + public void GetEditStyle_Always_ReturnUITypeEditorEditStyleModal() + { + // Setup + var editor = new ColorEditor(); + + // Call + UITypeEditorEditStyle editStyle = editor.GetEditStyle(null); + + // Assert + Assert.AreEqual(UITypeEditorEditStyle.Modal, editStyle); + } + + [Test] + public void EditValue_WithOtherValue_ReturnSameValue() + { + // Setup + var editor = new ColorEditor(); + var value = new object(); + + // Call + object editedValue = editor.EditValue(null, null, value); + + // Assert + Assert.AreSame(value, editedValue); + } + + [Test] + public void GetPaintValueSupported_Always_ReturnTrue() + { + // Setup + var editor = new ColorEditor(); + + // Call + bool paintValueSupported = editor.GetPaintValueSupported(); + + // Assert + Assert.IsTrue(paintValueSupported); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/UITypeEditors/SelectionEditorTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/UITypeEditors/SelectionEditorTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/UITypeEditors/SelectionEditorTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,140 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.ComponentModel; +using System.Drawing.Design; +using System.Windows.Forms.Design; +using Core.Gui.PropertyBag; +using Core.Gui.UITypeEditors; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test.UITypeEditors +{ + [TestFixture] + public class SelectionEditorTest + { + [Test] + public void GetEditStyle_Always_ReturnDropDown() + { + // Setup + var editor = new SelectionEditor<IObjectProperties, object>(); + + // Call + UITypeEditorEditStyle editStyle = editor.GetEditStyle(); + + // Assert + Assert.AreEqual(UITypeEditorEditStyle.DropDown, editStyle); + } + + [Test] + public void EditValue_NoProviderNoContext_ReturnsOriginalValue() + { + // Setup + var editor = new SelectionEditor<IObjectProperties, object>(); + var someValue = new object(); + + // Call + object result = editor.EditValue(null, null, someValue); + + // Assert + Assert.AreSame(someValue, result); + } + + [Test] + public void EditValue_NoContext_ReturnsOriginalValue() + { + // Setup + var editor = new SelectionEditor<IObjectProperties, object>(); + var mockRepository = new MockRepository(); + var provider = mockRepository.StrictMock<IServiceProvider>(); + var service = mockRepository.StrictMock<IWindowsFormsEditorService>(); + provider.Expect(p => p.GetService(null)).IgnoreArguments().Return(service); + mockRepository.ReplayAll(); + + var someValue = new object(); + + // Call + object result = editor.EditValue(null, provider, someValue); + + // Assert + Assert.AreSame(someValue, result); + + mockRepository.VerifyAll(); + } + + [Test] + public void EditValue_Always_ReturnsOriginalValue() + { + // Setup + var editor = new SelectionEditor<IObjectProperties, object>(); + var mockRepository = new MockRepository(); + var provider = mockRepository.StrictMock<IServiceProvider>(); + var service = mockRepository.StrictMock<IWindowsFormsEditorService>(); + var context = mockRepository.StrictMock<ITypeDescriptorContext>(); + provider.Expect(p => p.GetService(null)).IgnoreArguments().Return(service); + service.Expect(s => s.DropDownControl(null)).IgnoreArguments(); + mockRepository.ReplayAll(); + + var someValue = new object(); + + // Call + object result = editor.EditValue(context, provider, someValue); + + // Assert + Assert.AreSame(someValue, result); + + mockRepository.VerifyAll(); + } + + [Test] + public void EditValue_NullItem_ReturnsNull() + { + var nullItem = new object(); + var editor = new TestSelectionEditor(nullItem); + + var mockRepository = new MockRepository(); + var provider = mockRepository.StrictMock<IServiceProvider>(); + var service = mockRepository.StrictMock<IWindowsFormsEditorService>(); + var context = mockRepository.StrictMock<ITypeDescriptorContext>(); + provider.Expect(p => p.GetService(null)).IgnoreArguments().Return(service); + service.Expect(s => s.DropDownControl(null)).IgnoreArguments(); + service.Expect(s => s.CloseDropDown()); + mockRepository.ReplayAll(); + + // Call + object result = editor.EditValue(context, provider, nullItem); + + // Assert + Assert.IsNull(result); + mockRepository.VerifyAll(); + } + + private class TestSelectionEditor : SelectionEditor<IObjectProperties, object> + { + public TestSelectionEditor(object nullItem) + { + NullItem = nullItem; + } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.Test/ViewPropertyEditorTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.Test/ViewPropertyEditorTest.cs (revision 0) +++ Core/Gui/test/Core.Gui.Test/ViewPropertyEditorTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,84 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Drawing.Design; +using Core.Gui.Commands; +using NUnit.Framework; +using Rhino.Mocks; + +namespace Core.Gui.Test +{ + [TestFixture] + public class ViewPropertyEditorTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var editor = new ViewPropertyEditor(); + + // Assert + Assert.IsInstanceOf<UITypeEditor>(editor); + } + + [Test] + public void GetEditStyle_Always_ReturnModal() + { + // Setup + var editor = new ViewPropertyEditor(); + + // Call + UITypeEditorEditStyle style = editor.GetEditStyle(); + + // Assert + Assert.AreEqual(UITypeEditorEditStyle.Modal, style); + } + + [Test] + public void EditValue_Always_OpenViewForData() + { + // Setup + var editor = new ViewPropertyEditor(); + var data = new object(); + + var mocks = new MockRepository(); + var commands = mocks.StrictMock<IViewCommands>(); + commands.Expect(c => c.OpenView(data)); + mocks.ReplayAll(); + + IViewCommands originalValue = ViewPropertyEditor.ViewCommands; + try + { + ViewPropertyEditor.ViewCommands = commands; + + // Call + editor.EditValue(null, null, data); + + // Assert + mocks.VerifyAll(); // Expect 'OpenView' to be called. + } + finally + { + ViewPropertyEditor.ViewCommands = originalValue; + } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.TestUtil/Clipboard/ClipboardConfig.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.TestUtil/Clipboard/ClipboardConfig.cs (revision 0) +++ Core/Gui/test/Core.Gui.TestUtil/Clipboard/ClipboardConfig.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,95 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Windows.Forms; +using Core.Common.Gui.Clipboard; + +namespace Core.Common.Gui.TestUtil.Clipboard +{ + /// <summary> + /// This class can be used to set a temporary <see cref="IClipboard"/> for <see cref="ClipboardProvider"/> while + /// testing. Disposing an instance of this class will revert the <see cref="ClipboardProvider.Clipboard"/> to its + /// original state. + /// </summary> + /// <example> + /// The following is an example for how to use this class: + /// <code> + /// using(new ClipboardConfig()) + /// { + /// IClipboard clipboard = ClipboardProvider.Clipboard; + /// + /// // Perform tests with clipboard + /// } + /// </code> + /// </example> + public class ClipboardConfig : IDisposable + { + private readonly IClipboard previousClipboard; + + /// <summary> + /// Creates a new instance of <see cref="ClipboardConfig"/>. Sets a test implementation of <see cref="IClipboard"/> to + /// <see cref="ClipboardProvider.Clipboard"/>. + /// </summary> + public ClipboardConfig() + { + previousClipboard = ClipboardProvider.Clipboard; + ClipboardProvider.Clipboard = new TestClipboard(); + } + + /// <summary> + /// Reverts <see cref="ClipboardProvider.Clipboard"/> to its original state. + /// </summary> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + ClipboardProvider.Clipboard = previousClipboard; + } + } + + private class TestClipboard : IClipboard + { + private object clipboardContent; + + public void SetDataObject(object data, bool copy = false) + { + clipboardContent = data; + } + + public IDataObject GetDataObject() + { + return clipboardContent as IDataObject; + } + + public string GetText() + { + return clipboardContent as string; + } + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.TestUtil/ContextMenu/CustomItemsOnlyContextMenuBuilder.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.TestUtil/ContextMenu/CustomItemsOnlyContextMenuBuilder.cs (revision 0) +++ Core/Gui/test/Core.Gui.TestUtil/ContextMenu/CustomItemsOnlyContextMenuBuilder.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,185 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using Core.Common.Gui.ContextMenu; +using Core.Common.Gui.Plugin; + +namespace Core.Common.Gui.TestUtil.ContextMenu +{ + /// <summary> + /// This class can be used for easily testing the custom items which are added to a context menu. + /// </summary> + public class CustomItemsOnlyContextMenuBuilder : IContextMenuBuilder + { + /// <summary> + /// The context menu which is build. + /// </summary> + private readonly ContextMenuStrip contextMenu = new ContextMenuStrip(); + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddRenameItem() + { + return AddStubItem(); + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddDeleteItem() + { + return AddStubItem(); + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddDeleteChildrenItem() + { + return AddStubItem(); + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddExpandAllItem() + { + return AddStubItem(); + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddCollapseAllItem() + { + return AddStubItem(); + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddOpenItem() + { + return AddStubItem(); + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddExportItem() + { + return AddStubItem(); + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <param name="importInfos">An enumeration of <see cref="ImportInfo"/> instances, representing one or more + /// supported import actions.</param> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddImportItem(IEnumerable<ImportInfo> importInfos = null) + { + return AddStubItem(); + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <param name="text">The text of the import item.</param> + /// <param name="toolTip">The tooltip of the import item.</param> + /// <param name="image">The image of the import item.</param> + /// <param name="importInfos">An enumeration of <see cref="ImportInfo"/> instances, representing one or more + /// supported import actions.</param> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddImportItem(string text, string toolTip, Image image, IEnumerable<ImportInfo> importInfos = null) + { + return AddStubItem(); + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddUpdateItem() + { + return AddStubItem(); + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddPropertiesItem() + { + return AddStubItem(); + } + + /// <summary> + /// Adds a toolstrip separator. + /// </summary> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddSeparator() + { + contextMenu.Items.Add(new ToolStripSeparator()); + return this; + } + + /// <summary> + /// Adds a dummy <see cref="ToolStripItem"/> to the <see cref="ContextMenuStrip"/>. + /// </summary> + /// <param name="item">The custom <see cref="StrictContextMenuItem"/> to add to the <see cref="ContextMenuStrip"/>.</param> + /// <returns>The <see cref="CustomItemsOnlyContextMenuBuilder"/>.</returns> + public IContextMenuBuilder AddCustomItem(StrictContextMenuItem item) + { + contextMenu.Items.Add(item); + return this; + } + + /// <summary> + /// Obtain the <see cref="ContextMenuStrip"/>, which has been constructed by using <see cref="AddCustomItem"/>. + /// </summary> + /// <returns>The constructed <see cref="ContextMenuStrip"/>.</returns> + public ContextMenuStrip Build() + { + return contextMenu; + } + + private IContextMenuBuilder AddStubItem() + { + ToolStripItem toolStripItem = new StrictContextMenuItem(string.Empty, string.Empty, null, (sender, args) => {}); + + contextMenu.Items.Add(toolStripItem); + + return this; + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.TestUtil/Core.Common.Gui.TestUtil.csproj =================================================================== diff -u --- Core/Gui/test/Core.Gui.TestUtil/Core.Common.Gui.TestUtil.csproj (revision 0) +++ Core/Gui/test/Core.Gui.TestUtil/Core.Common.Gui.TestUtil.csproj (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,21 @@ +<Project Sdk="Microsoft.NET.Sdk"> + <Import Project="$(SolutionDir)build\TestUtil.targets" /> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Drawing" /> + <Reference Include="System.Windows.Forms" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\src\Core.Common.Gui\Core.Common.Gui.csproj" /> + </ItemGroup> + <ItemGroup> + <None Include="..\..\..\..\build\Copying.Lesser.licenseheader"> + <Link>Copying.Lesser.licenseheader</Link> + </None> + </ItemGroup> + <ItemGroup> + <PackageReference Include="NUnit"> + <Version>3.8.1</Version> + </PackageReference> + </ItemGroup> +</Project> \ No newline at end of file Index: Core/Gui/test/Core.Gui.TestUtil/PluginTestHelper.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.TestUtil/PluginTestHelper.cs (revision 0) +++ Core/Gui/test/Core.Gui.TestUtil/PluginTestHelper.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,99 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using Core.Common.Gui.Plugin; +using NUnit.Framework; + +namespace Core.Common.Gui.TestUtil +{ + /// <summary> + /// Contains routines for testing classes which are related to GUI. + /// </summary> + public static class PluginTestHelper + { + /// <summary> + /// Asserts that the given <paramref name="propertyInfos"/> contains a definition for the combination of + /// <paramref name="dataObjectType"/> and <paramref name="propertyObjectType"/>. + /// </summary> + /// <param name="propertyInfos">The collection of <see cref="PropertyInfo"/> definitions.</param> + /// <param name="dataObjectType">The type of the data object for which property info is defined.</param> + /// <param name="propertyObjectType">The type of the object which shows the data object properties.</param> + /// <returns>The found property info.</returns> + /// <exception cref="AssertionException">Thrown when the <paramref name="propertyInfos"/> is <c>null</c> + /// or does not contain a definition for the combination of <paramref name="dataObjectType"/> and + /// <paramref name="propertyObjectType"/>.</exception> + public static PropertyInfo AssertPropertyInfoDefined(IEnumerable<PropertyInfo> propertyInfos, Type dataObjectType, Type propertyObjectType) + { + Assert.NotNull(propertyInfos, "The given collection of propertyInfos was undefined."); + PropertyInfo propertyInfo = propertyInfos.FirstOrDefault( + tni => tni.DataType == dataObjectType + && tni.PropertyObjectType == propertyObjectType); + Assert.NotNull(propertyInfo, $"The property info object was not found for the given dataType ({dataObjectType}) " + + $"and propertyObjectType ({propertyObjectType})."); + return propertyInfo; + } + + /// <summary> + /// Asserts that a view info is defined in the collection of view infos given. + /// </summary> + /// <param name="viewInfos">The collection of <see cref="ViewInfo"/> to search in.</param> + /// <param name="dataType">The type of the data which is passed to the <see cref="ViewInfo"/>.</param> + /// <param name="viewDataType">The type of the data which is set on the view.</param> + /// <param name="viewType">The type of the view.</param> + /// <returns>The <see cref="ViewInfo"/> that was found within the collection of <see cref="viewInfos"/>.</returns> + /// <exception cref="AssertionException">Thrown when either: + /// <list type="bullet"> + /// <item><paramref name="viewInfos"/> is <c>null</c>;</item> + /// <item>no <see cref="ViewInfo"/> can be found for the combination of <paramref name="viewDataType"/> and <paramref name="viewType"/>;</item> + /// <item>the found <see cref="ViewInfo"/> does not define the expected <paramref name="dataType"/>.</item> + /// </list> + /// </exception> + public static ViewInfo AssertViewInfoDefined(IEnumerable<ViewInfo> viewInfos, Type dataType, Type viewDataType, Type viewType) + { + Assert.NotNull(viewInfos); + ViewInfo viewInfo = viewInfos.SingleOrDefault(vi => vi.ViewDataType == viewDataType && vi.ViewType == viewType); + Assert.NotNull(viewInfo, "Could not find viewInfo for the combination of viewDataType {0} and viewType {1} ", viewDataType, viewType); + Assert.AreEqual(dataType, viewInfo.DataType); + return viewInfo; + } + + /// <summary> + /// Asserts that a view info is defined in the collection of view infos given. + /// </summary> + /// <param name="viewInfos">The collection of <see cref="ViewInfo"/> to search in.</param> + /// <param name="dataType">The type of the data which is passed to the <see cref="ViewInfo"/> and is set on the view.</param> + /// <param name="viewType">The type of the view.</param> + /// <returns>The <see cref="ViewInfo"/> that was found within the collection of <see cref="viewInfos"/>.</returns> + /// <exception cref="AssertionException">Thrown when either: + /// <list type="bullet"> + /// <item><paramref name="viewInfos"/> is <c>null</c>;</item> + /// <item>no <see cref="ViewInfo"/> can be found for the combination of <paramref name="dataType"/> and <paramref name="viewType"/>.</item> + /// </list> + /// </exception> + public static ViewInfo AssertViewInfoDefined(IEnumerable<ViewInfo> viewInfos, Type dataType, Type viewType) + { + return AssertViewInfoDefined(viewInfos, dataType, dataType, viewType); + } + } +} \ No newline at end of file Index: Core/Gui/test/Core.Gui.TestUtil/Properties/AssemblyInfo.cs =================================================================== diff -u --- Core/Gui/test/Core.Gui.TestUtil/Properties/AssemblyInfo.cs (revision 0) +++ Core/Gui/test/Core.Gui.TestUtil/Properties/AssemblyInfo.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,25 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Reflection; + +[assembly: AssemblyTitle("Core.Common.Gui.TestUtil")] +[assembly: AssemblyProduct("Core.Common.Gui.TestUtil")] \ No newline at end of file Index: Core/Gui/test/Core.Integration.Test/Core.Common.Integration.Test.csproj =================================================================== diff -u --- Core/Gui/test/Core.Integration.Test/Core.Common.Integration.Test.csproj (revision 0) +++ Core/Gui/test/Core.Integration.Test/Core.Common.Integration.Test.csproj (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,34 @@ +<Project Sdk="Microsoft.NET.Sdk"> + <Import Project="$(SolutionDir)build\Test.targets" /> + <ItemGroup> + <Reference Include="PresentationCore" /> + <Reference Include="PresentationFramework" /> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Windows.Forms" /> + <Reference Include="System.Xaml" /> + <Reference Include="WindowsBase" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\..\Riskeer\Integration\src\Riskeer.Integration.Plugin\Riskeer.Integration.Plugin.csproj" /> + <ProjectReference Include="..\..\src\Core.Common.Base\Core.Common.Base.csproj" /> + <ProjectReference Include="..\..\src\Core.Common.Gui\Core.Common.Gui.csproj" /> + <ProjectReference Include="..\Core.Common.TestUtil\Core.Common.TestUtil.csproj" /> + </ItemGroup> + <ItemGroup> + <None Include="..\..\..\..\build\Copying.Lesser.licenseheader"> + <Link>Copying.Lesser.licenseheader</Link> + </None> + </ItemGroup> + <ItemGroup> + <PackageReference Include="MahApps.Metro"> + <Version>2.4.4</Version> + </PackageReference> + <PackageReference Include="NUnit"> + <Version>3.8.1</Version> + </PackageReference> + <PackageReference Include="RhinoMocks"> + <Version>3.6.1</Version> + </PackageReference> + </ItemGroup> +</Project> \ No newline at end of file Index: Core/Gui/test/Core.Integration.Test/Properties/AssemblyInfo.cs =================================================================== diff -u --- Core/Gui/test/Core.Integration.Test/Properties/AssemblyInfo.cs (revision 0) +++ Core/Gui/test/Core.Integration.Test/Properties/AssemblyInfo.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,25 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Reflection; + +[assembly: AssemblyTitle("Core.Common.Integration.Test")] +[assembly: AssemblyProduct("Core.Common.Integration.Test")] \ No newline at end of file Index: Core/Gui/test/Core.Integration.Test/Riskeer/Application.Riskeer/GuiCoreIntegrationTest.cs =================================================================== diff -u --- Core/Gui/test/Core.Integration.Test/Riskeer/Application.Riskeer/GuiCoreIntegrationTest.cs (revision 0) +++ Core/Gui/test/Core.Integration.Test/Riskeer/Application.Riskeer/GuiCoreIntegrationTest.cs (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -0,0 +1,109 @@ +// Copyright (C) Stichting Deltares 2021. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.Threading; +using System.Windows.Controls; +using System.Windows.Threading; +using Core.Common.Base.Data; +using Core.Common.Base.Storage; +using Core.Common.Gui; +using Core.Common.Gui.Forms.MainWindow; +using Core.Common.Gui.Settings; +using Core.Common.TestUtil; +using NUnit.Framework; +using Rhino.Mocks; +using Riskeer.Integration.Data; +using Riskeer.Integration.Plugin; + +namespace Core.Common.Integration.Test.Riskeer.Application.Riskeer +{ + [TestFixture] + public class GuiCoreIntegrationTest + { + [SetUp] + public void SetUp() + { + LogHelper.ResetLogging(); + } + + [TearDown] + public void TearDown() + { + Dispatcher.CurrentDispatcher.InvokeShutdown(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void Run_StartWithCommonPlugins_RunsFasterThanThreshold() + { + // Setup + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + var projectFactory = mocks.Stub<IProjectFactory>(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(new RiskeerProject()); + mocks.ReplayAll(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new RiskeerPlugin()); + + // Call + void Action() + { + gui.Run(); + WpfTestHelper.ShowModal((Control) gui.MainWindow); + } + + // Assert + TestHelper.AssertIsFasterThan(7500, Action); + } + + mocks.VerifyAll(); + } + + [Test] + [Apartment(ApartmentState.STA)] + public void FormActionIsRunForMainWindow() + { + //testing testhelper + visible changed event of mainwindow. + //could be tested separately but the combination is vital to many tests. That's why this test is here. + var mocks = new MockRepository(); + var projectStore = mocks.Stub<IStoreProject>(); + var projectMigrator = mocks.Stub<IMigrateProject>(); + var projectFactory = mocks.Stub<IProjectFactory>(); + projectFactory.Stub(pf => pf.CreateNewProject()).Return(mocks.Stub<IProject>()); + mocks.ReplayAll(); + + using (var gui = new GuiCore(new MainWindow(), projectStore, projectMigrator, projectFactory, new GuiCoreSettings())) + { + gui.Plugins.Add(new TestPlugin()); + gui.Run(); + + var callCount = 0; + WpfTestHelper.ShowModal((Control) gui.MainWindow, () => callCount++); + Assert.AreEqual(1, callCount); + } + + mocks.VerifyAll(); + } + } +} \ No newline at end of file Index: Riskeer.sln =================================================================== diff -u -r434415295de74c310ce6d3cdd0100c28838cf9ea -r781a97409ffc49e5b666a7856f633f46178056df --- Riskeer.sln (.../Riskeer.sln) (revision 434415295de74c310ce6d3cdd0100c28838cf9ea) +++ Riskeer.sln (.../Riskeer.sln) (revision 781a97409ffc49e5b666a7856f633f46178056df) @@ -243,11 +243,6 @@ {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Common.Integration.Test", "Core\Common\test\Core.Common.Integration.Test\Core.Common.Integration.Test.csproj", "{A6A434E0-AE5A-4D5B-97D7-532B00FBDFE9}" - ProjectSection(ProjectDependencies) = postProject - {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} - EndProjectSection -EndProject Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Application.Riskeer.Setup", "Application\Riskeer\src\Application.Riskeer.Setup\Application.Riskeer.Setup.wixproj", "{3CCB05DB-C7B3-4EF7-B41D-22B6D2A3774E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Common.Base.Test", "Core\Common\test\Core.Common.Base.Test\Core.Common.Base.Test.csproj", "{FAFDB463-9612-41F4-B3DD-FF9C6E7023BA}" @@ -260,11 +255,6 @@ {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Common.Gui.Test", "Core\Common\test\Core.Common.Gui.Test\Core.Common.Gui.Test.csproj", "{D5EC1DF2-03C9-467B-B6AF-BE5AC83417F8}" - ProjectSection(ProjectDependencies) = postProject - {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Integration", "Integration", "{11FE8C37-49EB-4FF2-8583-DABC9816FFC8}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{14E296C8-B6B9-458A-A402-68E8A0F9B97C}" @@ -316,11 +306,6 @@ {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Common.Gui.TestUtil", "Core\Common\test\Core.Common.Gui.TestUtil\Core.Common.Gui.TestUtil.csproj", "{26214BD0-DAFB-4CFC-8EB2-80C5D53C859E}" - ProjectSection(ProjectDependencies) = postProject - {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Common.Controls.Test", "Core\Common\test\Core.Common.Controls.Test\Core.Common.Controls.Test.csproj", "{A8CE1456-1880-4FC8-84B3-D618EA88F384}" ProjectSection(ProjectDependencies) = postProject {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} @@ -1770,9 +1755,14 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Gui", "Core\Gui\src\Core.Gui\Core.Gui.csproj", "{FE63A65E-C5AF-456D-A786-912F9B7E26A1}" ProjectSection(ProjectDependencies) = postProject - {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} - EndProjectSection + {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} + EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Gui.Test", "Core\Gui\test\Core.Gui.Test\Core.Gui.Test.csproj", "{D0C7032E-5730-46D1-A06F-7C4F06BA590A}" + ProjectSection(ProjectDependencies) = postProject + {C90B77DA-E421-43CC-B82E-529651BC21AC} = {C90B77DA-E421-43CC-B82E-529651BC21AC} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 @@ -1918,12 +1908,6 @@ {D783543B-46A1-4848-A812-AF5A5259ED7E}.Release|x86.Build.0 = Release|x86 {D783543B-46A1-4848-A812-AF5A5259ED7E}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 {D783543B-46A1-4848-A812-AF5A5259ED7E}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 - {A6A434E0-AE5A-4D5B-97D7-532B00FBDFE9}.Debug|x86.ActiveCfg = Debug|x86 - {A6A434E0-AE5A-4D5B-97D7-532B00FBDFE9}.Debug|x86.Build.0 = Debug|x86 - {A6A434E0-AE5A-4D5B-97D7-532B00FBDFE9}.Release|x86.ActiveCfg = Release|x86 - {A6A434E0-AE5A-4D5B-97D7-532B00FBDFE9}.Release|x86.Build.0 = Release|x86 - {A6A434E0-AE5A-4D5B-97D7-532B00FBDFE9}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 - {A6A434E0-AE5A-4D5B-97D7-532B00FBDFE9}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 {3CCB05DB-C7B3-4EF7-B41D-22B6D2A3774E}.Debug|x86.ActiveCfg = Debug|x86 {3CCB05DB-C7B3-4EF7-B41D-22B6D2A3774E}.Release|x86.ActiveCfg = Release|x86 {3CCB05DB-C7B3-4EF7-B41D-22B6D2A3774E}.ReleaseForCodeCoverage|x86.ActiveCfg = Release|x86 @@ -1939,12 +1923,6 @@ {813FFA92-1F3F-462B-B596-5919334007A9}.Release|x86.Build.0 = Release|x86 {813FFA92-1F3F-462B-B596-5919334007A9}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 {813FFA92-1F3F-462B-B596-5919334007A9}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 - {D5EC1DF2-03C9-467B-B6AF-BE5AC83417F8}.Debug|x86.ActiveCfg = Debug|x86 - {D5EC1DF2-03C9-467B-B6AF-BE5AC83417F8}.Debug|x86.Build.0 = Debug|x86 - {D5EC1DF2-03C9-467B-B6AF-BE5AC83417F8}.Release|x86.ActiveCfg = Release|x86 - {D5EC1DF2-03C9-467B-B6AF-BE5AC83417F8}.Release|x86.Build.0 = Release|x86 - {D5EC1DF2-03C9-467B-B6AF-BE5AC83417F8}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 - {D5EC1DF2-03C9-467B-B6AF-BE5AC83417F8}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 {11F1F874-45AF-43E4-8AE5-15A5C9593E28}.Debug|x86.ActiveCfg = Debug|x86 {11F1F874-45AF-43E4-8AE5-15A5C9593E28}.Debug|x86.Build.0 = Debug|x86 {11F1F874-45AF-43E4-8AE5-15A5C9593E28}.Release|x86.ActiveCfg = Release|x86 @@ -1999,12 +1977,6 @@ {D4200F43-3F72-4F42-AF0A-8CED416A38EC}.Release|x86.Build.0 = Release|x86 {D4200F43-3F72-4F42-AF0A-8CED416A38EC}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 {D4200F43-3F72-4F42-AF0A-8CED416A38EC}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 - {26214BD0-DAFB-4CFC-8EB2-80C5D53C859E}.Debug|x86.ActiveCfg = Debug|x86 - {26214BD0-DAFB-4CFC-8EB2-80C5D53C859E}.Debug|x86.Build.0 = Debug|x86 - {26214BD0-DAFB-4CFC-8EB2-80C5D53C859E}.Release|x86.ActiveCfg = Release|x86 - {26214BD0-DAFB-4CFC-8EB2-80C5D53C859E}.Release|x86.Build.0 = Release|x86 - {26214BD0-DAFB-4CFC-8EB2-80C5D53C859E}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 - {26214BD0-DAFB-4CFC-8EB2-80C5D53C859E}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 {A8CE1456-1880-4FC8-84B3-D618EA88F384}.Debug|x86.ActiveCfg = Debug|x86 {A8CE1456-1880-4FC8-84B3-D618EA88F384}.Debug|x86.Build.0 = Debug|x86 {A8CE1456-1880-4FC8-84B3-D618EA88F384}.Release|x86.ActiveCfg = Release|x86 @@ -3601,6 +3573,12 @@ {FE63A65E-C5AF-456D-A786-912F9B7E26A1}.Release|x86.Build.0 = Release|x86 {FE63A65E-C5AF-456D-A786-912F9B7E26A1}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 {FE63A65E-C5AF-456D-A786-912F9B7E26A1}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 + {D0C7032E-5730-46D1-A06F-7C4F06BA590A}.Debug|x86.ActiveCfg = Debug|x86 + {D0C7032E-5730-46D1-A06F-7C4F06BA590A}.Debug|x86.Build.0 = Debug|x86 + {D0C7032E-5730-46D1-A06F-7C4F06BA590A}.Release|x86.ActiveCfg = Release|x86 + {D0C7032E-5730-46D1-A06F-7C4F06BA590A}.Release|x86.Build.0 = Release|x86 + {D0C7032E-5730-46D1-A06F-7C4F06BA590A}.ReleaseForCodeCoverage|x86.ActiveCfg = ReleaseForCodeCoverage|x86 + {D0C7032E-5730-46D1-A06F-7C4F06BA590A}.ReleaseForCodeCoverage|x86.Build.0 = ReleaseForCodeCoverage|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -3641,11 +3619,9 @@ {E4B0E068-F1A3-47BA-965F-0EC1E78E530A} = {1F0D20C2-7F04-431D-AF22-95A31FD53733} {9A5C8069-520E-49D3-AA62-E8FB19614A27} = {1F0D20C2-7F04-431D-AF22-95A31FD53733} {D783543B-46A1-4848-A812-AF5A5259ED7E} = {1F0D20C2-7F04-431D-AF22-95A31FD53733} - {A6A434E0-AE5A-4D5B-97D7-532B00FBDFE9} = {0D9858E1-CF2D-4DE5-AC0E-64401900D531} {3CCB05DB-C7B3-4EF7-B41D-22B6D2A3774E} = {39EB5D07-C076-484C-9621-B34C4E5BF64C} {FAFDB463-9612-41F4-B3DD-FF9C6E7023BA} = {0D9858E1-CF2D-4DE5-AC0E-64401900D531} {813FFA92-1F3F-462B-B596-5919334007A9} = {1F0D20C2-7F04-431D-AF22-95A31FD53733} - {D5EC1DF2-03C9-467B-B6AF-BE5AC83417F8} = {0D9858E1-CF2D-4DE5-AC0E-64401900D531} {11FE8C37-49EB-4FF2-8583-DABC9816FFC8} = {05D133D6-D7D8-4872-9B53-2753DD3F8BF9} {14E296C8-B6B9-458A-A402-68E8A0F9B97C} = {11FE8C37-49EB-4FF2-8583-DABC9816FFC8} {88E04195-C43E-40D3-B5F2-3A25E1E79E03} = {11FE8C37-49EB-4FF2-8583-DABC9816FFC8} @@ -3658,7 +3634,6 @@ {96C8FDAE-9F59-4D2F-A66E-BE512BB5EECB} = {88E04195-C43E-40D3-B5F2-3A25E1E79E03} {886FDBE5-7065-4AB9-A894-869DBFD4E440} = {B5F4F5A5-FD36-405D-ABA1-56C270207C8F} {D4200F43-3F72-4F42-AF0A-8CED416A38EC} = {0590D3BB-EB3E-4B53-BD64-1725E1CBB1F4} - {26214BD0-DAFB-4CFC-8EB2-80C5D53C859E} = {0D9858E1-CF2D-4DE5-AC0E-64401900D531} {A8CE1456-1880-4FC8-84B3-D618EA88F384} = {0D9858E1-CF2D-4DE5-AC0E-64401900D531} {7BABA02F-4809-43D2-93E5-DA9ED69BDDE2} = {B5F4F5A5-FD36-405D-ABA1-56C270207C8F} {1D27F91F-4E62-4EAF-A0A8-A32708B9A9B1} = {8261CCE1-98D7-465B-BC94-4ED239DE7F2E} @@ -3985,6 +3960,7 @@ {8BE49C65-DD09-4890-82B1-5216BF13E757} = {94E919CC-F375-485D-A849-3CE3FCC9B2C3} {F73AF5D7-DDD9-4A48-A171-037817B59056} = {94E919CC-F375-485D-A849-3CE3FCC9B2C3} {FE63A65E-C5AF-456D-A786-912F9B7E26A1} = {8BE49C65-DD09-4890-82B1-5216BF13E757} + {D0C7032E-5730-46D1-A06F-7C4F06BA590A} = {F73AF5D7-DDD9-4A48-A171-037817B59056} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {039D31AA-B517-4354-B8CD-0B2B826D0B1F}