From 1446bc622f54b11994f3aa972cfe1c51181733f4 Mon Sep 17 00:00:00 2001 From: James Friel Date: Wed, 13 Dec 2023 12:07:59 +0000 Subject: [PATCH] Merge Latest Release into main (#1702) * Bump YamlDotNet from 13.3.1 to 13.4.0 Bumps [YamlDotNet](https://github.com/aaubry/YamlDotNet) from 13.3.1 to 13.4.0. - [Release notes](https://github.com/aaubry/YamlDotNet/releases) - [Commits](https://github.com/aaubry/YamlDotNet/compare/v13.3.1...v13.4.0) --- updated-dependencies: - dependency-name: YamlDotNet dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump shogo82148/actions-setup-perl from 1.23.1 to 1.24.1 Bumps [shogo82148/actions-setup-perl](https://github.com/shogo82148/actions-setup-perl) from 1.23.1 to 1.24.1. - [Release notes](https://github.com/shogo82148/actions-setup-perl/releases) - [Commits](https://github.com/shogo82148/actions-setup-perl/compare/v1.23.1...v1.24.1) --- updated-dependencies: - dependency-name: shogo82148/actions-setup-perl dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * fix checkbox issue * improve confirmation text (#1639) * improve confirmation text * Loop tidyup, use var where possible --------- Co-authored-by: jas88 * correct typo in create logging sql (#1640) * Feature/ci codescan (#1641) * Move SecurityCodescan.VS2019 to run on Github CI alone, integrate results with CodeQL * Remove SecurityCodescan from Packages.md, no longer used via Nuget --------- Co-authored-by: James A Sutherland * hide source control when not available * Remove old Plugin object bits, tidy up (#1636) * Remove old Plugin object bits, tidy up * Purge remaining bits of AllExpiredPluginsNode * Fix plugin display name in tree * Update CreateNewDataExtractionProjectUI.cs Casting fix * Feature/rdmp42 delete plugins (#1642) * add ui plugin delete functionality * Warning and inheritance redundancy cleanups * Narrow scope of catch clause per CodeQL warning * Tidy Plugin name retrieval --------- Co-authored-by: James A Sutherland <> Co-authored-by: James Friel * Bump MongoDB.Driver from 2.21.0 to 2.22.0 Bumps [MongoDB.Driver](https://github.com/mongodb/mongo-csharp-driver) from 2.21.0 to 2.22.0. - [Release notes](https://github.com/mongodb/mongo-csharp-driver/releases) - [Commits](https://github.com/mongodb/mongo-csharp-driver/compare/v2.21.0...v2.22.0) --- updated-dependencies: - dependency-name: MongoDB.Driver dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump YamlDotNet from 13.4.0 to 13.5.2 (#1644) Bumps [YamlDotNet](https://github.com/aaubry/YamlDotNet) from 13.4.0 to 13.5.2. - [Release notes](https://github.com/aaubry/YamlDotNet/releases) - [Commits](https://github.com/aaubry/YamlDotNet/compare/v13.4.0...v13.5.2) --- updated-dependencies: - dependency-name: YamlDotNet dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump YamlDotNet from 13.5.2 to 13.7.0 (#1647) * Bump SSH.NET from 2020.0.2 to 2023.0.0 (#1646) * Bump YamlDotNet from 13.7.0 to 13.7.1 Bumps [YamlDotNet](https://github.com/aaubry/YamlDotNet) from 13.7.0 to 13.7.1. - [Release notes](https://github.com/aaubry/YamlDotNet/releases) - [Commits](https://github.com/aaubry/YamlDotNet/compare/v13.7.0...v13.7.1) --- updated-dependencies: - dependency-name: YamlDotNet dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump NLog from 5.2.4 to 5.2.5 Bumps [NLog](https://github.com/NLog/NLog) from 5.2.4 to 5.2.5. - [Release notes](https://github.com/NLog/NLog/releases) - [Changelog](https://github.com/NLog/NLog/blob/dev/CHANGELOG.md) - [Commits](https://github.com/NLog/NLog/compare/v5.2.4...v5.2.5) --- updated-dependencies: - dependency-name: NLog dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * New FTP/FTPS support, improve SFTP (#1649) Co-authored-by: James Friel * Cut Windows exe file counts (#1650) * Cut Windows exe file counts * Remove manual deletion of files dotnet publish used to create * Fix up docs links * More doc link fixups * Fix FAnsiSql Implementations README links * Make GUI and CLI Windows exes single-file, update MSI accordingly * Build source zip early on for inclusion later --------- Co-authored-by: James Friel Co-authored-by: James A Sutherland <> * Bump actions/setup-node from 3.8.1 to 4.0.0 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3.8.1 to 4.0.0. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3.8.1...v4.0.0) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Task/rdmp-32 Fix Progress Log writing using excessive resources (#1657) * add load * readd sorting * revert sorting * tidy up code * Task/rdmp 32 Name DataTable Chunks (#1658) * add chunk naming * bump to 8.1.1-r1 * Add heading for WIP 8.1.1 release --------- Co-authored-by: James A Sutherland * RDMP-15 Use .bak files as Data Loads (#1656) * basic ui triggers * working dl --------- Co-authored-by: James A Sutherland * Bump FluentFTP from 48.0.1 to 48.0.3 Bumps [FluentFTP](https://github.com/robinrodricks/FluentFTP) from 48.0.1 to 48.0.3. - [Release notes](https://github.com/robinrodricks/FluentFTP/releases) - [Changelog](https://github.com/robinrodricks/FluentFTP/blob/master/RELEASES.md) - [Commits](https://github.com/robinrodricks/FluentFTP/commits) --- updated-dependencies: - dependency-name: FluentFTP dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Feature/cleanup (#1659) * Use var * Whitespace fixes * Remove stray parentheses * Update SingletonNode.cs Fix confused syntax, use Equ for simplicity * Typos Fix typos, also make some verbatim strings raw strings for better formatting. * Spelling/grammar, wrongly marked partial classes * Update SingletonNode.cs Fix up equality test to be strict about types * Fix typos and tidy tooltip cache logic * Bump shogo82148/actions-setup-perl from 1.24.1 to 1.24.2 --- updated-dependencies: - dependency-name: shogo82148/actions-setup-perl dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump SixLabors.ImageSharp.Drawing from 2.0.0 to 2.0.1 Bumps [SixLabors.ImageSharp.Drawing](https://github.com/SixLabors/ImageSharp.Drawing) from 2.0.0 to 2.0.1. - [Release notes](https://github.com/SixLabors/ImageSharp.Drawing/releases) - [Commits](https://github.com/SixLabors/ImageSharp.Drawing/compare/v2.0.0...v2.0.1) --- updated-dependencies: - dependency-name: SixLabors.ImageSharp.Drawing dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump Terminal.Gui from 1.14.0 to 1.14.1 (#1662) Bumps [Terminal.Gui](https://github.com/gui-cs/Terminal.Gui) from 1.14.0 to 1.14.1. - [Release notes](https://github.com/gui-cs/Terminal.Gui/releases) - [Commits](https://github.com/gui-cs/Terminal.Gui/compare/v1.14.0...v1.14.1) --- updated-dependencies: - dependency-name: Terminal.Gui dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Restore buggy Equals behaviour on SingletonNode since some UI code relied on the bug * Bump NUnit from 3.13.3 to 3.14.0 Bumps [NUnit](https://github.com/nunit/nunit) from 3.13.3 to 3.14.0. - [Release notes](https://github.com/nunit/nunit/releases) - [Changelog](https://github.com/nunit/nunit/blob/master/CHANGES.md) - [Commits](https://github.com/nunit/nunit/compare/v3.13.3...v3.14.0) --- updated-dependencies: - dependency-name: NUnit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Fix Extraction Refresh Issue (#1671) * fix extraction refresh issue * reload, but not hot * Bump Microsoft.NET.Test.Sdk from 17.7.2 to 17.8.0 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.7.2 to 17.8.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md) - [Commits](https://github.com/microsoft/vstest/compare/v17.7.2...v17.8.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Feature/rdmp 73 cohort holdouts (#1653) * add top to cohort * working holdout flow * interim * basic ui flow * now filtering * working flow * working auto-holdout * fix test * add query * improved holdout * tidy up code * add description * revert test db * add holdout description * add todo * fixups from codeql * Minor syntax fix * Fix possible null deref * fix todo url * Tidy, typo fix * Remove disused field --------- Co-authored-by: James A Sutherland Co-authored-by: James A Sutherland <> * RDMP-108 Unified UI Alerting from Processing Chunks (#1663) * batched ui * tidy up * attempt to fix codeql * fix linting * add if check * fix test * add pragma * fix up test * update from codeql * Update DataFlowPipelineEngine.cs Tidy thread logic, fix double-disposal of objects * Put chunk disposal in a finally block to avoid leaks --------- Co-authored-by: James A Sutherland Co-authored-by: James A Sutherland <> * Bump NLog from 5.2.5 to 5.2.6 (#1679) Bumps [NLog](https://github.com/NLog/NLog) from 5.2.5 to 5.2.6. - [Release notes](https://github.com/NLog/NLog/releases) - [Changelog](https://github.com/NLog/NLog/blob/dev/CHANGELOG.md) - [Commits](https://github.com/NLog/NLog/compare/v5.2.5...v5.2.6) --- updated-dependencies: - dependency-name: NLog dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump Microsoft.SourceLink.GitHub from 1.1.1 to 8.0.0 Bumps [Microsoft.SourceLink.GitHub](https://github.com/dotnet/sourcelink) from 1.1.1 to 8.0.0. - [Release notes](https://github.com/dotnet/sourcelink/releases) - [Commits](https://github.com/dotnet/sourcelink/commits) --- updated-dependencies: - dependency-name: Microsoft.SourceLink.GitHub dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Bump Microsoft.XmlSerializer.Generator from 7.0.0 to 8.0.0 Bumps [Microsoft.XmlSerializer.Generator](https://github.com/dotnet/runtime) from 7.0.0 to 8.0.0. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v7.0.0...v8.0.0) --- updated-dependencies: - dependency-name: Microsoft.XmlSerializer.Generator dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * fix bump * Fix coverage reporting (#1683) * Rearrange lcov file handling * Update coveralls action * Point Github-Actions Dependabot updates at develop branch, add JFriel as reviewer * Bump Spectre.Console from 0.47.0 to 0.48.0 Bumps [Spectre.Console](https://github.com/spectreconsole/spectre.console) from 0.47.0 to 0.48.0. - [Release notes](https://github.com/spectreconsole/spectre.console/releases) - [Commits](https://github.com/spectreconsole/spectre.console/compare/0.47.0...0.48.0) --- updated-dependencies: - dependency-name: Spectre.Console dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump WeCantSpell.Hunspell from 4.0.0 to 4.1.0 Bumps [WeCantSpell.Hunspell](https://github.com/aarondandy/WeCantSpell.Hunspell) from 4.0.0 to 4.1.0. - [Release notes](https://github.com/aarondandy/WeCantSpell.Hunspell/releases) - [Changelog](https://github.com/aarondandy/WeCantSpell.Hunspell/blob/main/changelog.md) - [Commits](https://github.com/aarondandy/WeCantSpell.Hunspell/compare/4.0.0...4.1.0) --- updated-dependencies: - dependency-name: WeCantSpell.Hunspell dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Task/update plugin bundling (#1678) * attempt to wget dicom plugin * improved looping for plugins * update script * add to bundle * update build * add charts * update changelog * remove bad files * improve build * add verbose curl * temp diable tests * attempt to simplify build * readd tests --------- Co-authored-by: James A Sutherland * Bump shogo82148/actions-setup-perl from 1.24.2 to 1.24.3 Bumps [shogo82148/actions-setup-perl](https://github.com/shogo82148/actions-setup-perl) from 1.24.2 to 1.24.3. - [Release notes](https://github.com/shogo82148/actions-setup-perl/releases) - [Commits](https://github.com/shogo82148/actions-setup-perl/compare/v1.24.2...v1.24.3) --- updated-dependencies: - dependency-name: shogo82148/actions-setup-perl dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * bump version * attemt sign * remove coveralls * update sign * add ls * correct file name * more ls * correct linux file extention * comment out linux * fix typo * update signing * update changelog * add ls * remove extra sign * add test back in * Bump NLog from 5.2.6 to 5.2.7 Bumps [NLog](https://github.com/NLog/NLog) from 5.2.6 to 5.2.7. - [Release notes](https://github.com/NLog/NLog/releases) - [Changelog](https://github.com/NLog/NLog/blob/dev/CHANGELOG.md) - [Commits](https://github.com/NLog/NLog/commits) --- updated-dependencies: - dependency-name: NLog dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump System.Security.Permissions from 7.0.0 to 8.0.0 (#1676) * Bump System.Threading.AccessControl from 7.0.1 to 8.0.0 (#1675) * Bump NUnit from 3.14.0 to 4.0.0 (#1686) * Bump actions/setup-dotnet from 3.2.0 to 4.0.0 (#1694) * Feature/rdmp-113 datasets (#1682) * Dataset PR * Bump shogo82148/actions-setup-perl from 1.24.3 to 1.25.0 (#1692) Bump shogo82148/actions-setup-perl from 1.24.3 to 1.25.0 (#1692) * Bump SixLabors.ImageSharp from 3.0.2 to 3.1.0 (#1693) * Bump NUnit from 4.0.0 to 4.0.1 Bumps [NUnit](https://github.com/nunit/nunit) from 4.0.0 to 4.0.1. - [Release notes](https://github.com/nunit/nunit/releases) - [Changelog](https://github.com/nunit/nunit/blob/master/CHANGES.md) - [Commits](https://github.com/nunit/nunit/compare/v4.0.0...v4.0.1) --- updated-dependencies: - dependency-name: NUnit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump SixLabors.ImageSharp.Drawing from 2.0.1 to 2.1.0 Bumps [SixLabors.ImageSharp.Drawing](https://github.com/SixLabors/ImageSharp.Drawing) from 2.0.1 to 2.1.0. - [Release notes](https://github.com/SixLabors/ImageSharp.Drawing/releases) - [Commits](https://github.com/SixLabors/ImageSharp.Drawing/compare/v2.0.1...v2.1.0) --- updated-dependencies: - dependency-name: SixLabors.ImageSharp.Drawing dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Implement first pass at platform export tool (#1672) * Implement first pass at platform export tool * Remove dead code, add progress report * Syntax fix * Note command addition in CHANGELOG * ignore certain dqe types --------- Co-authored-by: James A Sutherland <> Co-authored-by: James Friel * update rdmp client xml * Bump SixLabors.ImageSharp from 3.1.0 to 3.1.1 Bumps [SixLabors.ImageSharp](https://github.com/SixLabors/ImageSharp) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/SixLabors/ImageSharp/releases) - [Commits](https://github.com/SixLabors/ImageSharp/compare/v3.1.0...v3.1.1) --- updated-dependencies: - dependency-name: SixLabors.ImageSharp dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Bump MongoDB.Driver from 2.22.0 to 2.23.0 Bumps [MongoDB.Driver](https://github.com/mongodb/mongo-csharp-driver) from 2.22.0 to 2.23.0. - [Release notes](https://github.com/mongodb/mongo-csharp-driver/releases) - [Commits](https://github.com/mongodb/mongo-csharp-driver/compare/v2.22.0...v2.23.0) --- updated-dependencies: - dependency-name: MongoDB.Driver dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: jas88 Co-authored-by: James A Sutherland Co-authored-by: James A Sutherland Co-authored-by: Brian <76164974+bpeacock001@users.noreply.github.com> --- .github/workflows/build.yml | 72 +- .github/workflows/codeql.yml | 14 + .github/workflows/docker.yml | 2 +- .../NLog.template.config | 23 - .../ResearchDataManagementPlatform/Program.cs | 2 - .../ResearchDataManagementPlatform.csproj | 11 - .../WindowManagement/ActivateItems.cs | 24 + .../WindowManagement/CollectionNavigation.cs | 1 - .../TopBar/RDMPTaskBarUI.Designer.cs | 320 ++- .../WindowManagement/TopBar/RDMPTaskBarUI.cs | 14 +- .../TopBar/RDMPTaskBarUI.resx | 155 +- .../WindowManagement/WindowManager.cs | 6 + CHANGELOG.md | 13 +- Documentation/CodeTutorials/Coding.md | 2 +- Documentation/CodeTutorials/FAQ.md | 14 +- Documentation/CodeTutorials/Graphs.md | 4 +- Documentation/CodeTutorials/Packages.md | 13 +- Documentation/CodeTutorials/UserManual.md | 4 +- NoteForNewDevelopers.md | 8 +- .../Caching/Integration/CachingHostTests.cs | 6 +- .../Integration/CustomDateCachingTests.cs | 20 +- .../Caching/Unit/PipelineExecutionTests.cs | 1 - Rdmp.Core.Tests/Caching/Unit/ZipTests.cs | 8 +- .../CohortCommitting/CommitCohortExample.cs | 30 +- .../CreateNewCohortDatabaseWizardTests.cs | 83 +- .../AggregateFilterPublishingTests.cs | 65 +- .../CohortCompilerRunnerTests.cs | 28 +- .../CohortCreation/CohortCompilerTests.cs | 33 +- .../CohortContainerAndCloningTests.cs | 94 +- ...tIdentificationConfigurationMergerTests.cs | 120 +- .../CohortIdentificationTests.cs | 2 +- .../CohortMandatoryFilterImportingTests.cs | 66 +- .../PluginCohortCompilerTests.cs | 36 +- .../CohortCompilerCacheJoinableTest.cs | 45 +- .../QueryTests/CohortQueryBuilderTests.cs | 126 +- ...lderTestsInvolvingTableValuedParameters.cs | 20 +- .../CohortQueryBuilderWithCacheTests.cs | 14 +- .../CohortSummaryQueryBuilderTests.cs | 36 +- .../JoinableCohortConfigurationTests.cs | 67 +- .../SimpleCohortIdentificationTests.cs | 32 +- .../CommandExecution/AxisAndPivotCLITests.cs | 26 +- .../CommandExecution/CommandCliTests.cs | 14 +- .../CommandExecution/CommandInvokerTests.cs | 9 +- ...xecuteCommandAddNewFilterContainerTests.cs | 29 +- ...ExecuteCommandAddPipelineComponentTests.cs | 56 +- ...ecuteCommandAlterTableMakeDistinctTests.cs | 8 +- .../ExecuteCommandConfirmLogsTests.cs | 14 +- .../ExecuteCommandCreateDatasetTests.cs | 33 + ...eCommandCreateNewDataLoadDirectoryTests.cs | 11 +- .../ExecuteCommandCreateNewFilterCliTests.cs | 27 +- .../ExecuteCommandDeleteDatasetTest.cs | 32 + .../ExecuteCommandDeleteTestsCli.cs | 44 +- .../ExecuteCommandDeprecateTests.cs | 4 +- ...ecuteCommandLinkCatalogueToDatasetTests.cs | 119 ++ ...teCommandLinkCoulmnInfoWithDatasetTests.cs | 113 ++ .../ExecuteCommandListTests.cs | 4 +- ...ExecuteCommandRefreshBrokenCohortsTests.cs | 22 +- .../ExecuteCommandReplacedByTests.cs | 39 +- .../ExecuteCommandSetArgumentTests.cs | 52 +- .../ExecuteCommandSetExtendedPropertyTests.cs | 43 +- ...cuteCommandSetExtractionIdentifierTests.cs | 43 +- .../ExecuteCommandSimilarTests.cs | 8 +- .../TestCommandsAreSupported.cs | 2 +- ...mmandAssociateCatalogueWithLoadMetadata.cs | 14 +- .../TestExecuteCommandClearUserSettings.cs | 7 +- .../TestExecuteCommandDescribe.cs | 2 +- .../TestExecuteCommandDescribeCommand.cs | 4 +- ...ExecuteCommandImportFilterContainerTree.cs | 56 +- .../TestExecuteCommandImportTableInfo.cs | 12 +- .../TestExecuteCommandNewObject.cs | 17 +- .../CommandExecution/TestExecuteCommandSet.cs | 24 +- .../TestExecuteCommandSetUserSetting.cs | 20 +- .../CommandLine/AbstractBaseRunnerTests.cs | 27 +- .../AutomationLoopTests/EndToEndCacheTest.cs | 8 +- .../EndToEndDLECacheTest.cs | 15 +- .../AutomationLoopTests/EndToEndDLETest.cs | 9 +- .../CommandLineObjectPickerTests.cs | 153 +- .../ExampleDatasetsCreationTests.cs | 20 +- .../CommandLine/NewObjectPoolTests.cs | 23 +- Rdmp.Core.Tests/CommandLine/PickTableTests.cs | 21 +- .../CommandLine/RdmpScriptTests.cs | 38 +- Rdmp.Core.Tests/CommentStoreTests.cs | 38 +- .../Anonymisation/ANOMigrationTests.cs | 14 +- .../ANOStoreFunctionalityTests.cs | 8 +- .../Curation/Anonymisation/ANOTableTests.cs | 71 +- ...orwardEngineerANOCatalogueTwoTableTests.cs | 13 +- .../IdentifierDumpFunctionalityTests.cs | 62 +- .../BasicParameterUseTests.cs | 12 +- Rdmp.Core.Tests/Curation/DublinCoreTests.cs | 62 +- .../Curation/ExtendedPropertyTests.cs | 28 +- .../ImportTests/GatherAndShareTests.cs | 139 +- .../Curation/ImportTests/PluginClassTests.cs | 123 -- .../ImportTests/ShareLoadMetadataTests.cs | 38 +- .../Integration/AllKeywordsDescribedTest.cs | 6 +- .../ArgumentTests/ArgumentTypeTests.cs | 9 +- .../ArgumentTests/ProcessTaskArgumentTests.cs | 66 +- .../ArgumentTests/ProcessTaskTests.cs | 73 +- .../Integration/BundledLookupTableTests.cs | 15 +- .../Integration/CatalogueCheckTests.cs | 8 +- .../Integration/CatalogueItemTests.cs | 83 +- .../Curation/Integration/CatalogueTests.cs | 186 +- .../Curation/Integration/ColumnInfoTests.cs | 42 +- .../Integration/CommitInProgressTests.cs | 18 +- ...mprehensiveQueryPerformanceCounterTests.cs | 4 +- .../Curation/Integration/CredentialsTests.cs | 92 +- .../Integration/CrossDatabaseTriggerTests.cs | 103 +- .../SuperMultiThreadedVolumeAccess.cs | 10 +- .../Integration/DataAccess/TestDataAccess.cs | 45 +- .../Dependencies/DependencyTests.cs | 21 +- .../Integration/DitaExtractorTests.cs | 25 +- .../Curation/Integration/EncryptionTests.cs | 102 +- .../ExtractionFilterParameterSetTests.cs | 11 +- .../Integration/ExtractionFilterTests.cs | 3 +- .../Integration/ExtractionInformationTests.cs | 51 +- .../ExtractionInformationUnitTests.cs | 10 +- .../FilterImporterTests.cs | 18 +- .../ParameterCreatorTests.cs | 15 +- .../ForwardEngineerANOCatalogueTests.cs | 177 +- .../GetDatabaseDiagramBinaryTest.cs | 7 +- .../Curation/Integration/GovernanceTests.cs | 31 +- .../Curation/Integration/LinkerTests.cs | 19 +- .../Curation/Integration/LoadMetadataTests.cs | 22 +- .../Curation/Integration/LoadProgressTest.cs | 19 +- .../Integration/LoadProgressUnitTests.cs | 4 +- .../Curation/Integration/LookupTest.cs | 94 +- .../Curation/Integration/MEFCheckerTests.cs | 13 +- .../Curation/Integration/MementoTests.cs | 49 +- ...MetadataLoggingConfigurationChecksTests.cs | 15 +- .../MySqlTriggerImplementerTests.cs | 2 +- ...dDataExportObscureDependencyFinderTests.cs | 18 +- ...jectSharingObscureDependencyFinderTests.cs | 29 +- ...lidationXMLObscureDependencyFinderTests.cs | 19 +- .../PasswordEncryptionKeyLocationTests.cs | 27 +- .../Curation/Integration/PipelineTests.cs | 87 +- .../AggregateDataBasedTests.cs | 97 +- .../MicrosoftAggregateBuilderTests.cs | 30 +- .../MySqlAggregateBuilderTests.cs | 8 +- .../MicrosoftQueryBuilderTests.cs | 14 +- .../MySqlQueryBuilderTests.cs | 48 +- .../QueryBuilderUnitTests.cs | 21 +- .../Integration/ServerDefaultsTests.cs | 18 +- .../Integration/SupportingDocumentTests.cs | 11 +- .../Integration/TableInfoSynchronizerTests.cs | 64 +- .../Curation/Integration/TableInfoTests.cs | 105 +- .../Integration/TableNamingConventionTests.cs | 17 +- .../AggregationTests.cs | 32 +- .../ImportAndTestTests.cs | 135 +- .../Curation/Integration/TriggerTests.cs | 87 +- .../Validation/StandardRegexTests.cs | 11 +- .../JsonSerializationTests.cs | 13 +- .../MemoryRepositoryTests.cs | 8 +- .../MemoryRepositoryVsDatabaseRepository.cs | 2 +- .../SelectSQLRefactorerTests.cs | 26 +- .../Curation/SimpleExampleTests.cs | 42 +- .../Unit/AggregateConfigurationTests.cs | 6 +- .../Unit/CacheFetchRequestProviderTests.cs | 19 +- .../Curation/Unit/CacheLagPeriodUnitTests.cs | 22 +- .../Curation/Unit/CatalogueNamingTests.cs | 4 +- .../Curation/Unit/CommitAssemblyTest.cs | 2 +- .../ExerciseData/TestBiochemistryCreation.cs | 12 +- .../ExerciseData/TestDemographyCreation.cs | 14 +- .../ExerciseData/TestPrescribingCreation.cs | 11 +- Rdmp.Core.Tests/Curation/Unit/IColumnTests.cs | 31 +- .../Curation/Unit/IMightBeReadOnlyTests.cs | 44 +- .../Curation/Unit/ObjectConstructorTests.cs | 24 +- .../Curation/Unit/ParameterManagerTests.cs | 81 +- .../Curation/Unit/PermissionWindowTests.cs | 15 +- .../Curation/Unit/PreInitializeTests.cs | 24 +- .../Curation/Unit/SimpleColumnInfoTests.cs | 3 +- .../Curation/Unit/SqlSyntaxHelperTests.cs | 54 +- .../Curation/Unit/TestAcronymGeneration.cs | 2 +- .../Curation/UnitTestsAllObjectsSupported.cs | 13 +- .../Curation/YamlRepositoryTests.cs | 179 +- .../CloneExtractionConfigurationTests.cs | 47 +- .../DataExport/Cohort/CohortTests.cs | 30 +- .../Cohort/CommittingNewCohortsTests.cs | 44 +- ...tentGuidReleaseIdentifierAllocatorTests.cs | 67 +- .../ConfigurationPropertiesTests.cs | 7 +- .../CustomData/CustomDataImportingTests.cs | 37 +- .../Data/ExternalCohortTableTests.cs | 79 +- .../ExtractableCohortAuditLogBuilderTests.cs | 31 +- .../DataExport/Data/ExtractableCohortTests.cs | 11 +- .../Data/ExtractionProgressTests.cs | 40 +- .../Data/SelectedDataSetsCheckerTests.cs | 10 +- .../DataAccess/PackageContentsTests.cs | 8 +- .../DataAccess/SelectedColumnsTests.cs | 8 +- .../DataExport/DataExportRepositoryTests.cs | 12 +- .../EmptyDataExtractionTests.cs | 22 +- ...eCrossServerDatasetExtractionSourceTest.cs | 7 +- ...tasetExtractionFlatFileDestinationTests.cs | 9 +- ...ullExtractionToDatabaseMSSqlChecksTests.cs | 20 +- ...xtractionToDatabaseMSSqlDestinationTest.cs | 35 +- ...SynthesizerDatasetExtractionSourceTests.cs | 53 +- .../ExtractionSubdirectoryPatternTests.cs | 8 +- .../HashedDataExtractionTests.cs | 18 +- .../NormalDataExtractionTests.cs | 21 +- .../DataExtraction/RowPeekerTests.cs | 18 +- .../SimpleFileExtractorTests.cs | 14 +- .../SupplementalExtractionResultsTest.cs | 9 +- .../DataExtraction/TestCohortRefreshing.cs | 39 +- .../DataExport/ExtractionConfigurationTest.cs | 2 +- Rdmp.Core.Tests/DataExport/ImportFileTests.cs | 40 +- .../DataExport/ProjectChecksTestsComplex.cs | 7 +- .../DataExport/ProjectChecksTestsSimple.cs | 36 +- ...tificationConfigurationAssociationTests.cs | 29 +- .../EndToEndTableValuedFunction.cs | 54 +- .../DataExport/TestExtractableTables.cs | 23 +- .../HICDatabaseConfigurationTests.cs | 32 +- .../TableInfoCloneOperationTests.cs | 2 +- .../Integration/BackfillSqlHelperTests.cs | 10 +- .../Engine/Integration/BackfillTests.cs | 118 +- .../Integration/CachedFileRetrieverTests.cs | 9 +- .../CheckingTests/ProcessTaskCheckingTests.cs | 21 +- .../Engine/Integration/CoalescerTests.cs | 11 +- .../CrossDatabaseDataLoadTests.cs | 104 +- .../CrossDatabaseMergeCommandTest.cs | 26 +- .../HowDoWeAchieveMd5Test.cs | 13 +- .../Integration/DataLoadEngineTestsBase.cs | 26 +- .../DataLoadProgressUpdateInfoTests.cs | 31 +- .../DataTableUploadDestinationTests.cs | 302 +-- .../Integration/DatabaseOperationTests.cs | 11 +- .../DilutionOperationFactoryTests.cs | 4 +- .../DilutionTests/DilutionOperationTests.cs | 10 +- .../Engine/Integration/DistincterTests.cs | 4 +- .../Engine/Integration/ExcelConversionTest.cs | 19 +- .../Engine/Integration/ExcelDatabaseTests.cs | 16 +- .../Integration/ExecutableProcessTaskTests.cs | 11 +- .../ExecuteSqlFileRuntimeTaskTests.cs | 19 +- .../Engine/Integration/FixedWidthTests.cs | 171 +- .../Integration/FlatFileAttacherTests.cs | 164 +- .../Engine/Integration/HICPipelineTests.cs | 11 +- .../Engine/Integration/HousekeepingTests.cs | 4 +- .../ImportFilesDataProviderTests.cs | 48 +- ...nerationStrategyFactoryTestsIntegration.cs | 26 +- .../Engine/Integration/KVPAttacherTest.cs | 21 +- .../Integration/MigrationStrategyTests.cs | 3 +- .../Engine/Integration/PayloadTest.cs | 2 +- .../PipelineTests/ArchiveFilesTests.cs | 13 +- .../ComponentCompatibilityTests.cs | 2 +- .../Components/AliasHandlerTests.cs | 58 +- .../Components/ColumnSwapperTests.cs | 92 +- .../Components/RemoveDuplicatesTests.cs | 67 +- .../Components/TransposerTests.cs | 13 +- .../PipelineTests/PipelineArgumentTests.cs | 7 +- .../PipelineReadPerformanceTest.cs | 4 +- .../Sources/DelimitedFileSourceTests.cs | 189 +- .../Sources/DelimitedFileSourceTestsBase.cs | 2 +- ...edFileSourceTests_AutomaticallyResolved.cs | 115 +- ...SourceTests_ResolvedAccordingToStrategy.cs | 95 +- .../DelimitedFileSourceTests_Unresolveable.cs | 10 +- .../PipelineTests/Sources/SourceTests.cs | 29 +- .../Integration/PrematureLoadEnderTests.cs | 8 +- .../PrimaryKeyCollisionResolverTests.cs | 32 +- .../RemoteDatabaseAttacherTests.cs | 7 +- .../Integration/RuntimeTaskFactoryTests.cs | 3 +- ...maryKeyCollisionResolverMutilationTests.cs | 132 +- .../TableInfoJoiningQueryBuilderTests.cs | 21 +- .../Integration/TableVarcharMaxerTests.cs | 18 +- .../Engine/Integration/TestTemporalTables.cs | 16 +- .../Engine/Unit/CohortSamplerTests.cs | 35 +- .../Engine/Unit/CommandLineHelperTests.cs | 13 +- .../Engine/Unit/DataFlowComponentTests.cs | 14 +- .../DataLoad/Engine/Unit/ExcelTests.cs | 193 +- .../Engine/Unit/ExecutableProcessTaskTests.cs | 4 +- ...bDateGenerationStrategyFactoryTestsUnit.cs | 6 +- .../Unit/JobDateGenerationStrategyTests.cs | 34 +- .../DataLoad/Engine/Unit/MDFAttacherTests.cs | 44 +- .../DataLoad/Engine/Unit/SchedulingTests.cs | 6 +- .../Attachers/RemoteTableAttacherTests.cs | 62 +- .../DataFlowOperations/RowDeleterTests.cs | 20 +- .../DataFlowOperations/SetNullTests.cs | 24 +- .../CatalogueConstraintReportTests.cs | 79 +- .../DQEGraphAnnotationTests.cs | 30 +- .../PeriodicityStateTests.cs | 6 +- .../MasterDatabaseScriptExecutorTests.cs | 5 +- .../Databases/Patch68FixNamespacesTest.cs | 3 +- .../DatabaseEntityConventionTests.cs | 3 +- Rdmp.Core.Tests/IHasSummaryTests.cs | 2 +- .../Logging/ArchivalDataLoadInfoTests.cs | 2 +- .../Logging/FatalErrorLoggingTest.cs | 11 +- Rdmp.Core.Tests/Logging/LogManagerTest.cs | 55 +- .../CatalogueProblemProviderTests.cs | 114 +- Rdmp.Core.Tests/Providers/RowVerTest.cs | 34 +- .../Providers/SearchablesMatchScorerTests.cs | 21 +- ...gregateConfigurationResultsManagerTests.cs | 35 +- .../DataAccessPortalCollectionTests.cs | 72 +- .../ExtractableAggregateCachingTests.cs | 20 +- .../QueryCachingCrossServerTests.cs | 70 +- Rdmp.Core.Tests/Rdmp.Core.Tests.csproj | 8 +- .../Reports/CustomMetadataReportTests.cs | 160 +- .../WordDataReleaseFileGeneratorTests.cs | 2 +- .../Reports/MetadataReportTests.cs | 18 +- .../Repositories/CatalogueRepositoryTests.cs | 18 +- .../ChangeLogIsCorrectTests.cs | 6 +- .../DataTableExtensionsTests.cs | 27 +- .../ExpectedIdenticalStringsExceptionTests.cs | 34 +- .../PackageListIsCorrectTests.cs | 15 +- .../ReusableCodeTests/UsefulStuffTests.cs | 60 +- .../ReusableCodeTests/UsefulStuffUnitTests.cs | 6 +- .../Constraints/Primary/AlphaNumericTest.cs | 8 +- .../Constraints/Primary/AlphaTest.cs | 8 +- .../Primary/BoundsValidationDateTest.cs | 56 +- .../Primary/BoundsValidationIntegerTest.cs | 2 +- .../Validation/Constraints/Primary/ChiTest.cs | 8 +- .../Constraints/Primary/ChiValidationTest.cs | 4 +- .../Constraints/Primary/DateEuTest.cs | 8 +- .../Constraints/Secondary/BoundDateTest.cs | 12 +- .../Secondary/PredictionChiSexTest.cs | 2 +- .../Secondary/PredictionNotNullTest.cs | 9 +- .../Secondary/RegularExpressionTest.cs | 10 +- .../Validation/ExceptionHandlingTests.cs | 4 +- .../Validation/ItemValidatorTest.cs | 16 +- .../Validation/PredictionValidationTest.cs | 24 +- .../ValidationDeserializationMemoryTest.cs | 6 +- .../LegacySerializationTest.cs | 2 +- .../PluginValidationSerializationTest.cs | 17 +- Rdmp.Core.Tests/Validation/ValidatorTest.cs | 63 +- .../CohortCommitting/CohortCommitting.md | 2 +- .../Pipeline/CohortHoldoutLookupRequest.cs | 64 + .../Pipeline/ICohortHoldoutLookupRequest.cs} | 18 +- ...CohortIdentificationConfigurationSource.cs | 1 - ...hortIdentificationConfigurationUICommon.cs | 4 +- .../Execution/CohortCompiler.cs | 17 +- .../CommandExecution/AtomicCommandFactory.cs | 5 +- ...ommandCreateNewCatalogueByImportingFile.cs | 23 +- .../ExecuteCommandAddPlugins.cs | 18 +- .../ExecuteCommandCreateDataset.cs | 31 + .../ExecuteCommandCreateHoldoutLookup.cs | 202 ++ ...uteCommandCreateNewFileBasedProcessTask.cs | 49 +- .../ExecuteCommandDeleteDataset.cs | 26 + .../ExecuteCommandExportDatabaseToDir.cs | 52 + .../ExecuteCommandExportPlugins.cs | 20 +- .../ExecuteCommandLinkCatalogueToDataset.cs | 49 + .../ExecuteCommandLinkColumnInfoToDataset.cs | 41 + .../CommandExecution/BasicActivateItems.cs | 10 + .../CommandExecution/IBasicActivateItems.cs | 4 + .../DatabaseCreation/NightmareDatasets.cs | 3 - .../ForwardEngineerANOCataloguePlanManager.cs | 7 +- .../Curation/Data/Cache/CacheLagPeriod.cs | 2 +- Rdmp.Core/Curation/Data/Catalogue.cs | 4 +- .../Data/Cohort/CohortAggregateContainer.cs | 4 +- Rdmp.Core/Curation/Data/ColumnInfo.cs | 14 + Rdmp.Core/Curation/Data/CommitInProgress.cs | 6 +- .../Data/Dashboarding/PersistStringHelper.cs | 5 +- .../Curation/Data/DataLoad/ProcessTask.cs | 5 +- .../Curation/Data/DataLoad/ProcessTaskType.cs | 5 + Rdmp.Core/Curation/Data/Dataset.cs | 79 + .../Data/EntityNaming/SuffixBasedNamer.cs | 5 +- .../Curation/Data/ExternalDatabaseServer.cs | 4 +- .../Data/ExtractionFilterParameterSet.cs | 4 +- Rdmp.Core/Curation/Data/IDataset.cs | 25 + Rdmp.Core/Curation/Data/LoadModuleAssembly.cs | 196 +- .../Data/Pipelines/IDataFlowPipelineEngine.cs | 5 +- Rdmp.Core/Curation/Data/Plugin.cs | 149 +- Rdmp.Core/Curation/Data/TableInfo.cs | 2 +- .../Pipeline/SimpleFileExtractor.cs | 2 +- .../Sources/ExecuteDatasetExtractionSource.cs | 7 +- .../DataFlowPipelineEngine.cs | 68 +- .../Runtime/ExecuteSqlBakFileRuntimeTask.cs | 124 ++ .../Components/Runtime/RuntimeTaskFactory.cs | 1 + .../Destinations/SqlBulkInsertDestination.cs | 2 +- .../Modules/Attachers/FixedWidthFormatFile.cs | 2 +- .../DataFlowOperations/CohortSampler.cs | 4 - .../DataFlowSources/ExcelDataFlowSource.cs | 21 +- .../DataLoad/Modules/FTP/FTPDownloader.cs | 237 +-- .../DataLoad/Modules/FTP/SFTPDownloader.cs | 74 +- .../Reports/CatalogueConstraintReport.cs | 7 +- .../PeriodicityCubesOverTime.cs | 16 +- .../CreateCatalogue.sql | 27 +- .../up/077_AddDataSetMapping.sql | 27 + .../runAfterCreateDatabase/CreateLogging.sql | 2 +- .../Dataset/DatasetConfigurationUICommon.cs | 31 + Rdmp.Core/Icons/AllExpiredPluginsNode.png | Bin 973 -> 0 bytes Rdmp.Core/Icons/Dataset.png | Bin 0 -> 726 bytes .../IconProvision/CatalogueIconProvider.cs | 1 + .../IconProvision/CatalogueIcons.Designer.cs | 25 +- .../Icons/IconProvision/CatalogueIcons.resx | 8 +- Rdmp.Core/Icons/IconProvision/RDMPConcept.cs | 4 +- .../ProcessTaskStateBasedIconProvider.cs | 1 + .../MemoryRepository.cs | 14 +- Rdmp.Core/Providers/CatalogueChildProvider.cs | 80 +- .../Providers/DataExportChildProvider.cs | 6 +- Rdmp.Core/Providers/DatasetChildProvider.cs | 18 + Rdmp.Core/Providers/DescendancyList.cs | 2 +- Rdmp.Core/Providers/ICoreChildProvider.cs | 2 + Rdmp.Core/Providers/Nodes/SingletonNode.cs | 17 +- .../QueryBuilding/ExtractionQueryBuilder.cs | 2 +- .../Options/AggregateBuilderCohortOptions.cs | 2 +- Rdmp.Core/QueryBuilding/QueryTimeColumn.cs | 6 +- Rdmp.Core/RDMPCollection.cs | 3 +- Rdmp.Core/Rdmp.Core.csproj | 254 +-- Rdmp.Core/Reports/DocXHelper.cs | 8 +- .../DublinCore/DublinCoreDefinition.cs | 6 +- .../WordDataReleaseFileGenerator.cs | 18 +- .../Reports/ExtractionTime/WordDataWriter.cs | 34 +- Rdmp.Core/Repositories/CatalogueRepository.cs | 5 - .../Repositories/ICatalogueRepository.cs | 5 - Rdmp.Core/Repositories/MEF.cs | 1 - .../Managers/CommentStoreWithKeywords.cs | 10 +- .../FilterManagerFromChildProvider.cs | 2 +- .../Repositories/Managers/PluginManager.cs | 42 - .../Repositories/MemoryCatalogueRepository.cs | 74 +- Rdmp.Core/Repositories/YamlRepository.cs | 27 - .../Checks/CheckEventArgs.cs | 6 +- .../IgnorableSerializerContractResolver.cs | 9 +- .../Sharing/Dependency/Gathering/Gatherer.cs | 11 - Rdmp.Core/Startup/Startup.cs | 6 +- Rdmp.UI.Tests/AggregateEditorUITests.cs | 45 +- Rdmp.UI.Tests/ArbitraryFolderNodeTests.cs | 6 +- Rdmp.UI.Tests/CatalogueIconProviderTests.cs | 14 +- Rdmp.UI.Tests/CatalogueItemUITests.cs | 18 +- Rdmp.UI.Tests/CatalogueUITests.cs | 52 +- Rdmp.UI.Tests/ChildProviderTests.cs | 100 +- ...ortIdentificationConfigurationUnitTests.cs | 33 +- .../ExternalCohortTableUITests.cs | 2 +- .../ExecuteCommandAlterColumnTypeTests.cs | 22 +- .../ExecuteCommandClearFavouritesTests.cs | 15 +- .../ExecuteCommandDeleteTests.cs | 38 +- .../Integration/ExtractionFilterUITests.cs | 14 +- .../ColumnInfoToANOTableConverterUITests.cs | 2 +- .../DataRelease/DataReleaseUITests.cs | 2 +- .../AllObjectsHaveImages.cs | 2 +- .../AllUIsDocumentedTest.cs | 2 +- .../AllImportantClassesDocumented.cs | 2 +- .../DocumentationCrossExaminationTest.cs | 4 +- .../ExplicitDatabaseNameChecker.cs | 2 +- ...mptyChecksMethodsOrNotICheckablePlugins.cs | 2 +- .../SuspiciousRelationshipPropertyUse.cs | 63 +- .../DependenciesEvaluation.cs | 182 -- ...aluateNamespacesAndSolutionFoldersTests.cs | 17 +- .../InterfaceDeclarationsCorrect.cs | 2 +- .../DesignPatternTests/RunUITests.cs | 9 +- .../UserInterfaceStandardisationChecker.cs | 2 +- .../ExternalDatabaseServerUITests.cs | 6 +- .../ExtractionUIs/ConfigureDatasetUITests.cs | 15 +- .../JoinsAndLookups/LookupBrowserUITests.cs | 2 +- Rdmp.UI.Tests/ForEachUITests.cs | 7 +- Rdmp.UI.Tests/HelpIconTests.cs | 4 +- Rdmp.UI.Tests/HistoryProviderTests.cs | 54 +- Rdmp.UI.Tests/LogViewer/LoggingTabUITests.cs | 2 +- Rdmp.UI.Tests/Rdmp.UI.Tests.csproj | 11 +- Rdmp.UI.Tests/TypeTextOrCancelDialogTests.cs | 32 +- Rdmp.UI.Tests/UITests.cs | 41 +- Rdmp.UI.Tests/UITimeoutAttribute.cs | 1 - Rdmp.UI.Tests/WideMessageBoxTests.cs | 44 +- Rdmp.UI/ChecksUI/RAGSmileyToolStrip.cs | 4 +- .../CreateHoldoutLookupUI.Designer.cs | 385 ++++ .../CreateHoldoutLookupUI.cs | 133 ++ .../CreateHoldoutLookupUI.resx | 120 ++ .../CohortUI/CreateHoldoutLookup/Holdouts.md | 16 + .../DatasetsCollectionUI.Designer.cs | 81 + Rdmp.UI/Collections/DatasetsCollectionUI.cs | 109 + Rdmp.UI/Collections/DatasetsCollectionUI.resx | 120 ++ .../RDMPCollectionCommonFunctionality.cs | 45 +- .../ExecuteCommandCreateNewDatasetUI.cs | 28 + .../ExecuteCommandDeleteDatasetUI.cs | 38 + .../ExecuteCommandDeletePlugin.cs | 44 + .../ExecuteCommandLinkCatalogueToDatasetUI.cs | 54 + ...ExecuteCommandLinkColumnInfoToDataSetUI.cs | 54 + .../ExecuteCommandOpenExtractionDirectory.cs | 6 +- .../ProposeExecutionWhenTargetIsDataset.cs | 36 + ...oposeExecutionWhenTargetIsLoadStageNode.cs | 5 +- ...ProposeExecutionWhenTargetIsProcessTask.cs | 3 + .../LoadDiagram/LoadDiagramUI.cs | 18 +- .../Diagrams/LoadProgressDiagramUI.cs | 9 +- .../ParameterUIs/ParameterCollectionUI.cs | 14 +- .../JoinsAndLookups/LookupConfigurationUI.cs | 2 +- .../CatalogueItemUI.Designer.cs | 597 +++--- Rdmp.UI/MainFormUITabs/CatalogueItemUI.cs | 39 +- Rdmp.UI/MainFormUITabs/CatalogueItemUI.resx | 62 +- .../MainFormUITabs/CatalogueUI.Designer.cs | 1755 +++++++++-------- Rdmp.UI/MainFormUITabs/CatalogueUI.cs | 19 + Rdmp.UI/MainFormUITabs/CatalogueUI.resx | 65 +- .../MainFormUITabs/ExtractionProgressUI.cs | 2 +- Rdmp.UI/Menus/CatalogueMenu.cs | 2 +- Rdmp.UI/Menus/ColumnInfoMenu.cs | 2 +- Rdmp.UI/Menus/DatasetMenu.cs | 20 + Rdmp.UI/Menus/LoadModuleAssemblyMenu.cs | 18 + Rdmp.UI/Menus/RDMPContextMenuStrip.cs | 8 +- ...talogueToDatasetLinkageObjectCollection.cs | 17 +- ...ogueToDatasetLinkagePieChartUI.Designer.cs | 136 ++ .../CatalogueToDatasetLinkagePieChartUI.cs | 303 +++ .../CatalogueToDatasetLinkagePieChartUI.resx | 124 ++ Rdmp.UI/Progress/ProgressUI.cs | 7 +- .../ProjectUI/Datasets/ConfigureDatasetUI.cs | 28 +- Rdmp.UI/ProjectUI/ExecuteExtractionUI.cs | 2 +- .../ProjectUI/ExtractCommandStateMonitor.cs | 8 +- Rdmp.UI/Rdmp.UI.csproj | 13 +- Rdmp.UI/Refreshing/RefreshBus.cs | 4 +- Rdmp.UI/SimpleControls/ObjectSaverButton.cs | 102 +- .../Datasets/CreateNewDatasetUI.Designer.cs | 139 ++ .../Datasets/CreateNewDatasetUI.cs | 31 + .../Datasets/CreateNewDatasetUI.resx | 120 ++ .../ConfigureCatalogueExtractabilityUI.cs | 27 +- Rdmp.UI/SimpleDialogs/SelectDialog`1.resx | 923 +-------- .../SimpleDialogs/ViewSourceCodeToolTip.cs | 35 +- .../SimpleDialogs/WideMessageBox.Designer.cs | 1 + Rdmp.UI/SimpleDialogs/WideMessageBox.cs | 3 + .../DatasetConfigurationUI.Designer.cs | 147 ++ .../SubComponents/DatasetConfigurationUI.cs | 70 + .../SubComponents/DatasetConfigurationUI.resx | 120 ++ .../RDMPControlCommonFunctionality.cs | 9 +- Rdmp.UI/TestsAndSetup/StartupUI.cs | 13 +- Rdmp.UI/Theme/BackColorProvider.cs | 1 + .../CreateNewDataExtractionProjectUI.cs | 92 +- SharedAssemblyInfo.cs | 6 +- Tests.Common/DatabaseTests.cs | 20 +- .../Scenarios/TestsRequiringACohort.cs | 4 +- ...TestsRequiringAnExtractionConfiguration.cs | 6 +- Tests.Common/Tests.Common.csproj | 6 +- Tests.Common/UnitTests.cs | 29 +- .../CommandLine/Gui/ConsoleGuiSelectOne.cs | 2 +- Tools/rdmp/rdmp.csproj | 9 +- rdmp-client.xml | 4 +- scripts/orphan_extractable_column.yaml | 4 +- wix/build.cmd | 4 +- wix/rdmp.wxs | 84 - 517 files changed, 12234 insertions(+), 8892 deletions(-) delete mode 100644 Application/ResearchDataManagementPlatform/NLog.template.config create mode 100644 Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateDatasetTests.cs create mode 100644 Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeleteDatasetTest.cs create mode 100644 Rdmp.Core.Tests/CommandExecution/ExecuteCommandLinkCatalogueToDatasetTests.cs create mode 100644 Rdmp.Core.Tests/CommandExecution/ExecuteCommandLinkCoulmnInfoWithDatasetTests.cs delete mode 100644 Rdmp.Core.Tests/Curation/ImportTests/PluginClassTests.cs create mode 100644 Rdmp.Core/CohortCommitting/Pipeline/CohortHoldoutLookupRequest.cs rename Rdmp.Core/{Repositories/Managers/IPluginManager.cs => CohortCommitting/Pipeline/ICohortHoldoutLookupRequest.cs} (67%) create mode 100644 Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateDataset.cs create mode 100644 Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateHoldoutLookup.cs create mode 100644 Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandDeleteDataset.cs create mode 100644 Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandExportDatabaseToDir.cs create mode 100644 Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandLinkCatalogueToDataset.cs create mode 100644 Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandLinkColumnInfoToDataset.cs create mode 100644 Rdmp.Core/Curation/Data/Dataset.cs create mode 100644 Rdmp.Core/Curation/Data/IDataset.cs create mode 100644 Rdmp.Core/DataLoad/Engine/LoadExecution/Components/Runtime/ExecuteSqlBakFileRuntimeTask.cs create mode 100644 Rdmp.Core/Databases/CatalogueDatabase/up/077_AddDataSetMapping.sql create mode 100644 Rdmp.Core/Dataset/DatasetConfigurationUICommon.cs delete mode 100644 Rdmp.Core/Icons/AllExpiredPluginsNode.png create mode 100644 Rdmp.Core/Icons/Dataset.png create mode 100644 Rdmp.Core/Providers/DatasetChildProvider.cs delete mode 100644 Rdmp.Core/Repositories/Managers/PluginManager.cs delete mode 100644 Rdmp.UI.Tests/DesignPatternTests/DependenciesEvaluation.cs create mode 100644 Rdmp.UI/CohortUI/CreateHoldoutLookup/CreateHoldoutLookupUI.Designer.cs create mode 100644 Rdmp.UI/CohortUI/CreateHoldoutLookup/CreateHoldoutLookupUI.cs create mode 100644 Rdmp.UI/CohortUI/CreateHoldoutLookup/CreateHoldoutLookupUI.resx create mode 100644 Rdmp.UI/CohortUI/CreateHoldoutLookup/Holdouts.md create mode 100644 Rdmp.UI/Collections/DatasetsCollectionUI.Designer.cs create mode 100644 Rdmp.UI/Collections/DatasetsCollectionUI.cs create mode 100644 Rdmp.UI/Collections/DatasetsCollectionUI.resx create mode 100644 Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandCreateNewDatasetUI.cs create mode 100644 Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandDeleteDatasetUI.cs create mode 100644 Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandDeletePlugin.cs create mode 100644 Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandLinkCatalogueToDatasetUI.cs create mode 100644 Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandLinkColumnInfoToDataSetUI.cs create mode 100644 Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsDataset.cs create mode 100644 Rdmp.UI/Menus/DatasetMenu.cs create mode 100644 Rdmp.UI/Menus/LoadModuleAssemblyMenu.cs rename Rdmp.Core/Providers/Nodes/AllExpiredPluginsNode.cs => Rdmp.UI/PieCharts/CatalogueToDatasetLinkageObjectCollection.cs (64%) create mode 100644 Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.Designer.cs create mode 100644 Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.cs create mode 100644 Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.resx create mode 100644 Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.Designer.cs create mode 100644 Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.cs create mode 100644 Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.resx create mode 100644 Rdmp.UI/SubComponents/DatasetConfigurationUI.Designer.cs create mode 100644 Rdmp.UI/SubComponents/DatasetConfigurationUI.cs create mode 100644 Rdmp.UI/SubComponents/DatasetConfigurationUI.resx diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a9ab6ded0d..d44cb25bdb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,16 +18,6 @@ jobs: runs-on: windows-latest steps: - - name: Stub Node dependencies - shell: bash - run: touch package-lock.json - - name: Install Node for coverage reporting - uses: actions/setup-node@v3.8.1 - with: - node-version: '16.x' - cache: 'npm' - - name: LCov merger tool - run: npm install -g lcov-result-merger - name: Checkout code uses: actions/checkout@v4 - name: Determine RDMP build version @@ -37,7 +27,7 @@ jobs: - name: Check output run: echo ${{ steps.version.outputs.rdmpversion }} - name: Setup .NET Core - uses: actions/setup-dotnet@v3.2.0 + uses: actions/setup-dotnet@v4.0.0 with: dotnet-version: 6.0.x - name: Install MS SQL 2019 Express LocalDB @@ -59,6 +49,14 @@ jobs: shell: bash run: | find ./Tools/rdmp/Databases.yaml -type f -exec sed -i 's/RDMP_/TEST_/g' {} \; + - name: BundleSource + shell: bash + run: | + mkdir -p Tools/BundleUpSourceIntoZip/output + rm -f Tools/BundleUpSourceIntoZip/output/SourceCodeForSelfAwareness.zip + echo "dir /s/b *.cs *.xml > srcbitsa.txt" | cmd + perl -pe '$_=reverse' < srcbitsa.txt | sort -t'\' -k1,1 -u | perl -pe '$_=reverse' > srcbits.txt + echo 7z a -mx=9 Tools/BundleUpSourceIntoZip/output/SourceCodeForSelfAwareness.zip @srcbits.txt | cmd - name: Build run: dotnet build --configuration Release --verbosity minimal - name: Create MySql Logging, DQE and Cohort Building Cache Db @@ -97,51 +95,59 @@ jobs: mv `find coverage -type f` fs-ui.lcov dotnet test Rdmp.Core.Tests/Rdmp.Core.Tests.csproj --nologo --collect:"XPlat Code Coverage" --no-build --verbosity minimal -c Release --results-directory coverage -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=lcov mv `find coverage -type f` fs-core.lcov - - name: Merge LCovs - run: lcov-result-merger "{db,fs}-{ui,core}.lcov" all.lcov - name: Coveralls - uses: coverallsapp/github-action@master + uses: coverallsapp/github-action@v2.2.3 with: github-token: ${{ secrets.github_token }} - path-to-lcov: all.lcov + files: ./db-ui.lcov ./db-core.lcov ./fs-ui.lcov ./fs-core.lcov flag-name: unit tests - name: Package run: | - dotnet publish Application/ResearchDataManagementPlatform/ResearchDataManagementPlatform.csproj -r win-x64 --self-contained -c Release -o PublishWinForms -p:GenerateDocumentationFile=false -p:PublishSingleFile=true -p:PublishReadyToRun=true --verbosity minimal --nologo - dotnet publish Tools/rdmp/rdmp.csproj -r win-x64 --self-contained -c Release -o PublishWindows -p:GenerateDocumentationFile=false -p:PublishSingleFile=true -p:PublishReadyToRun=true --verbosity minimal --nologo + dotnet publish Application/ResearchDataManagementPlatform/ResearchDataManagementPlatform.csproj -r win-x64 --self-contained -c Release -o PublishWinForms -p:GenerateDocumentationFile=false -p:PublishSingleFile=true -p:PublishReadyToRun=true -p:IncludeNativeLibrariesForSelfExtract=true --verbosity minimal --nologo + dotnet publish Tools/rdmp/rdmp.csproj -r win-x64 --self-contained -c Release -o PublishWindows -p:GenerateDocumentationFile=false -p:PublishSingleFile=true -p:PublishReadyToRun=true -p:IncludeNativeLibrariesForSelfExtract=true --verbosity minimal --nologo dotnet publish Tools/rdmp/rdmp.csproj -r linux-x64 --self-contained -c Release -o PublishLinux -p:GenerateDocumentationFile=false -p:PublishSingleFile=true -p:PublishReadyToRun=true --verbosity minimal --nologo - - name: BundleSource + - name: Install Plugins + if: contains(github.ref, 'refs/tags/v') || contains('refs/heads/main refs/heads/develop',github.ref) shell: bash run: | - mkdir -p Tools/BundleUpSourceIntoZip/output - echo "dir /s/b *.cs *.xml > srcbitsa.txt" | cmd - perl -pe '$_=reverse' < srcbitsa.txt | sort -t'\' -k1,1 -u | perl -pe '$_=reverse' > srcbits.txt - echo 7z a -mx=9 Tools/BundleUpSourceIntoZip/output/SourceCodeForSelfAwareness.zip @srcbits.txt | cmd + for plugin in https://api.github.com/repos/SMI/RdmpDicom/releases/latest https://api.github.com/repos/HICServices/HicPlugin/releases/latest https://api.github.com/repos/HICServices/RdmpExtensions/releases/latest + do + PluginName="$(cut -d/ -f6 <<< $plugin)" + NAME="$(curl -s $plugin | grep "browser_download_url.*$PluginName.*nupkg" | cut -d : -f 2,3 | cut -d "\"" -f 2)" + echo $NAME + curl -OL $NAME + for platform in PublishWindows PublishLinux PublishWinForms + do + cp *.nupkg $platform + done + rm *.nupkg + done - name: Sign + if: contains(github.ref, 'refs/tags/v') || contains('refs/heads/main refs/heads/develop',github.ref) shell: bash run: | - signtool=(/c/Program\ Files\ \(x86\)/Windows\ Kits/10/bin/*/x64/signtool.exe) - signtool=${signtool[${#signtool[@]}-1]} - signtool=`echo $signtool | sed -e 's#^/c#c:#' | tr / \\\\` - echo ${{ secrets.DIGICERT_PFX }} | base64 --decode > GitHubActionsWorkflow.pfx - echo '"'$signtool'"' 'Sign /f GitHubActionsWorkflow.pfx /fd sha256 /tr http://timestamp.digicert.com /td sha256 /p ${{ secrets.DIGICERT_PASSWORD }} PublishWindows/*.exe PublishWinForms/*.exe' | cmd + dotnet tool install --global AzureSignTool + AzureSignTool sign -kvu "${{ secrets.AZURE_KEY_VAULT_URI }}" -kvi "${{ secrets.AZURE_CLIENT_ID }}" -kvt "${{ secrets.AZURE_TENANT_ID }}" -kvs "${{ secrets.AZURE_CLIENT_SECRET }}" -kvc ${{ secrets.AZURE_CERT_NAME }} -tr http://timestamp.digicert.com -v PublishWindows/rdmp.exe + AzureSignTool sign -kvu "${{ secrets.AZURE_KEY_VAULT_URI }}" -kvi "${{ secrets.AZURE_CLIENT_ID }}" -kvt "${{ secrets.AZURE_TENANT_ID }}" -kvs "${{ secrets.AZURE_CLIENT_SECRET }}" -kvc ${{ secrets.AZURE_CERT_NAME }} -tr http://timestamp.digicert.com -v PublishWinForms/ResearchDataManagementPlatform.exe mkdir -p dist cmd /c wix\\build.cmd ${{ steps.version.outputs.rdmpversion }} - echo '"'$signtool'"' 'Sign /f GitHubActionsWorkflow.pfx /fd sha256 /tr http://timestamp.digicert.com /td sha256 /p ${{ secrets.DIGICERT_PASSWORD }} dist/rdmp.msi' | cmd - (cd PublishWindows ; echo 7z a -mx=9 ../dist/rdmp-${{ steps.version.outputs.rdmpversion }}-cli-win-x64.zip . | cmd) + (cd PublishWindows ; echo 7z a -mx=9 ../dist/rdmp-${{ steps.version.outputs.rdmpversion }}-cli-win-x64.zip rdmp.exe NLog.config *.yaml *.nupkg | cmd) (cd PublishLinux ; echo 7z a -mx=0 ../dist/rdmp-${{ steps.version.outputs.rdmpversion }}-cli-linux-x64.zip . | cmd) mv PublishLinux rdmp-${{ steps.version.outputs.rdmpversion }}-cli-linux echo 7z a dist/rdmp-${{ steps.version.outputs.rdmpversion }}-cli-linux-x64.tar rdmp-${{ steps.version.outputs.rdmpversion }}-cli-linux | cmd - (cd PublishWinForms ; echo 7z a -mx=9 ../dist/rdmp-${{ steps.version.outputs.rdmpversion }}-client.zip . | cmd) + (cd PublishWinForms ; echo 7z a -mx=9 ../dist/rdmp-${{ steps.version.outputs.rdmpversion }}-client.zip ResearchDataManagementPlatform.exe *.nupkg | cmd) + - name: Install Perl dependencies - uses: shogo82148/actions-setup-perl@v1.23.1 + if: contains(github.ref, 'refs/tags/v') || contains('refs/heads/main refs/heads/develop',github.ref) + uses: shogo82148/actions-setup-perl@v1.25.0 with: install-modules-with: cpanm install-modules: Archive::Zip Archive::Tar - name: Fix execute permissions + if: contains(github.ref, 'refs/tags/v') || contains('refs/heads/main refs/heads/develop',github.ref) shell: perl {0} run: | use strict; @@ -173,11 +179,13 @@ jobs: $zip->memberNamed('rdmp')->unixFileAttributes( 0755 ); $zip->overwriteAs($zipname); - name: Compress tar + if: contains(github.ref, 'refs/tags/v') || contains('refs/heads/main refs/heads/develop',github.ref) run: | 7z a -txz dist/rdmp-${{ steps.version.outputs.rdmpversion }}-cli-linux-x64.tar.xz dist/rdmp-${{ steps.version.outputs.rdmpversion }}-cli-linux-x64.tar rm dist/rdmp-${{ steps.version.outputs.rdmpversion }}-cli-linux-x64.tar - name: Build Nuget packages + if: contains(github.ref, 'refs/tags/v') shell: bash run: | for i in Rdmp.Core/Rdmp.Core.csproj Rdmp.UI/Rdmp.UI.csproj Tests.Common/Tests.Common.csproj @@ -190,9 +198,11 @@ jobs: run: dotnet nuget push HIC.RDMP.Plugin*${{ steps.version.outputs.rdmpversion }}.nupkg -s https://api.nuget.org/v3/index.json --skip-duplicate -k ${{ secrets.NUGET_KEY }} - name: Calculate SHA256SUMS + if: contains(github.ref, 'refs/tags/v') run: '&{foreach ($i in Get-ChildItem dist -Exclude *SUMS|Get-FileHash) { echo "$($i.Hash) $(echo $i | Split-Path -Leaf)" }} > dist/SHA256SUMS' - name: Archive production artifacts + if: contains(github.ref, 'refs/tags/v') || contains('refs/heads/main refs/heads/develop',github.ref) uses: actions/upload-artifact@v3 with: name: dist diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ed58b6036a..9d13ae26d3 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -35,7 +35,21 @@ jobs: - name: Build run: dotnet build + - name: SecurityCodescan + run: | + dotnet tool install --global security-scan + mkdir -p sarif-results + security-scan HIC.DataManagementPlatform.sln -n -x sarif-results/scs.sarif + sed -i 's/"language": ""/"language": "en-US"/' sarif-results/scs.sarif + - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: category: "/language:${{ matrix.language }}" + upload: False + output: sarif-results + + - name: Upload SARIF + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: sarif-results diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 94e1036058..5e3ef508dc 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -17,7 +17,7 @@ jobs: with: submodules: true - name: Setup .NET Core - uses: actions/setup-dotnet@v3.2.0 + uses: actions/setup-dotnet@v4.0.0 with: dotnet-version: 6.0.x - name: Cache Nuget diff --git a/Application/ResearchDataManagementPlatform/NLog.template.config b/Application/ResearchDataManagementPlatform/NLog.template.config deleted file mode 100644 index 348ad21979..0000000000 --- a/Application/ResearchDataManagementPlatform/NLog.template.config +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Application/ResearchDataManagementPlatform/Program.cs b/Application/ResearchDataManagementPlatform/Program.cs index 693670d108..bf5d49e128 100644 --- a/Application/ResearchDataManagementPlatform/Program.cs +++ b/Application/ResearchDataManagementPlatform/Program.cs @@ -5,10 +5,8 @@ // You should have received a copy of the GNU General Public License along with RDMP. If not, see . using System; -using System.IO; using System.Runtime.InteropServices; using CommandLine; -using Rdmp.Core.Curation.Data; using Rdmp.Core.ReusableLibraryCode; using Rdmp.Core.ReusableLibraryCode.Checks; using Rdmp.Core.Startup; diff --git a/Application/ResearchDataManagementPlatform/ResearchDataManagementPlatform.csproj b/Application/ResearchDataManagementPlatform/ResearchDataManagementPlatform.csproj index 3f15434037..e78dd26e59 100644 --- a/Application/ResearchDataManagementPlatform/ResearchDataManagementPlatform.csproj +++ b/Application/ResearchDataManagementPlatform/ResearchDataManagementPlatform.csproj @@ -11,7 +11,6 @@ embedded true true - true true @@ -29,17 +28,10 @@ - - - - - all - runtime; build; native; contentfiles; analyzers - @@ -70,9 +62,6 @@ - - PreserveNewest - RDMPMainForm.cs diff --git a/Application/ResearchDataManagementPlatform/WindowManagement/ActivateItems.cs b/Application/ResearchDataManagementPlatform/WindowManagement/ActivateItems.cs index c3a6dd8a37..b7f6996013 100644 --- a/Application/ResearchDataManagementPlatform/WindowManagement/ActivateItems.cs +++ b/Application/ResearchDataManagementPlatform/WindowManagement/ActivateItems.cs @@ -611,6 +611,7 @@ public override IEnumerable GetIgnoredCommands() yield return typeof(ExecuteCommandRefreshObject); yield return typeof(ExecuteCommandChangeExtractability); yield return typeof(ExecuteCommandOpenInExplorer); + yield return typeof(ExecuteCommandDeletePlugin); yield return typeof(ExecuteCommandCreateNewFileBasedProcessTask); } @@ -831,6 +832,11 @@ public void StartSession(string sessionName, IEnumerable + GetCohortHoldoutLookupRequest(externalCohortTable, project, cic)); + + var ui = new Rdmp.UI.CohortUI.CreateHoldoutLookup.CreateHoldoutLookupUI(this, externalCohortTable, cic); + + if (!string.IsNullOrWhiteSpace(cic.Description)) + ui.CohortDescription = $"{cic.Description} ({Environment.UserName} - {DateTime.Now})"; + return ui.ShowDialog() == DialogResult.OK ? ui.Result : null; + } + public override ICatalogue CreateAndConfigureCatalogue(ITableInfo tableInfo, ColumnInfo[] extractionIdentifierColumns, string initialDescription, IProject projectSpecific, string folder) { + if(extractionIdentifierColumns is not null) + { + return base.CreateAndConfigureCatalogue(tableInfo, extractionIdentifierColumns, initialDescription, projectSpecific, folder); + } // if on wrong Thread if (_mainDockPanel?.InvokeRequired ?? false) return _mainDockPanel.Invoke(() => CreateAndConfigureCatalogue(tableInfo, extractionIdentifierColumns, diff --git a/Application/ResearchDataManagementPlatform/WindowManagement/CollectionNavigation.cs b/Application/ResearchDataManagementPlatform/WindowManagement/CollectionNavigation.cs index 8e66a34146..6e2b4855b1 100644 --- a/Application/ResearchDataManagementPlatform/WindowManagement/CollectionNavigation.cs +++ b/Application/ResearchDataManagementPlatform/WindowManagement/CollectionNavigation.cs @@ -6,7 +6,6 @@ using FAnsi.Discovery; using Rdmp.Core.CommandExecution; -using System.Collections.Generic; using Equ; using Rdmp.Core.MapsDirectlyToDatabaseTable; diff --git a/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.Designer.cs b/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.Designer.cs index a9789d8c89..5548b83c3c 100644 --- a/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.Designer.cs +++ b/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.Designer.cs @@ -31,235 +31,224 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RDMPTaskBarUI)); - this.btnHome = new System.Windows.Forms.ToolStripButton(); - this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); - this.btnCatalogues = new System.Windows.Forms.ToolStripButton(); - this.btnCohorts = new System.Windows.Forms.ToolStripButton(); - this.btnDataExport = new System.Windows.Forms.ToolStripButton(); - this.btnTables = new System.Windows.Forms.ToolStripButton(); - this.btnLoad = new System.Windows.Forms.ToolStripButton(); - this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripSeparator = new System.Windows.Forms.ToolStripSeparator(); - this.toolStrip1 = new System.Windows.Forms.ToolStrip(); - this.btnBack = new System.Windows.Forms.ToolStripSplitButton(); - this.btnForward = new System.Windows.Forms.ToolStripButton(); - this.btnFavourites = new System.Windows.Forms.ToolStripButton(); - this.btnSavedCohorts = new System.Windows.Forms.ToolStripButton(); - this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); - this.cbxLayouts = new System.Windows.Forms.ToolStripComboBox(); - this.btnSaveWindowLayout = new System.Windows.Forms.ToolStripButton(); - this.btnDeleteLayout = new System.Windows.Forms.ToolStripButton(); - this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); - this.cbCommits = new System.Windows.Forms.ToolStripButton(); - this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStrip1.SuspendLayout(); - this.SuspendLayout(); + btnHome = new System.Windows.Forms.ToolStripButton(); + toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + btnCatalogues = new System.Windows.Forms.ToolStripButton(); + btnCohorts = new System.Windows.Forms.ToolStripButton(); + btnDataExport = new System.Windows.Forms.ToolStripButton(); + btnTables = new System.Windows.Forms.ToolStripButton(); + btnDataSets = new System.Windows.Forms.ToolStripButton(); + toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + toolStripSeparator = new System.Windows.Forms.ToolStripSeparator(); + toolStrip1 = new System.Windows.Forms.ToolStrip(); + btnBack = new System.Windows.Forms.ToolStripSplitButton(); + btnForward = new System.Windows.Forms.ToolStripButton(); + btnFavourites = new System.Windows.Forms.ToolStripButton(); + btnSavedCohorts = new System.Windows.Forms.ToolStripButton(); + btnLoads = new System.Windows.Forms.ToolStripButton(); + toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + cbxLayouts = new System.Windows.Forms.ToolStripComboBox(); + btnSaveWindowLayout = new System.Windows.Forms.ToolStripButton(); + btnDeleteLayout = new System.Windows.Forms.ToolStripButton(); + toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); + cbCommits = new System.Windows.Forms.ToolStripButton(); + toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); + toolStrip1.SuspendLayout(); + SuspendLayout(); // // btnHome // - this.btnHome.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnHome.Name = "btnHome"; - this.btnHome.Size = new System.Drawing.Size(44, 22); - this.btnHome.Text = "Home"; - this.btnHome.Click += new System.EventHandler(this.btnHome_Click); + btnHome.ImageTransparentColor = System.Drawing.Color.Magenta; + btnHome.Name = "btnHome"; + btnHome.Size = new System.Drawing.Size(44, 22); + btnHome.Text = "Home"; + btnHome.Click += btnHome_Click; // // toolStripSeparator1 // - this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); + toolStripSeparator1.Name = "toolStripSeparator1"; + toolStripSeparator1.Size = new System.Drawing.Size(6, 25); // // btnCatalogues // - this.btnCatalogues.Image = ((System.Drawing.Image)(resources.GetObject("btnCatalogues.Image"))); - this.btnCatalogues.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnCatalogues.Name = "btnCatalogues"; - this.btnCatalogues.Size = new System.Drawing.Size(86, 22); - this.btnCatalogues.Text = "Catalogues"; - this.btnCatalogues.Click += new System.EventHandler(this.ToolboxButtonClicked); + btnCatalogues.Image = (System.Drawing.Image)resources.GetObject("btnCatalogues.Image"); + btnCatalogues.ImageTransparentColor = System.Drawing.Color.Magenta; + btnCatalogues.Name = "btnCatalogues"; + btnCatalogues.Size = new System.Drawing.Size(86, 22); + btnCatalogues.Text = "Catalogues"; + btnCatalogues.Click += ToolboxButtonClicked; // // btnCohorts // - this.btnCohorts.Image = ((System.Drawing.Image)(resources.GetObject("btnCohorts.Image"))); - this.btnCohorts.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnCohorts.Name = "btnCohorts"; - this.btnCohorts.Size = new System.Drawing.Size(104, 22); - this.btnCohorts.Text = "Cohort Builder"; - this.btnCohorts.Click += new System.EventHandler(this.ToolboxButtonClicked); + btnCohorts.Image = (System.Drawing.Image)resources.GetObject("btnCohorts.Image"); + btnCohorts.ImageTransparentColor = System.Drawing.Color.Magenta; + btnCohorts.Name = "btnCohorts"; + btnCohorts.Size = new System.Drawing.Size(104, 22); + btnCohorts.Text = "Cohort Builder"; + btnCohorts.Click += ToolboxButtonClicked; // // btnDataExport // - this.btnDataExport.Image = ((System.Drawing.Image)(resources.GetObject("btnDataExport.Image"))); - this.btnDataExport.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnDataExport.Name = "btnDataExport"; - this.btnDataExport.Size = new System.Drawing.Size(69, 22); - this.btnDataExport.Text = "Projects"; - this.btnDataExport.Click += new System.EventHandler(this.ToolboxButtonClicked); + btnDataExport.Image = (System.Drawing.Image)resources.GetObject("btnDataExport.Image"); + btnDataExport.ImageTransparentColor = System.Drawing.Color.Magenta; + btnDataExport.Name = "btnDataExport"; + btnDataExport.Size = new System.Drawing.Size(69, 22); + btnDataExport.Text = "Projects"; + btnDataExport.Click += ToolboxButtonClicked; // // btnTables // - this.btnTables.Image = ((System.Drawing.Image)(resources.GetObject("btnTables.Image"))); - this.btnTables.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnTables.Name = "btnTables"; - this.btnTables.Size = new System.Drawing.Size(123, 22); - this.btnTables.Text = "Tables (Advanced)"; - this.btnTables.Click += new System.EventHandler(this.ToolboxButtonClicked); + btnTables.Image = (System.Drawing.Image)resources.GetObject("btnTables.Image"); + btnTables.ImageTransparentColor = System.Drawing.Color.Magenta; + btnTables.Name = "btnTables"; + btnTables.Size = new System.Drawing.Size(123, 22); + btnTables.Text = "Tables (Advanced)"; + btnTables.Click += ToolboxButtonClicked; // - // btnLoad + // btnDataSets // - this.btnLoad.Image = ((System.Drawing.Image)(resources.GetObject("btnLoad.Image"))); - this.btnLoad.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnLoad.Name = "btnLoad"; - this.btnLoad.Size = new System.Drawing.Size(80, 22); - this.btnLoad.Text = "Data Load"; - this.btnLoad.Click += new System.EventHandler(this.ToolboxButtonClicked); + btnDataSets.Image = (System.Drawing.Image)resources.GetObject("btnDataSets.Image"); + btnDataSets.ImageTransparentColor = System.Drawing.Color.Magenta; + btnDataSets.Name = "btnDataSets"; + btnDataSets.Size = new System.Drawing.Size(71, 22); + btnDataSets.Text = "Datasets"; + btnDataSets.Click += ToolboxButtonClicked; // // toolStripSeparator2 // - this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(6, 25); + toolStripSeparator2.Name = "toolStripSeparator2"; + toolStripSeparator2.Size = new System.Drawing.Size(6, 25); // // toolStripSeparator // - this.toolStripSeparator.Name = "toolStripSeparator"; - this.toolStripSeparator.Size = new System.Drawing.Size(6, 25); + toolStripSeparator.Name = "toolStripSeparator"; + toolStripSeparator.Size = new System.Drawing.Size(6, 25); // // toolStrip1 // - this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.btnBack, - this.btnForward, - this.btnHome, - this.toolStripSeparator1, - this.btnFavourites, - this.btnCatalogues, - this.btnCohorts, - this.btnSavedCohorts, - this.btnDataExport, - this.toolStripSeparator, - this.btnTables, - this.btnLoad, - this.toolStripSeparator2, - this.toolStripLabel2, - this.cbxLayouts, - this.btnSaveWindowLayout, - this.btnDeleteLayout, - this.toolStripSeparator4, - this.cbCommits, - this.toolStripSeparator3}); - this.toolStrip1.Location = new System.Drawing.Point(0, 0); - this.toolStrip1.Name = "toolStrip1"; - this.toolStrip1.Size = new System.Drawing.Size(1539, 25); - this.toolStrip1.TabIndex = 0; - this.toolStrip1.Text = "toolStrip1"; + toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { btnBack, btnForward, btnHome, toolStripSeparator1, btnFavourites, btnCatalogues, btnCohorts, btnSavedCohorts, btnDataExport, toolStripSeparator, btnTables, btnLoads, btnDataSets, toolStripSeparator2, toolStripLabel2, cbxLayouts, btnSaveWindowLayout, btnDeleteLayout, toolStripSeparator4, cbCommits, toolStripSeparator3 }); + toolStrip1.Location = new System.Drawing.Point(0, 0); + toolStrip1.Name = "toolStrip1"; + toolStrip1.Size = new System.Drawing.Size(1539, 25); + toolStrip1.TabIndex = 0; + toolStrip1.Text = "toolStrip1"; // // btnBack // - this.btnBack.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.btnBack.Enabled = false; - this.btnBack.Image = ((System.Drawing.Image)(resources.GetObject("btnBack.Image"))); - this.btnBack.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnBack.Name = "btnBack"; - this.btnBack.Size = new System.Drawing.Size(32, 22); - this.btnBack.Text = "Back"; - this.btnBack.ButtonClick += new System.EventHandler(this.btnBack_ButtonClick); - this.btnBack.DropDownOpening += new System.EventHandler(this.btnBack_DropDownOpening); + btnBack.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + btnBack.Enabled = false; + btnBack.Image = (System.Drawing.Image)resources.GetObject("btnBack.Image"); + btnBack.ImageTransparentColor = System.Drawing.Color.Magenta; + btnBack.Name = "btnBack"; + btnBack.Size = new System.Drawing.Size(32, 22); + btnBack.Text = "Back"; + btnBack.ButtonClick += btnBack_ButtonClick; + btnBack.DropDownOpening += btnBack_DropDownOpening; // // btnForward // - this.btnForward.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.btnForward.Enabled = false; - this.btnForward.Image = ((System.Drawing.Image)(resources.GetObject("btnForward.Image"))); - this.btnForward.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnForward.Name = "btnForward"; - this.btnForward.Size = new System.Drawing.Size(23, 22); - this.btnForward.Text = "Forward"; - this.btnForward.Click += new System.EventHandler(this.btnForward_Click); + btnForward.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + btnForward.Enabled = false; + btnForward.Image = (System.Drawing.Image)resources.GetObject("btnForward.Image"); + btnForward.ImageTransparentColor = System.Drawing.Color.Magenta; + btnForward.Name = "btnForward"; + btnForward.Size = new System.Drawing.Size(23, 22); + btnForward.Text = "Forward"; + btnForward.Click += btnForward_Click; // // btnFavourites // - this.btnFavourites.Image = ((System.Drawing.Image)(resources.GetObject("btnFavourites.Image"))); - this.btnFavourites.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnFavourites.Name = "btnFavourites"; - this.btnFavourites.Size = new System.Drawing.Size(81, 22); - this.btnFavourites.Text = "Favourites"; - this.btnFavourites.Click += new System.EventHandler(this.ToolboxButtonClicked); + btnFavourites.Image = (System.Drawing.Image)resources.GetObject("btnFavourites.Image"); + btnFavourites.ImageTransparentColor = System.Drawing.Color.Magenta; + btnFavourites.Name = "btnFavourites"; + btnFavourites.Size = new System.Drawing.Size(81, 22); + btnFavourites.Text = "Favourites"; + btnFavourites.Click += ToolboxButtonClicked; // // btnSavedCohorts // - this.btnSavedCohorts.Image = ((System.Drawing.Image)(resources.GetObject("btnSavedCohorts.Image"))); - this.btnSavedCohorts.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnSavedCohorts.Name = "btnSavedCohorts"; - this.btnSavedCohorts.Size = new System.Drawing.Size(103, 22); - this.btnSavedCohorts.Text = "Saved Cohorts"; - this.btnSavedCohorts.Click += new System.EventHandler(this.ToolboxButtonClicked); + btnSavedCohorts.Image = (System.Drawing.Image)resources.GetObject("btnSavedCohorts.Image"); + btnSavedCohorts.ImageTransparentColor = System.Drawing.Color.Magenta; + btnSavedCohorts.Name = "btnSavedCohorts"; + btnSavedCohorts.Size = new System.Drawing.Size(103, 22); + btnSavedCohorts.Text = "Saved Cohorts"; + btnSavedCohorts.Click += ToolboxButtonClicked; + // + // btnLoads + // + btnLoads.Image = (System.Drawing.Image)resources.GetObject("btnLoads.Image"); + btnLoads.ImageTransparentColor = System.Drawing.Color.Magenta; + btnLoads.Name = "btnLoads"; + btnLoads.Size = new System.Drawing.Size(80, 22); + btnLoads.Text = "Data Load"; + btnLoads.Click += ToolboxButtonClicked; // // toolStripLabel2 // - this.toolStripLabel2.Name = "toolStripLabel2"; - this.toolStripLabel2.Size = new System.Drawing.Size(43, 22); - this.toolStripLabel2.Text = "Layout"; + toolStripLabel2.Name = "toolStripLabel2"; + toolStripLabel2.Size = new System.Drawing.Size(43, 22); + toolStripLabel2.Text = "Layout"; // // cbxLayouts // - this.cbxLayouts.Name = "cbxLayouts"; - this.cbxLayouts.Size = new System.Drawing.Size(174, 25); - this.cbxLayouts.DropDownClosed += new System.EventHandler(this.cbx_DropDownClosed); - this.cbxLayouts.SelectedIndexChanged += new System.EventHandler(this.cbx_SelectedIndexChanged); + cbxLayouts.Name = "cbxLayouts"; + cbxLayouts.Size = new System.Drawing.Size(174, 25); + cbxLayouts.DropDownClosed += cbx_DropDownClosed; + cbxLayouts.SelectedIndexChanged += cbx_SelectedIndexChanged; // // btnSaveWindowLayout // - this.btnSaveWindowLayout.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.btnSaveWindowLayout.Enabled = false; - this.btnSaveWindowLayout.Image = ((System.Drawing.Image)(resources.GetObject("btnSaveWindowLayout.Image"))); - this.btnSaveWindowLayout.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnSaveWindowLayout.Name = "btnSaveWindowLayout"; - this.btnSaveWindowLayout.Size = new System.Drawing.Size(23, 22); - this.btnSaveWindowLayout.Text = "Save Window Layout"; - this.btnSaveWindowLayout.Click += new System.EventHandler(this.btnSaveWindowLayout_Click); + btnSaveWindowLayout.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + btnSaveWindowLayout.Enabled = false; + btnSaveWindowLayout.Image = (System.Drawing.Image)resources.GetObject("btnSaveWindowLayout.Image"); + btnSaveWindowLayout.ImageTransparentColor = System.Drawing.Color.Magenta; + btnSaveWindowLayout.Name = "btnSaveWindowLayout"; + btnSaveWindowLayout.Size = new System.Drawing.Size(23, 22); + btnSaveWindowLayout.Text = "Save Window Layout"; + btnSaveWindowLayout.Click += btnSaveWindowLayout_Click; // // btnDeleteLayout // - this.btnDeleteLayout.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.btnDeleteLayout.Enabled = false; - this.btnDeleteLayout.Image = ((System.Drawing.Image)(resources.GetObject("btnDeleteLayout.Image"))); - this.btnDeleteLayout.ImageTransparentColor = System.Drawing.Color.Magenta; - this.btnDeleteLayout.Name = "btnDeleteLayout"; - this.btnDeleteLayout.Size = new System.Drawing.Size(23, 22); - this.btnDeleteLayout.Text = "Delete Layout"; - this.btnDeleteLayout.Click += new System.EventHandler(this.btnDelete_Click); + btnDeleteLayout.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + btnDeleteLayout.Enabled = false; + btnDeleteLayout.Image = (System.Drawing.Image)resources.GetObject("btnDeleteLayout.Image"); + btnDeleteLayout.ImageTransparentColor = System.Drawing.Color.Magenta; + btnDeleteLayout.Name = "btnDeleteLayout"; + btnDeleteLayout.Size = new System.Drawing.Size(23, 22); + btnDeleteLayout.Text = "Delete Layout"; + btnDeleteLayout.Click += btnDelete_Click; // // toolStripSeparator4 // - this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size(6, 25); + toolStripSeparator4.Name = "toolStripSeparator4"; + toolStripSeparator4.Size = new System.Drawing.Size(6, 25); // // cbCommits // - this.cbCommits.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.cbCommits.Image = ((System.Drawing.Image)(resources.GetObject("cbCommits.Image"))); - this.cbCommits.ImageTransparentColor = System.Drawing.Color.Magenta; - this.cbCommits.Name = "cbCommits"; - this.cbCommits.Size = new System.Drawing.Size(23, 22); - this.cbCommits.Text = "Use Commits"; + cbCommits.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + cbCommits.Image = (System.Drawing.Image)resources.GetObject("cbCommits.Image"); + cbCommits.ImageTransparentColor = System.Drawing.Color.Magenta; + cbCommits.Name = "cbCommits"; + cbCommits.Size = new System.Drawing.Size(23, 22); + cbCommits.Text = "Use Commits"; // // toolStripSeparator3 // - this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size(6, 25); + toolStripSeparator3.Name = "toolStripSeparator3"; + toolStripSeparator3.Size = new System.Drawing.Size(6, 25); // // RDMPTaskBarUI // - this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.toolStrip1); - this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.Name = "RDMPTaskBarUI"; - this.Size = new System.Drawing.Size(1539, 29); - this.toolStrip1.ResumeLayout(false); - this.toolStrip1.PerformLayout(); - this.ResumeLayout(false); - this.PerformLayout(); - + AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + Controls.Add(toolStrip1); + Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + Name = "RDMPTaskBarUI"; + Size = new System.Drawing.Size(1539, 29); + toolStrip1.ResumeLayout(false); + toolStrip1.PerformLayout(); + ResumeLayout(false); + PerformLayout(); } #endregion @@ -270,7 +259,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripButton btnCohorts; private System.Windows.Forms.ToolStripButton btnDataExport; private System.Windows.Forms.ToolStripButton btnTables; - private System.Windows.Forms.ToolStripButton btnLoad; + private System.Windows.Forms.ToolStripButton btnDataSets; private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; private System.Windows.Forms.ToolStripSeparator toolStripSeparator; private System.Windows.Forms.ToolStrip toolStrip1; @@ -285,5 +274,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; private System.Windows.Forms.ToolStripButton cbCommits; private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; + private System.Windows.Forms.ToolStripButton btnLoads; } } diff --git a/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.cs b/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.cs index 6639022c8a..d79e7e9645 100644 --- a/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.cs +++ b/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.cs @@ -51,8 +51,11 @@ public RDMPTaskBarUI() btnTables.Image = CatalogueIcons.TableInfo.ImageToBitmap(); btnTables.BackgroundImage = BackColorProvider.GetBackgroundImage(btnTables.Size, RDMPCollection.Tables); - btnLoad.Image = CatalogueIcons.LoadMetadata.ImageToBitmap(); - btnLoad.BackgroundImage = BackColorProvider.GetBackgroundImage(btnLoad.Size, RDMPCollection.DataLoad); + btnDataSets.Image = CatalogueIcons.Dataset.ImageToBitmap(); + btnDataSets.BackgroundImage = BackColorProvider.GetBackgroundImage(btnDataSets.Size, RDMPCollection.Datasets); + + btnLoads.Image = CatalogueIcons.LoadMetadata.ImageToBitmap(); + btnLoads.BackgroundImage = BackColorProvider.GetBackgroundImage(btnDataSets.Size, RDMPCollection.DataLoad); btnFavourites.Image = CatalogueIcons.Favourite.ImageToBitmap(); btnDeleteLayout.Image = FamFamFamIcons.delete.ImageToBitmap(); @@ -106,8 +109,9 @@ private void SetupToolTipText() btnSavedCohorts.ToolTipText = "Finalised identifier lists, ready for linkage and extraction"; btnDataExport.ToolTipText = "Show Projects and Extractable Dataset Packages allowing data extraction"; btnTables.ToolTipText = "Advanced features e.g. logging, credentials, dashboards etc"; - btnLoad.ToolTipText = "Load configurations for reading data into your databases"; + btnLoads.ToolTipText = "Load configurations for reading data into your databases"; btnFavourites.ToolTipText = "Collection of all objects that you have favourited"; + btnDataSets.ToolTipText = "All external datasets that have been configured for use in RDMP"; } catch (Exception e) { @@ -180,12 +184,14 @@ private RDMPCollection ButtonToEnum(object button) collectionToToggle = RDMPCollection.DataExport; else if (button == btnTables) collectionToToggle = RDMPCollection.Tables; - else if (button == btnLoad) + else if (button == btnLoads) collectionToToggle = RDMPCollection.DataLoad; else if (button == btnSavedCohorts) collectionToToggle = RDMPCollection.SavedCohorts; else if (button == btnFavourites) collectionToToggle = RDMPCollection.Favourites; + else if (button == btnDataSets) + collectionToToggle = RDMPCollection.Datasets; else throw new ArgumentOutOfRangeException(nameof(button)); diff --git a/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.resx b/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.resx index 9c79f1917c..46a8e47b5d 100644 --- a/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.resx +++ b/Application/ResearchDataManagementPlatform/WindowManagement/TopBar/RDMPTaskBarUI.resx @@ -1,4 +1,64 @@ - + + + @@ -118,7 +178,7 @@ TgDQASA1MVpwzwAAAABJRU5ErkJggg== - + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG @@ -192,54 +252,69 @@ mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D TgDQASA1MVpwzwAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 + 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw + bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc + VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 + c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 + Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo + mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ + kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D + TgDQASA1MVpwzwAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAARGSURBVDhPhZTZU5pXGIe56H/TaS8SRZRpnV73pred6UzT - aIwLAZdo3Dqm1kxS25hoNS4EAorFDRU3VDaHGhMKdSGo4AKyi7KFTWT79XzoRW9qv5lnzplzzjznfd/v - nUPLr1TUMdmqzkK2aqmQrbTkc5Yit8sWU0z2YraIrUQRW4GiBwowyfzLahWKa1RkVOILjiLGrJFbi2tW - BfSK5a+K29Sf0JgcVY9I5dqWvfMEl7b8F3qjJ63ZcWd15gDe7vqxtnOOte1zrH/wQWsK5NAYfFBsOtIz - Sne8Y2zP8U2bZoxeIfuaRqLSzP3pCi1tRqA9jIP6grEkpjR2OH0XCF9kEI5nkEhmkc4CiVQW/kgaTn8S - 29Yo5rRetIn3AyRCDS2frXLNqr2XPGUA09qPSGYAy2kMnF49diwhBKNphGJpxC8zOfyRFGznl7B4E5Bt - BjH9zgeR0k7SloNWWK6MSt7a0pRM8j6EaCKDA1cUta/+xtZxCKF4Ord2QW4Jk7krkCSXJXIIVWfoWXCD - t3wCRtVslnaLFHtYfpJ9rfRjYiMIfzQFkzOKJ6JdGE/CiOREWcTIeB5Oweq9xJHnAseUTH2GzmkHuiSH - YFTKSGTsheyYxgOuwg+RJgDrWQKH5PCeI0rqcokAkYdiKXhDVETUegxGeyw38hWneDZlQ+eEGQUVi5RM - gT/WPOCTNJsER2jhbaOVb0CbwICfRz7gyagRHSIjHgsNaOXtoPn1Npquqefu4dmkFU/F+ygoXyAy0kOj - apK3woeHfCs4g2ZUD5lRwzWj7praIROqB01g9+/hAYH1ahdVfUawB0x4Om7JXUa/P38lG1G5wF09Q+Ow - Ay0iJ8GB1mtaRuxoJjQN2/BIYEXDGyvq+RbU8Y5Qyz1Eh/gIjwU7oJdJiYylgFDhwuDKGRoEdjwS2tEo - tF1BBA2CE9QTwcOc4JgIjkjkB+AMkAxItD+JzCT9TeTfm7mS8Vcd6Jd50T7mJL/aQzjF79d0z3vwUurG - i1kXumadeD7jwG8SG36dOkGz4AA/CvfQOKRDfuk0JZODt+LICSQbAdJTKZxHwjdyRogmkhCvudHANaC+ - X4u80inQmKRmXJkjF8GcNgxb8ACD2iYMaBv/E2qfOjepOUXtwBZqezeQVzJJZKQ1hpbseDnngVQbgifs - xpxxFNIboPapc+NrLlT36cHpXkfe3XHQqCdmYNGOLlIX6fuPsActEOh+wZsboPapc2LSBazuv8Dq0uD2 - 3TFSs3J59MWiOc2Xe6ExRuCLOyE74P0PfPgvXJhdd5EUtSh5rs7c/kFwSWOw5Lp2odnVN2+KT6qPM3ry - junNIehyBKEzUQT+hR+6fT/0Jh96JQaUt8uy37Utx299P+ag0StXehislSkGa9lML1lJFFUto7BKRlhC - YeUCGBXzYJRLUXB/BgVl04QpFNybBL10IlenT78VJz+7I3Z/fke88Q92NlVRGjmKRQAAAABJRU5ErkJg - gg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAARISURBVDhPhZTZU5pXGIe56D/Ti3baRhF1WqfXveldbzrT + mJrEhYBLNG4dbWomqa02Wo0LgUDEggu4i8qiQ40JxboFFVxAlk8E2cK+/3o+4kVvar+ZZ86Zc848533f + 753DyK9U1RVzNJ2FHM1iIUdtzufOhz4tm0sVc+ayRRw1ijgqFN1ToZjMv6jWoKRGQ0Y1PueqIsU1SktJ + zYqQWbH0ZUnb6geMYq6mV6yhdhSvnf75bW9s00Cl17YdWb3Jh1f7XqztXmJt5xLrbz3QGX05tHseqLas + 6SnlebRDemD/uk0rZVYovmKQqLSzf1KBxa0QdMdR0J8/ksSk1gaHJ4ZgLINgNIN4Mot0FoinsvCG0nB4 + k9ixhDGrc6FNcugjEWoZ+RwNNb3qSvDVPsh175DMAOaLCLh9m9g1B+APpxGIpBFNZHJ4QylYLxMwu+JQ + bPkhf+2BWG0jaSvBKCxXh2WvLGlaJnsTQDiewREVRu2zv7F9GkAgms6txcgtQTKnfElyWTyHSONG7/w5 + +EtnYFXJs4xPSLGFy+bsc7UX4xt+eMMpGB1hPBLvw3AWRCgnyiJCxstgChZXAifOGE5p2aobnXI7umXH + YFUqSGSc2axU6wRP5YVY64PFHccxOXxgD5O6JOAj8kAkBVeAjohej8Bgi+RGgeoCTyat6Bw3oaBigZap + 8MeaEwKSZpPwBC38HbQK9tAm3MNPI2/xaNSADrEB7aI9tPJ30fx8B01X1PMO8GTCgseSQxSUzxMZ6aHR + VZK3yoP7Agu4QyZUD5tQwzOh7oraYSOqh4zgDBzgHoH9bB9V/QZwBo14PGbOXca8O/deNqKhwFtxo/Gl + HS1iB8GO1itaRmxoJjS9tOKB0IKGFxbUC8yo45+glneMDskJ2oW7YN6ZITK2CiIVhaFlNxqENjwQ2dAo + sr6HCBqEZ6gngvs5wSkRnJDIj8AdJBmQaH8Um0j6W8i/PfVeJlixY0DhwkOpg/xqJ+ECv1/RM+fE05lz + /DZNoXvaga4pO36VWfHL5BmahUf4QXSAxmE98svktEwJ/rI9J5Bt+EhPpXAZCl6LmxCOJyFZO0cDbw/1 + AzrklU2CUUxqxlPYcxHM6oKw+o8wpGvCoK7xP6H36XMT2gvUDm6jtm8Ded9PEBlpjeFFG57OOjGjC8AZ + PMesYRQz10Dv0+fG1ihU92+C27OOvFtjYNBPzOCCDd2kLjNv3sHmN0Oo/xkvroHep89JSBewe/4Cu1uL + G7ekpGblynDXwmFaoHRBawjBE3VAccT/HwTwxihMr1MkRR1Ku1YzN0oFCQaLrdQ/FJmo/rmD6MTqcWaT + vGObpgD0OfzQG2l8/8IL/aEXm0YP+mR7KG9fyH7bthT97DupncGsXO5lsZcnWewlE7N0OV5UtYTCKgVh + EYWV82BVzIFVPoOCu1MouCMnTKLg9gSYZeO5On34jST50U3J+cc3JRv/AJ4BVRHR/DhKAAAAAElFTkSu + QmCC iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAQPSURBVDhPjVTrT1tlHK5Ztq/wH0D84JSpfJhLzMxCzJZt - 0HIr64WWlo5bKXcx5TbWwpQNylUWkeJlg7mxkGVELTAL2DGpwqwFE5DJBDaQFQqFw/X0gPj4vm3ZJaLx - SZ6cvOec9znPeX6/38vbC+DxXoJItM+WkrJ/RCQ6sEu6pvfpc9+r/w26YUqdHfhIrZZPqJONDxNVpgdn - leYxlcL0QCU1jiTEysfiJYH0Pd+WvTGVne3/KDVVMJWR3uL4UG+f/aKJ+ePmlzuu1muYbm7ama3VMxNp - KvsvypgWmyxKMBQf6e/b+iIm8vP9HiepxdM5Oeb5mipu/Zt2cH1mbH9/B9uWr7F15xY2b1+Dq6ESk2nJ - 3LBSaB6UholtohN+PgkvaA7U0QwRclZVgrWY8ef9PrhNrWCb6+BuuoitzwzYbm3EdscNMJcvYTxdiZ9l - fLNVclLQRvZ7hUiYk2lpAVOpqc3zFZc41txBhO6C+7wSq/V6rNQUYaO2CO7683DTa00B2JuNWCgvxmhi - GNcvDGm2Ct8N8BTF44qE7SjU2ldvXMW2tRvclWqw9TowhjyslWVh84OM55iOdZ0G7JWP8LgwHT/x37H3 - nTkm97ijVaFVm60zMGz7dbjbPsVKRR6WNHFYTJbClSTBUpL4GZMlWNWexUaNHq6yYoxoZIwl+m2jLeXw - fh7tn3F1YqerqR5bt6+CvVyClTod3P0WcIM/eOj2kbv/I9z3vsPSe0lYzlSRj5bi93OZ6I040tkmCjrg - FUtS9LgaarF1vQHsxWxsfFyKvzY3sBd21tawmJ0Mp0LoEZsofR/d4cE9T8V+VcV1Og0XwBoNYGku5blg - 7/XCPWAl7H/GQSvYuz1Y0CixkCLHUpke44VpMPPf9DqjmY2q5MaZrExmpVqPzeoirGTGwikPx7yE/w/O - UcoisXxeC0dJPoYVAqYr9JDRdphkRqvgGRER3+4ozsX6J1VgNDIStJAIRmA+loj6OEf4RBoOh1JMWqYC - v2kT0csPtneeDiLV5O3z9NlogjBgSBHVPK6Wc84LBVhrrIaLVNIZF4V5WcRTkSdiARzyM2BqDJguyIFF - EsJ1nTrYbAp7zdtnFNSdTUFmTRZhHiMiczotadhKLJPfcKYqiUAM5hIVcBVrwVSWYyYvCwPS4zQrc0fo - q2QCiKvnYROJ/Aalp8Q28WnzoPIkN5mvgbOkEEulxXDpzmGR0KHLw1huAiz8EI4KfRX2irj7xMsvzuYu - huJD/K2S44L+mGMtA1FH7SMpUmY4I37nYVEWhjRxOzTsXv7rJKODLdRRe2Tw3qfGLmgnWyJDAvuij8p7 - oo8YeyLfMlEX34a+YeoSHDJ28oPkJKdAT/X+D2iYnhyJMO2fXXrX/3bS8nh/A6xV4ATwatd3AAAAAElF + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAQPSURBVDhPjVTrT1NnHO5i9Cv8B5B9mJtu44MzWVwMWSQT + aLkVe6GlpXIrLXIZS7mJLbihUK7DjFF20eIUQ4xkWwFXYBVHJ7haXALD4bgIwUKhUK6nB8aevW9bvGRs + 2ZM8OXnPOe9znvP8fr+XsxfA4bwCgWCfLT19/7BAcGCXdE3v0+f+V/8bdMOkMid4SqmUjivTDI9TFKZH + p+XmUYXM9EghNgwnJ0hHk0TB9D3/lr0xmZMTOJWRwZs8k9ni+ERnn/262T1945sdV+tVTBmbd2brdO5x + tcL+qzy+xSaJ5Q0lxQT6t76M8YKCgCepSuF0bq55vraaXf++HWyfGds/3ca25Tts3b6JzVtX4WqswoQ6 + jX0o55sHxZFCmyAswC/hA82BOpohQs7qKjAWM/683wePqRWMsR6e5gvY+lKP7dYmbHdch/vSRYxlyvFA + wjVbRR/w2sh+nxAJc0KtDprMyDDOV15kGXMHEboD9qsqrDbosFJbjI26YngazsFDr7WFYG40YaGiBCMp + 4Ww/P9Ro5b8f5C2K1xUJ21Gksa9ev4JtazfYyzVgGrRw6/OxVp6NzY/PvMBMrGtVYC5/iidFmfiF+569 + 79RxqdcdrQqt2my93s20X4On7QusVOZjSZWIxTQxXKkiLKUKnzNNhFXNaWzU6uAqL8GwSuK2xL1rsKUf + 2c+h/TOmTOl0NTdg69YVMJdKsVKvhaffAnbwZy89frL378Fz90csfZiK5SwF+WgZ/jibhd7oo51tgkMH + fGKpsh5XYx22rjWCuZCDjc/K8NfmBvbCztoaFnPS4JTxvWLjZR+hOyqk55nYb4rETqf+PBiDHgzNpSIP + zN1eeAashP3POWgFc6cHCyo5FtKlWCrXYaxIDTP3bZ8zmtmIQmqYyc5yr9TosFlTjJWsBDilUZgXcf/B + OUpJDJbPaeAoLcBDGc/dFXHYYDtCMqNV8I6IgGt3lORh/fNquFUSEjSfCEZjPoGI+jlH+FQcBYdcSFqm + Er9rUtDLDbF3hh8i1eTs8/bZSDI/aEgWaxxTSlnn+UKsNdXARSrpTIzFvCT6mchTIQ8O6Sm4a/WYLsyF + RRTKdp08aDRFvuHrMwrqziYjsyaJNo8SkTmthjRsFZbJbzgz5EQgHnMpMrhKNHBXVWAmPxsD4hM0K3NH + xOtkAoirF2ETCAIGxSeFNmG4+Z48jJ0oUMFZWoSlshK4tGexSOjQ5mM0LxmWiFCWCn0b+ZqwO+zVl2dz + F0NJoYFW0Qlef/zxloHYY/bhdLHbrpbtPC7OxgOlZIeG3ct9k2R0sIU6ao8J2fvU2AXtZEtMaHBf3DFp + T9xRQ0/MOybq4oeIt0xdvMOGTu4hKckp2Fu9/wMapjdHIkz7Z5e+9b+dtBzO34EH3+wnRbZyAAAAAElF TkSuQmCC diff --git a/Application/ResearchDataManagementPlatform/WindowManagement/WindowManager.cs b/Application/ResearchDataManagementPlatform/WindowManagement/WindowManager.cs index dd49fcaad6..406e858db8 100644 --- a/Application/ResearchDataManagementPlatform/WindowManagement/WindowManager.cs +++ b/Application/ResearchDataManagementPlatform/WindowManagement/WindowManager.cs @@ -148,6 +148,12 @@ public PersistableToolboxDockContent Create(RDMPCollection collectionToCreate, Image.Load(CatalogueIcons.Favourite)); break; + case RDMPCollection.Datasets: + collection = new DatasetsCollectionUI(); + toReturn = Show(RDMPCollection.Datasets, collection, "Datasets", + Image.Load(CatalogueIcons.Dataset)); + break; + default: throw new ArgumentOutOfRangeException(nameof(collectionToCreate)); } diff --git a/CHANGELOG.md b/CHANGELOG.md index 7100a239d3..fbe0fdbfed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -... +### Changed + +- Add command to dump current platform DB to directory + +## [8.1.1] - 2023-12-01 + +### Changed + +- Improved file transfer (FTP/SFTP/FTPS) support +- Improved Plugin Bundling +- Add ability to bundle UI notifications from plugin pipeline components +- Add ability to use .bak files as data load ## [8.1.0] - 2023-09-19 diff --git a/Documentation/CodeTutorials/Coding.md b/Documentation/CodeTutorials/Coding.md index f7511d05c7..f4951ee4c2 100644 --- a/Documentation/CodeTutorials/Coding.md +++ b/Documentation/CodeTutorials/Coding.md @@ -94,7 +94,7 @@ Each area of the RDMP codebase has its own documentation. These include: - [Creating Right Click Context Menus](./CreatingANewRightClickMenu.md) - [Double Click / Drag and drop](./DoubleClickAndDragDrop.md) - [Writing Plugins](./PluginWriting.md) -- [Cohort Creation](./../../Rdmp.Core/CohortCreation/Readme.md) +- [Cohort Creation](./../../Rdmp.Core/CohortCreation/CohortCreation.md) - [Command Line Interface (CLI)](./../../Rdmp.Core/CommandLine/Runners/ExecuteCommandRunner.md) RDMP has over 20 class diagrams which you can open if you have visual studio. These files end in the extension `.cd` diff --git a/Documentation/CodeTutorials/FAQ.md b/Documentation/CodeTutorials/FAQ.md index 38323d54bd..fda1e96817 100644 --- a/Documentation/CodeTutorials/FAQ.md +++ b/Documentation/CodeTutorials/FAQ.md @@ -334,12 +334,12 @@ Since each section is runnable independently it is trivially easy for RDMP to pr ![Cohort Builder Tree](./Images/CohortBuilderUI.png) -For full details on technical implementation see [Cohort Creation](../../Rdmp.Core/CohortCreation/Readme.md). +For full details on technical implementation see [Cohort Creation](../../Rdmp.Core/CohortCreation/CohortCreation.md). ## Does the Cohort Builder support Excel, CSV files etc? -Yes. If a cohort is solely defined by the contents of such a file it can be [committed directly to the cohort store](../../Rdmp.Core/CohortCommitting/Readme.md). +Yes. If a cohort is solely defined by the contents of such a file it can be [committed directly to the cohort store](../../Rdmp.Core/CohortCommitting/CohortCommitting.md). If you need to combine data in the file (or multiple files) with data in your database then the first step is to create a new Catalogue by uploading the data into your database. This has a number of advantages: @@ -834,7 +834,7 @@ RDMP also supports creating the audit logging database in other [DBMS] types (e. ### System Logs System logs can be enabled for RDMP. These are low level logs designed to be read by a software developer or IT specialist. To enable -this feature, locate the `NLog.template.config` file in your RDMP install directory. Rename the file `NLog.config` (i.e. remove the word template). +this feature, download [NLog.config](https://raw.githubusercontent.com/HicServices/RDMP/main/Tools/rdmp/NLog.config) to your RDMP install. This template generates file logs to a `./logs/` sub-directory. You can adjust it to log anywhere including to databases/central server etc by [following the NLog targets guide](https://nlog-project.org/config/). **Logs may contain identifiable or sensitive information so should be secured appropriately if enabled**. @@ -891,7 +891,7 @@ var catalogues = repository.GetAllObjects(); var catalogueItems = repository.GetAllObjects(); ``` -If you think the problem is more widespread then you can also use the [`IInjectKnown`](./../../Reusable/MapsDirectlyToDatabaseTable/Injection/README.md) system to perform `Lazy` loads which prevents repeated calls to the same property going back to the database every time. +If you think the problem is more widespread then you can also use the [`IInjectKnown`](./../../Rdmp.Core/MapsDirectlyToDatabaseTable/Injection/Injection.md) system to perform `Lazy` loads which prevents repeated calls to the same property going back to the database every time. @@ -904,9 +904,9 @@ Yes there are over 1,000 unit and integration tests, this is covered in [Tests]( [hic_dataLoadRunID]: #hic_dataLoadRunID [Data Load Engine]: #data-load-engine [db_executor]: https://www.sqlmatters.com/Articles/Adding%20a%20db_executor%20role.aspx -[cohort databases]: ../../Rdmp.Core/CohortCommitting/Readme.md -[cohort database]: ../../Rdmp.Core/CohortCommitting/Readme.md -[query cache]: ../../Rdmp.Core/CohortCreation/Readme.md +[cohort databases]: ../../Rdmp.Core/CohortCommitting/CohortCommitting.md +[cohort database]: ../../Rdmp.Core/CohortCommitting/CohortCommitting.md +[query cache]: ../../Rdmp.Core/CohortCreation/CohortCreation.md [UNION]: ./Glossary.md#UNION [EXCEPT]: ./Glossary.md#EXCEPT [INTERSECT]: ./Glossary.md#INTERSECT diff --git a/Documentation/CodeTutorials/Graphs.md b/Documentation/CodeTutorials/Graphs.md index d1cc516dd4..e1a6336a78 100644 --- a/Documentation/CodeTutorials/Graphs.md +++ b/Documentation/CodeTutorials/Graphs.md @@ -41,7 +41,7 @@ This will take you to the 'Edit' page where you can specify which dimensions to The RDMP graphing engine supports Bar and Plot graphs. Not all [DBMS] implement all graph types. The following table shows what is implemented: -| Graph Type | [Sql Server](https://github.com/HicServices/FAnsiSql/blob/main/Implementations/FAnsi.Implementations.MicrosoftSQL/README.md) | [MySql](https://github.com/HicServices/FAnsiSql/blob/main/Implementations/FAnsi.Implementations.MySql/README.md) | [Postgres](https://github.com/HicServices/FAnsiSql/blob/main/Implementations/FAnsi.Implementations.PostgreSql/README.md) | [Oracle](https://github.com/HicServices/FAnsiSql/blob/main/Implementations/FAnsi.Implementations.Oracle/README.md) | +| Graph Type | [Sql Server](https://github.com/HicServices/FAnsiSql/blob/main/FAnsiSql/Implementations/MicrosoftSQL/README.md) | [MySql](https://github.com/HicServices/FAnsiSql/blob/main/FAnsiSql/Implementations/MySql/README.md) | [Postgres](https://github.com/HicServices/FAnsiSql/blob/main/FAnsiSql/Implementations/PostgreSql/README.md) | [Oracle](https://github.com/HicServices/FAnsiSql/blob/main/FAnsiSql/Implementations/Oracle/README.md) | |----|---|----|---|---| | [Bar 1 Dimension](#bar-1-dimension) | yes | yes | yes | yes | | [Bar 2 Dimensions](#bar-2-dimensions) | yes | yes | no | yes | @@ -119,7 +119,7 @@ _Applying a TOP to PIVOT graphs limits the number of series in the PIVOT_ One of the core strengths of the RDMP graphing system is the ability to run graphs on Filters, Cohorts and/or [ExtractionConfiguration] datasets. This lets you rapidly confirm that the cohort you are building does not have data holes or missing trends. -To graph a cohort right click it and go to Graph. Make sure you have set up a [cohort caching database](../../Rdmp.Core/CohortCreation/Readme.md). +To graph a cohort right click it and go to Graph. Make sure you have set up a [cohort caching database](../../Rdmp.Core/CohortCreation/CohortCreation.md). ![Right clicking a cohort set in a CohortIdentificationConfiguration and graphing it](Images/Graphs/GraphCohort.png) diff --git a/Documentation/CodeTutorials/Packages.md b/Documentation/CodeTutorials/Packages.md index 4bad44d302..012f38744a 100644 --- a/Documentation/CodeTutorials/Packages.md +++ b/Documentation/CodeTutorials/Packages.md @@ -10,6 +10,7 @@ | Package | Source Code | License | Purpose | Additional Risk Assessment | | ------- | ------------| ------- | ------- | -------------------------- | | Equ | [GitHub](https://github.com/thedmi/Equ) | [MIT](https://opensource.org/licenses/MIT) | Simplifies object equality implementation | | +| FluentFTP | [Github](https://github.com/robinrodricks/FluentFTP/) | [MIT](https://opensource.org/licenses/MIT) | FTP(S) client | | | MongoDB.Driver | [GitHub](https://github.com/mongodb/mongo-csharp-driver) | [Apache 2.0](https://opensource.org/licenses/Apache-2.0) | Database driver for MongoDB | | | Microsoft.SourceLink.GitHub | [GitHub](https://github.com/dotnet/sourcelink) | [MIT](https://opensource.org/licenses/MIT) | Enable source linkage from nupkg | Official MS project | | Microsoft.XmlSerializer.Generator | [Microsoft](https://learn.microsoft.com/en-us/dotnet/core/additional-tools/xml-serializer-generator) | [MIT](https://opensource.org/licenses/MIT) | XML handling improvements | @@ -31,21 +32,9 @@ | Moq 4 | [GitHub](https://github.com/moq/moq4) |[BSD 3](https://github.com/moq/moq4/blob/master/License.txt) | Mock objects during unit testing | | [Newtonsoft.Json](https://www.newtonsoft.com/json) | [GitHub](https://github.com/JamesNK/Newtonsoft.Json) | [MIT](https://opensource.org/licenses/MIT) | Serialization of objects for sharing/transmission | | YamlDotNet | [GitHub](https://github.com/aaubry/YamlDotNet) | [MIT](https://opensource.org/licenses/MIT) |Loading configuration files| -| [SecurityCodeScan.VS2019](https://security-code-scan.github.io/) | [GitHub](https://github.com/security-code-scan/security-code-scan) | [GPL 3.0](https://www.gnu.org/licenses/gpl-3.0.html)| Performs static build time analysis for vulnerabilities in the codebase (e.g. Sql injection)| | | SixLabors.ImageSharp | [GitHub](https://github.com/SixLabors/ImageSharp) | [Apache 2.0](https://github.com/SixLabors/ImageSharp/blob/main/LICENSE) | Platform-independent replacement for legacy Windows-only System.Drawing.Common | | | SixLabors.ImageSharp.Drawing | [GitHub](https://github.com/SixLabors/ImageSharp.Drawing) | [Apache 2.0](https://github.com/SixLabors/ImageSharp/blob/main/LICENSE) | Font handling for ImageSharp | | -| System.Runtime.Loader | [GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Allows loading assemblies in dot net core| | -| System.Diagnostics.Debug | [GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Interact with Processes / Debug / Console | | -| System.IO.FileSystem.Primitives | [GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Provides common enumerations and exceptions for path-based I/O libraries | | -| System.IO.FileSystem | [GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Provides types that allow reading and writing to files | | -| System.Runtime.Extensions | [GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Provides commonly-used classes for performing mathematical functions, conversions, string comparisons etc | | -| System.Threading | [GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Provides the fundamental synchronization primitives | | -| System.Threading.AccessControl | [GitHub](https://github.com/dotnet/runtime) |[MIT](https://opensource.org/licenses/MIT) | Required by Scintilla for sync primitives | | | System.Threading.ThreadPool | [GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Required to compile native linux binaries | | -| System.Globalization | [GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Provides classes that define culture-related information | | -| System.Net.NameResolution | [GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Provides the System.Net.Dns class, which enables developers to perform simple domain name resolution | | -| System.Net.Primitives | [GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Provides common types for network-based libraries | | -| System.Security.Permissions |[GitHub](https://github.com/dotnet/corefx) |[MIT](https://opensource.org/licenses/MIT) | Provides common types for Xml doc reading in UI code | | | [AutoComplete Console](https://www.codeproject.com/Articles/1182358/Using-Autocomplete-in-Windows-Console-Applications) by Jasper Lammers | Embedded | [CPOL](https://www.codeproject.com/info/cpol10.aspx) | Provides interactive autocomplete in console input | | | System.Resources.Extensions | [GitHub](https://github.com/dotnet/corefx) | [MIT](https://opensource.org/licenses/MIT) | Allows [publishing with dotnet publish on machines with netcoreapp3.0 SDK installed](https://github.com/microsoft/msbuild/issues/4704#issuecomment-530034240) | | | Spectre.Console | [GitHub](https://github.com/spectreconsole/spectre.console) | [MIT](https://opensource.org/licenses/MIT) | Allows richer command line interactions| | diff --git a/Documentation/CodeTutorials/UserManual.md b/Documentation/CodeTutorials/UserManual.md index f332b24879..224539fccc 100644 --- a/Documentation/CodeTutorials/UserManual.md +++ b/Documentation/CodeTutorials/UserManual.md @@ -120,7 +120,7 @@ There are a couple of other database types which can be created as and when you |Database|Role| |---|---| -| [Query Caching](./../../Rdmp.Core/CohortCreation/Readme.md)| Improves the performance of complex cohort identification configurations and anonymisation. Also allows cross server and plugin Cohort Builder elements (e.g. to [REST APIs](./FAQ.md#apis))| +| [Query Caching](./../../Rdmp.Core/CohortCreation/CohortCreation.md)| Improves the performance of complex cohort identification configurations and anonymisation. Also allows cross server and plugin Cohort Builder elements (e.g. to [REST APIs](./FAQ.md#apis))| |Anonymisation|Provides a way of performing identifier dropping / substitution on data load for when you want an entirely anonymous data repository| |[Plugin Databases](./FAQ.md#plugins)| RDMP supports plugins which can in some cases have their own database(s)| @@ -585,7 +585,7 @@ New [CohortIdentificationConfigurations] are created with 3 containers: - Inclusion Criteria - Exclusion Criteria -The first container is an [EXCEPT] while the other two are [UNION]. For more information on how these work see the [Cohort Builder FAQ](./FAQ.md#cohort-builder-overview) or [Cohort Creation](../../Rdmp.Core/CohortCreation/Readme.md). +The first container is an [EXCEPT] while the other two are [UNION]. For more information on how these work see the [Cohort Builder FAQ](./FAQ.md#cohort-builder-overview) or [Cohort Creation](../../Rdmp.Core/CohortCreation/CohortCreation.md). ## Commit Cohort diff --git a/NoteForNewDevelopers.md b/NoteForNewDevelopers.md index 0ac57d0a74..cb9c197f03 100644 --- a/NoteForNewDevelopers.md +++ b/NoteForNewDevelopers.md @@ -40,16 +40,16 @@ All technical and repo specific documentation are stored in markdown (`.md` form ** Performance ** - [Database Change Tracking (A Performance Enhancement)](./Documentation/CodeTutorials/ChangeTracking.md) -- [Reducing database calls with 'injection'](./Reusable/MapsDirectlyToDatabaseTable/Injection/README.md) +- [Reducing database calls with 'injection'](./Rdmp.Core/MapsDirectlyToDatabaseTable/Injection/Injection.md) **Deep Dives** - [How untyped CSV data is parsed by RDMP](./Documentation/CodeTutorials/CSVHandling.md) - [How 'Bulk Insert' function works](./Documentation/CodeTutorials/DataTableUpload.md) - [How xls / xlsx files are read by RDMP](./Documentation/CodeTutorials/ExcelHandling.md) - [Multiple Linkage Columns (e.g. NHS Number or CHI)](./Documentation/CodeTutorials/MultipleExtractionIdentifiers.md) -- [Storing cohort lists](./Rdmp.Core/CohortCommitting/Readme.md) -- [Cohort Builder docs including info on list caching](./Rdmp.Core/CohortCreation/Readme.md) -- [Tree layout documentation](./Rdmp.Core/Providers/Readme.md) +- [Storing cohort lists](./Rdmp.Core/CohortCommitting/CohortCommitting.md) +- [Cohort Builder docs including info on list caching](./Rdmp.Core/CohortCreation/CohortCreation.md) +- [Tree layout documentation](./Rdmp.Core/Providers/Providers.md) - [Aggregate Graphs](./Documentation/CodeTutorials/Graphs.md) - [YamlRepository](./Documentation/CodeTutorials/YamlRepository.md) - [Custom Metadata Reports](./Documentation/CodeTutorials/CustomMetadataSubstitutions.md) diff --git a/Rdmp.Core.Tests/Caching/Integration/CachingHostTests.cs b/Rdmp.Core.Tests/Caching/Integration/CachingHostTests.cs index 0d80ef878a..91b3eb653e 100644 --- a/Rdmp.Core.Tests/Caching/Integration/CachingHostTests.cs +++ b/Rdmp.Core.Tests/Caching/Integration/CachingHostTests.cs @@ -9,13 +9,11 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using NSubstitute; using NUnit.Framework; using Rdmp.Core.Caching; using Rdmp.Core.Curation; using Rdmp.Core.Curation.Data; using Rdmp.Core.Curation.Data.Cache; -using Rdmp.Core.Curation.Data.Pipelines; using Rdmp.Core.DataFlowPipeline; using Rdmp.Core.ReusableLibraryCode.Progress; using Tests.Common; @@ -94,8 +92,8 @@ public void CacheHostOutwithPermissionWindow() } catch (AggregateException e) { - Assert.AreEqual(1, e.InnerExceptions.Count); - Assert.IsInstanceOf(typeof(TaskCanceledException), e.InnerExceptions[0], e.InnerExceptions[0].Message); + Assert.That(e.InnerExceptions, Has.Count.EqualTo(1)); + Assert.That(e.InnerExceptions[0], Is.InstanceOf(typeof(TaskCanceledException)), e.InnerExceptions[0].Message); } finally { diff --git a/Rdmp.Core.Tests/Caching/Integration/CustomDateCachingTests.cs b/Rdmp.Core.Tests/Caching/Integration/CustomDateCachingTests.cs index 08c51665db..56aca0157b 100644 --- a/Rdmp.Core.Tests/Caching/Integration/CustomDateCachingTests.cs +++ b/Rdmp.Core.Tests/Caching/Integration/CustomDateCachingTests.cs @@ -88,13 +88,19 @@ public void FetchMultipleDays_Success(bool singleDay) .Select(n => n.Message.TrimStart('!')) .ToArray(); - //should not have been updated because this is a backfill request - Assert.AreEqual(new DateTime(2020, 1, 1), cacheProgress.CacheFillProgress); - - Assert.IsTrue(task.IsCompleted); - Assert.IsTrue(dateNotifications.Contains(startDate.ToString("g"))); - Assert.IsTrue(dateNotifications.Contains(endDate.ToString("g"))); - Assert.IsTrue(task.Status == TaskStatus.RanToCompletion); + Assert.Multiple(() => + { + //should not have been updated because this is a backfill request + Assert.That(cacheProgress.CacheFillProgress, Is.EqualTo(new DateTime(2020, 1, 1))); + + Assert.That(task.IsCompleted); + Assert.That(dateNotifications, Does.Contain(startDate.ToString("g"))); + }); + Assert.Multiple(() => + { + Assert.That(dateNotifications, Does.Contain(endDate.ToString("g"))); + Assert.That(task.Status, Is.EqualTo(TaskStatus.RanToCompletion)); + }); projDir.RootPath.Delete(true); } diff --git a/Rdmp.Core.Tests/Caching/Unit/PipelineExecutionTests.cs b/Rdmp.Core.Tests/Caching/Unit/PipelineExecutionTests.cs index ff5e813575..b4e969047d 100644 --- a/Rdmp.Core.Tests/Caching/Unit/PipelineExecutionTests.cs +++ b/Rdmp.Core.Tests/Caching/Unit/PipelineExecutionTests.cs @@ -4,7 +4,6 @@ // RDMP 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 General Public License for more details. // You should have received a copy of the GNU General Public License along with RDMP. If not, see . -using System; using NSubstitute; using NUnit.Framework; using Rdmp.Core.Caching.Pipeline; diff --git a/Rdmp.Core.Tests/Caching/Unit/ZipTests.cs b/Rdmp.Core.Tests/Caching/Unit/ZipTests.cs index 21d152245e..b51360ebe0 100644 --- a/Rdmp.Core.Tests/Caching/Unit/ZipTests.cs +++ b/Rdmp.Core.Tests/Caching/Unit/ZipTests.cs @@ -54,7 +54,7 @@ public void CreateAndUpdateZip() _zt.ArchiveFiles(files.ToArray(), when, _listener); using (var zip = ZipFile.Open(targetzip.FullName, ZipArchiveMode.Read)) { - Assert.True(zip.Entries.Count == 1); + Assert.That(zip.Entries, Has.Count.EqualTo(1)); } // Create a second file and add that to the zip too @@ -67,17 +67,17 @@ public void CreateAndUpdateZip() _zt.ArchiveFiles(files.ToArray(), when, _listener); using (var zip = ZipFile.Open(targetzip.FullName, ZipArchiveMode.Read)) { - Assert.True(zip.Entries.Count == 2); + Assert.That(zip.Entries, Has.Count.EqualTo(2)); } // Re-add just the first file: resulting zip should still contain both files _zt.ArchiveFiles(files.GetRange(0, 1).ToArray(), when, _listener); using (var zip = ZipFile.Open(targetzip.FullName, ZipArchiveMode.Read)) { - Assert.True(zip.Entries.Count == 2); + Assert.That(zip.Entries, Has.Count.EqualTo(2)); } - files.ForEach(s => File.Delete(s.FullName)); + files.ForEach(static s => File.Delete(s.FullName)); File.Delete(targetzip.FullName); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CohortCommitting/CommitCohortExample.cs b/Rdmp.Core.Tests/CohortCommitting/CommitCohortExample.cs index 3c521dca15..e15da53f2b 100644 --- a/Rdmp.Core.Tests/CohortCommitting/CommitCohortExample.cs +++ b/Rdmp.Core.Tests/CohortCommitting/CommitCohortExample.cs @@ -31,13 +31,13 @@ public void CommitCohortExampleTest(DatabaseType dbType, string privateDataType) //find the test server (where we will create the store schema) var db = GetCleanedServer(dbType); - + //create the cohort store table var wizard = new CreateNewCohortDatabaseWizard(db, CatalogueRepository, DataExportRepository, false); var privateColumn = new PrivateIdentifierPrototype("chi", privateDataType); var externalCohortTable = wizard.CreateDatabase(privateColumn, ThrowImmediatelyCheckNotifier.Quiet); - Assert.AreEqual(dbType, externalCohortTable.DatabaseType); + Assert.That(externalCohortTable.DatabaseType, Is.EqualTo(dbType)); //create a project into which we want to import a cohort var project = new Project(DataExportRepository, "MyProject") @@ -73,7 +73,7 @@ public void CommitCohortExampleTest(DatabaseType dbType, string privateDataType) new GracefulCancellationToken()); //there should be no cohorts yet - Assert.IsEmpty(DataExportRepository.GetAllObjects()); + Assert.That(DataExportRepository.GetAllObjects(), Is.Empty); //dispose of the pipeline pipelineDestination.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, null); @@ -81,19 +81,25 @@ public void CommitCohortExampleTest(DatabaseType dbType, string privateDataType) //now there should be one var cohort = DataExportRepository.GetAllObjects().Single(); - //make sure we are all on the same page about what the DBMS type is (nothing cached etc) - Assert.AreEqual(dbType, cohort.ExternalCohortTable.DatabaseType); - Assert.AreEqual(dbType, cohort.GetQuerySyntaxHelper().DatabaseType); + Assert.Multiple(() => + { + //make sure we are all on the same page about what the DBMS type is (nothing cached etc) + Assert.That(cohort.ExternalCohortTable.DatabaseType, Is.EqualTo(dbType)); + Assert.That(cohort.GetQuerySyntaxHelper().DatabaseType, Is.EqualTo(dbType)); - Assert.AreEqual(500, cohort.ExternalProjectNumber); - Assert.AreEqual(2, cohort.CountDistinct); + Assert.That(cohort.ExternalProjectNumber, Is.EqualTo(500)); + Assert.That(cohort.CountDistinct, Is.EqualTo(2)); + }); var tbl = externalCohortTable.DiscoverCohortTable(); - Assert.AreEqual(2, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(2)); var dtInDatabase = tbl.GetDataTable(); - //guid will be something like "6fb23de5-e8eb-46eb-84b5-dd368da21073" - Assert.AreEqual(36, dtInDatabase.Rows[0]["ReleaseId"].ToString().Length); - Assert.AreEqual("0101010101", dtInDatabase.Rows[0]["chi"]); + Assert.Multiple(() => + { + //guid will be something like "6fb23de5-e8eb-46eb-84b5-dd368da21073" + Assert.That(dtInDatabase.Rows[0]["ReleaseId"].ToString(), Has.Length.EqualTo(36)); + Assert.That(dtInDatabase.Rows[0]["chi"], Is.EqualTo("0101010101")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CohortCommitting/CreateNewCohortDatabaseWizardTests.cs b/Rdmp.Core.Tests/CohortCommitting/CreateNewCohortDatabaseWizardTests.cs index 6257d4558c..078658042d 100644 --- a/Rdmp.Core.Tests/CohortCommitting/CreateNewCohortDatabaseWizardTests.cs +++ b/Rdmp.Core.Tests/CohortCommitting/CreateNewCohortDatabaseWizardTests.cs @@ -74,15 +74,15 @@ public void TestMissingColumnInfos() var wizard = new CreateNewCohortDatabaseWizard(null, CatalogueRepository, DataExportRepository, false); //it finds it! - Assert.IsTrue(wizard.GetPrivateIdentifierCandidates() + Assert.That(wizard.GetPrivateIdentifierCandidates() .Any(prototype => prototype.RuntimeName.Equals("PrivateIdentifierA"))); //delete the column info to make it a missing reference _c1.DeleteInDatabase(); //now it should gracefully skip over it - Assert.IsFalse(wizard.GetPrivateIdentifierCandidates() - .Any(prototype => prototype.RuntimeName.Equals("PrivateIdentifierA"))); + Assert.That(wizard.GetPrivateIdentifierCandidates() + .Any(prototype => prototype.RuntimeName.Equals("PrivateIdentifierA")), Is.False); } [Test] @@ -92,16 +92,19 @@ public void ProposePrivateIdentifierDatatypes() var candidates = wizard.GetPrivateIdentifierCandidates(); - Assert.IsFalse(candidates.Any(c => - c.RuntimeName.Equals("PrivateIdentifierA") || c.RuntimeName.Equals("PrivateIdentifierB"))); + Assert.That(candidates.Any(c => + c.RuntimeName.Equals("PrivateIdentifierA") || c.RuntimeName.Equals("PrivateIdentifierB")), Is.False); _extractionInfo1.IsExtractionIdentifier = true; _extractionInfo1.SaveToDatabase(); candidates = wizard.GetPrivateIdentifierCandidates(); var candidate = candidates.Single(c => c.RuntimeName.Equals("PrivateIdentifierA")); - Assert.AreEqual("varchar(10)", candidate.DataType); - Assert.IsTrue(candidate.MatchingExtractionInformations.Single().ID == _extractionInfo1.ID); + Assert.Multiple(() => + { + Assert.That(candidate.DataType, Is.EqualTo("varchar(10)")); + Assert.That(candidate.MatchingExtractionInformations.Single().ID, Is.EqualTo(_extractionInfo1.ID)); + }); } [TestCase("text")] @@ -124,9 +127,8 @@ public void TestVarcharMaxNotAllowed(string term) var ex = Assert.Throws(() => wizard.CreateDatabase( candidate, ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual( - "Private identifier datatype cannot be varchar(max) style as this prevents Primary Key creation on the table", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Private identifier datatype cannot be varchar(max) style as this prevents Primary Key creation on the table")); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -144,14 +146,17 @@ public void TestActuallyCreatingIt(DatabaseType type) candidate, ThrowImmediatelyCheckNotifier.Quiet); - Assert.AreEqual(type, ect.DatabaseType); + Assert.That(ect.DatabaseType, Is.EqualTo(type)); //database should exist DiscoveredServerICanCreateRandomDatabasesAndTablesOn.ExpectDatabase(cohortDatabaseName); - Assert.IsTrue(db.Exists()); + Assert.Multiple(() => + { + Assert.That(db.Exists()); - //did it create the correct type? - Assert.AreEqual(type, ect.DatabaseType); + //did it create the correct type? + Assert.That(ect.DatabaseType, Is.EqualTo(type)); + }); //the ExternalCohortTable should pass tests ect.Check(ThrowImmediatelyCheckNotifier.Quiet); @@ -185,34 +190,40 @@ public void TestActuallyCreatingIt(DatabaseType type) dest.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, null); var cohort = request.CohortCreatedIfAny; - Assert.IsNotNull(cohort); + Assert.That(cohort, Is.Not.Null); var externalData = cohort.GetExternalData(); - Assert.AreEqual(10, externalData.ExternalProjectNumber); - Assert.IsFalse(string.IsNullOrEmpty(externalData.ExternalDescription)); + Assert.Multiple(() => + { + Assert.That(externalData.ExternalProjectNumber, Is.EqualTo(10)); + Assert.That(string.IsNullOrEmpty(externalData.ExternalDescription), Is.False); - Assert.AreEqual(DateTime.Now.Year, externalData.ExternalCohortCreationDate.Value.Year); - Assert.AreEqual(DateTime.Now.Month, externalData.ExternalCohortCreationDate.Value.Month); - Assert.AreEqual(DateTime.Now.Day, externalData.ExternalCohortCreationDate.Value.Day); - Assert.AreEqual(DateTime.Now.Hour, externalData.ExternalCohortCreationDate.Value.Hour); + Assert.That(externalData.ExternalCohortCreationDate.Value.Year, Is.EqualTo(DateTime.Now.Year)); + Assert.That(externalData.ExternalCohortCreationDate.Value.Month, Is.EqualTo(DateTime.Now.Month)); + Assert.That(externalData.ExternalCohortCreationDate.Value.Day, Is.EqualTo(DateTime.Now.Day)); + Assert.That(externalData.ExternalCohortCreationDate.Value.Hour, Is.EqualTo(DateTime.Now.Hour)); + }); cohort.AppendToAuditLog("Test"); - Assert.IsTrue(cohort.AuditLog.Contains("Test")); + Assert.Multiple(() => + { + Assert.That(cohort.AuditLog, Does.Contain("Test")); - Assert.AreEqual(1, cohort.Count); - Assert.AreEqual(1, cohort.CountDistinct); + Assert.That(cohort.Count, Is.EqualTo(1)); + }); + Assert.That(cohort.CountDistinct, Is.EqualTo(1)); var cohortTable = cohort.FetchEntireCohort(); - Assert.AreEqual(1, cohortTable.Rows.Count); + Assert.That(cohortTable.Rows, Has.Count.EqualTo(1)); var helper = ect.GetQuerySyntaxHelper(); - Assert.AreEqual(101243, cohortTable.Rows[0][helper.GetRuntimeName(ect.PrivateIdentifierField)]); + Assert.That(cohortTable.Rows[0][helper.GetRuntimeName(ect.PrivateIdentifierField)], Is.EqualTo(101243)); var aguid = cohortTable.Rows[0][helper.GetRuntimeName(ect.ReleaseIdentifierField)].ToString(); - Assert.IsFalse(string.IsNullOrWhiteSpace(aguid)); //should be a guid + Assert.That(string.IsNullOrWhiteSpace(aguid), Is.False); //should be a guid //test reversing the anonymisation of something var dtAno = new DataTable(); @@ -223,16 +234,19 @@ public void TestActuallyCreatingIt(DatabaseType type) cohort.ReverseAnonymiseDataTable(dtAno, ThrowImmediatelyDataLoadEventListener.Quiet, true); - Assert.AreEqual(2, dtAno.Columns.Count); - Assert.IsTrue(dtAno.Columns.Contains(cohort.GetPrivateIdentifier(true))); + Assert.That(dtAno.Columns, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(dtAno.Columns.Contains(cohort.GetPrivateIdentifier(true))); - Assert.AreEqual("101243", dtAno.Rows[0][cohort.GetPrivateIdentifier(true)]); - Assert.AreEqual("101243", dtAno.Rows[1][cohort.GetPrivateIdentifier(true)]); + Assert.That(dtAno.Rows[0][cohort.GetPrivateIdentifier(true)], Is.EqualTo("101243")); + Assert.That(dtAno.Rows[1][cohort.GetPrivateIdentifier(true)], Is.EqualTo("101243")); + }); //make sure that it shows up in the child provider (provides fast object access in CLI and builds tree model for UI) var repo = new DataExportChildProvider(RepositoryLocator, null, ThrowImmediatelyCheckNotifier.Quiet, null); var descendancy = repo.GetDescendancyListIfAnyFor(cohort); - Assert.IsNotNull(descendancy); + Assert.That(descendancy, Is.Not.Null); } [Test] @@ -258,9 +272,8 @@ public void Test_IdentifiableExtractions() UserSettings.SetErrorReportingLevelFor(ErrorCodes.ExtractionIsIdentifiable, CheckResult.Fail); var ex = Assert.Throws(() => ect.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual( - "R004 PrivateIdentifierField and ReleaseIdentifierField are the same, this means your cohort will extract identifiable data (no cohort identifier substitution takes place)", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("R004 PrivateIdentifierField and ReleaseIdentifierField are the same, this means your cohort will extract identifiable data (no cohort identifier substitution takes place)")); UserSettings.SetErrorReportingLevelFor(ErrorCodes.ExtractionIsIdentifiable, CheckResult.Warning); diff --git a/Rdmp.Core.Tests/CohortCreation/AggregateFilterPublishingTests.cs b/Rdmp.Core.Tests/CohortCreation/AggregateFilterPublishingTests.cs index 2297781e78..1280061285 100644 --- a/Rdmp.Core.Tests/CohortCreation/AggregateFilterPublishingTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/AggregateFilterPublishingTests.cs @@ -46,7 +46,7 @@ public void NotPopulated_Description() var ex = Assert.Throws(() => new FilterImporter(new ExtractionFilterFactory(_chiExtractionInformation), null).ImportFilter(_container, _filter, null)); - Assert.AreEqual("Cannot clone filter called 'folk' because:There is no description", ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("Cannot clone filter called 'folk' because:There is no description")); } [Test] @@ -56,9 +56,8 @@ public void NotPopulated_DescriptionTooShort() var ex = Assert.Throws(() => new FilterImporter(new ExtractionFilterFactory(_chiExtractionInformation), null).ImportFilter(_container, _filter, null)); - Assert.AreEqual( - "Cannot clone filter called 'folk' because:Description is not long enough (minimum length is 20 characters)", - ex?.Message); + Assert.That( + ex?.Message, Is.EqualTo("Cannot clone filter called 'folk' because:Description is not long enough (minimum length is 20 characters)")); } [Test] @@ -68,7 +67,7 @@ public void NotPopulated_WhereSQLNotSet() var ex = Assert.Throws(() => new FilterImporter(new ExtractionFilterFactory(_chiExtractionInformation), null).ImportFilter(_container, _filter, null)); - Assert.AreEqual("Cannot clone filter called 'folk' because:WhereSQL is not populated", ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("Cannot clone filter called 'folk' because:WhereSQL is not populated")); } /// @@ -85,7 +84,7 @@ public void NotPopulated_ParameterNoComment() var importedFilter = new FilterImporter(new ExtractionFilterFactory(_chiExtractionInformation), null).ImportFilter(null, _filter, null); - Assert.AreEqual("folk", importedFilter.Name); + Assert.That(importedFilter.Name, Is.EqualTo("folk")); } @@ -104,9 +103,8 @@ public void NotPopulated_ParameterNotSet() var ex = Assert.Throws(() => new FilterImporter(new ExtractionFilterFactory(_chiExtractionInformation), null).ImportFilter(_container, _filter, null)); - Assert.AreEqual( - "Cannot clone filter called 'folk' because:Parameter '@coconutCount' was rejected :There is no value/default value listed", - ex?.Message); + Assert.That( + ex?.Message, Is.EqualTo("Cannot clone filter called 'folk' because:Parameter '@coconutCount' was rejected :There is no value/default value listed")); } [Test] @@ -118,7 +116,7 @@ public void ShortcutFiltersWork_ProperlyReplicatesParentAndHasFK() var sql = new CohortQueryBuilder(aggregate1, null, null).SQL; Console.WriteLine(sql); - Assert.IsTrue(sql.Contains("folk=1")); + Assert.That(sql, Does.Contain("folk=1")); var shortcutAggregate = @@ -128,7 +126,7 @@ public void ShortcutFiltersWork_ProperlyReplicatesParentAndHasFK() testData.extractionInformations.Single(e => e.GetRuntimeName().Equals("sex")), shortcutAggregate); //before it is a shortcut it has no filters - Assert.IsFalse(shortcutAggregate.GetQueryBuilder().SQL.Contains("WHERE")); + Assert.That(shortcutAggregate.GetQueryBuilder().SQL, Does.Not.Contain("WHERE")); //make it a shortcut shortcutAggregate.OverrideFiltersByUsingParentAggregateConfigurationInstead_ID = aggregate1.ID; @@ -137,16 +135,16 @@ public void ShortcutFiltersWork_ProperlyReplicatesParentAndHasFK() var sqlShortcut = shortcutAggregate.GetQueryBuilder().SQL; //shortcut should have its own dimensions - Assert.IsTrue(sqlShortcut.Contains("[sex]")); - Assert.IsFalse(sqlShortcut.Contains("[chi]")); + Assert.That(sqlShortcut, Does.Contain("[sex]")); + Assert.That(sqlShortcut, Does.Not.Contain("[chi]")); //but should have a REFERENCE (not a clone!) to aggregate 1's filters - Assert.IsTrue(sqlShortcut.Contains("folk=1")); + Assert.That(sqlShortcut, Does.Contain("folk=1")); //make sure it is a reference by changing the original _filter.WhereSQL = "folk=2"; _filter.SaveToDatabase(); - Assert.IsTrue(shortcutAggregate.GetQueryBuilder().SQL.Contains("folk=2")); + Assert.That(shortcutAggregate.GetQueryBuilder().SQL, Does.Contain("folk=2")); //shouldn't work because of the dependency of the child - should give a foreign key error if (CatalogueRepository is TableRepository) Assert.Throws(aggregate1.DeleteInDatabase); @@ -161,18 +159,17 @@ public void ShortcutFiltersWork_ProperlyReplicatesParentAndHasFK() [Test] public void ShortcutFilters_AlreadyHasFilter() { - Assert.IsNotNull(aggregate1.RootFilterContainer_ID); + Assert.That(aggregate1.RootFilterContainer_ID, Is.Not.Null); var ex = Assert.Throws(() => aggregate1.OverrideFiltersByUsingParentAggregateConfigurationInstead_ID = -500); //not ok - Assert.AreEqual( - "Cannot set OverrideFiltersByUsingParentAggregateConfigurationInstead_ID because this AggregateConfiguration already has a filter container set (if you were to be a shortcut and also have a filter tree set it would be very confusing)", - ex?.Message); + Assert.That( + ex?.Message, Is.EqualTo("Cannot set OverrideFiltersByUsingParentAggregateConfigurationInstead_ID because this AggregateConfiguration already has a filter container set (if you were to be a shortcut and also have a filter tree set it would be very confusing)")); } [Test] public void ShortcutFilters_AlreadyHasFilter_ButSettingItToNull() { - Assert.IsNotNull(aggregate1.RootFilterContainer_ID); + Assert.That(aggregate1.RootFilterContainer_ID, Is.Not.Null); Assert.DoesNotThrow( () => { aggregate1.OverrideFiltersByUsingParentAggregateConfigurationInstead_ID = null; }); // is ok } @@ -191,9 +188,8 @@ public void ShortcutFilters_DoesNotHaveFilter_SetOne() aggregate1.OverrideFiltersByUsingParentAggregateConfigurationInstead_ID = -19; }); // is ok var ex = Assert.Throws(() => aggregate1.RootFilterContainer_ID = 123); - Assert.AreEqual( - "This AggregateConfiguration has a shortcut to another AggregateConfiguration's Filters (its OverrideFiltersByUsingParentAggregateConfigurationInstead_ID is -19) which means it cannot be assigned its own RootFilterContainerID", - ex?.Message); + Assert.That( + ex?.Message, Is.EqualTo("This AggregateConfiguration has a shortcut to another AggregateConfiguration's Filters (its OverrideFiltersByUsingParentAggregateConfigurationInstead_ID is -19) which means it cannot be assigned its own RootFilterContainerID")); } [Test] @@ -205,7 +201,7 @@ public void CloneWorks_AllPropertiesMatchIncludingParameters() new ParameterCreator(new AggregateFilterFactory(CatalogueRepository), null, null).CreateAll(_filter, null); _filter.SaveToDatabase(); - Assert.IsNull(_filter.ClonedFromExtractionFilter_ID); + Assert.That(_filter.ClonedFromExtractionFilter_ID, Is.Null); var parameter = _filter.GetAllParameters().Single(); parameter.ParameterSQL = "Declare @coconutCount int"; @@ -217,15 +213,16 @@ public void CloneWorks_AllPropertiesMatchIncludingParameters() new FilterImporter(new ExtractionFilterFactory(_chiExtractionInformation), null).ImportFilter(null, _filter, null); - //we should now be a clone of the master we just created - Assert.AreEqual(_filter.ClonedFromExtractionFilter_ID, newMaster.ID); - Assert.IsTrue(newMaster.Description.StartsWith(_filter.Description)); //it adds some addendum stuff onto it - Assert.AreEqual(_filter.WhereSQL, newMaster.WhereSQL); - - Assert.AreEqual(_filter.GetAllParameters().Single().ParameterName, - newMaster.GetAllParameters().Single().ParameterName); - Assert.AreEqual(_filter.GetAllParameters().Single().ParameterSQL, - newMaster.GetAllParameters().Single().ParameterSQL); - Assert.AreEqual(_filter.GetAllParameters().Single().Value, newMaster.GetAllParameters().Single().Value); + Assert.Multiple(() => + { + //we should now be a clone of the master we just created + Assert.That(newMaster.ID, Is.EqualTo(_filter.ClonedFromExtractionFilter_ID)); + Assert.That(newMaster.Description, Does.StartWith(_filter.Description)); //it adds some addendum stuff onto it + Assert.That(newMaster.WhereSQL, Is.EqualTo(_filter.WhereSQL)); + + Assert.That(newMaster.GetAllParameters().Single().ParameterName, Is.EqualTo(_filter.GetAllParameters().Single().ParameterName)); + Assert.That(newMaster.GetAllParameters().Single().ParameterSQL, Is.EqualTo(_filter.GetAllParameters().Single().ParameterSQL)); + Assert.That(newMaster.GetAllParameters().Single().Value, Is.EqualTo(_filter.GetAllParameters().Single().Value)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CohortCreation/CohortCompilerRunnerTests.cs b/Rdmp.Core.Tests/CohortCreation/CohortCompilerRunnerTests.cs index d85e4350ec..33524376a0 100644 --- a/Rdmp.Core.Tests/CohortCreation/CohortCompilerRunnerTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/CohortCompilerRunnerTests.cs @@ -33,15 +33,18 @@ public void CacheIdentifierListWithRunner_SimpleCase() var runner = new CohortCompilerRunner(compiler, 5000); runner.Run(new CancellationToken()); - Assert.AreEqual(CohortCompilerRunner.Phase.Finished, runner.ExecutionPhase); + Assert.That(runner.ExecutionPhase, Is.EqualTo(CohortCompilerRunner.Phase.Finished)); var rootTask = runner.Compiler.Tasks.Single(t => t.Key is AggregationContainerTask); - Assert.IsTrue(rootTask.Value.IsResultsForRootContainer); - Assert.IsNull(rootTask.Key.CrashMessage); - Assert.AreEqual(CompilationState.Finished, rootTask.Key.State); + Assert.Multiple(() => + { + Assert.That(rootTask.Value.IsResultsForRootContainer); + Assert.That(rootTask.Key.CrashMessage, Is.Null); + Assert.That(rootTask.Key.State, Is.EqualTo(CompilationState.Finished)); - Assert.AreEqual(dt.Rows.Count, rootTask.Value.Identifiers.Rows.Count); + Assert.That(rootTask.Value.Identifiers.Rows, Has.Count.EqualTo(dt.Rows.Count)); + }); } [Test] @@ -64,17 +67,20 @@ public void CacheIdentifierListWithRunner_WithCaching() var runner = new CohortCompilerRunner(compiler, 5000); runner.Run(new CancellationToken()); - Assert.AreEqual(CohortCompilerRunner.Phase.Finished, runner.ExecutionPhase); + Assert.That(runner.ExecutionPhase, Is.EqualTo(CohortCompilerRunner.Phase.Finished)); var rootTask = runner.Compiler.Tasks.Single(t => t.Key is AggregationContainerTask); - Assert.IsTrue(rootTask.Value.IsResultsForRootContainer); - Assert.IsNull(rootTask.Key.CrashMessage); - Assert.AreEqual(CompilationState.Finished, rootTask.Key.State); + Assert.Multiple(() => + { + Assert.That(rootTask.Value.IsResultsForRootContainer); + Assert.That(rootTask.Key.CrashMessage, Is.Null); + Assert.That(rootTask.Key.State, Is.EqualTo(CompilationState.Finished)); - Assert.IsTrue(runner.Compiler.AreaAllQueriesCached(rootTask.Key)); + Assert.That(runner.Compiler.AreaAllQueriesCached(rootTask.Key)); - Assert.AreEqual(dt.Rows.Count, rootTask.Value.Identifiers.Rows.Count); + Assert.That(rootTask.Value.Identifiers.Rows, Has.Count.EqualTo(dt.Rows.Count)); + }); } private void SetupCohort(out DiscoveredDatabase db, out CohortIdentificationConfiguration cic, out DataTable dt) diff --git a/Rdmp.Core.Tests/CohortCreation/CohortCompilerTests.cs b/Rdmp.Core.Tests/CohortCreation/CohortCompilerTests.cs index 0b60742c4c..48d582cf81 100644 --- a/Rdmp.Core.Tests/CohortCreation/CohortCompilerTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/CohortCompilerTests.cs @@ -28,13 +28,13 @@ public void AddSameTaskTwice_StaysAtOne() { compiler.AddTask(aggregate1, null); - Assert.AreEqual(1, compiler.Tasks.Count); + Assert.That(compiler.Tasks, Has.Count.EqualTo(1)); var oldTask = compiler.Tasks.First(); //adding it again with the same SQL should result in it ignoring it compiler.AddTask(aggregate1, null); - Assert.AreEqual(1, compiler.Tasks.Count); + Assert.That(compiler.Tasks, Has.Count.EqualTo(1)); //make a change to the SQL foreach (var d in aggregate1.AggregateDimensions) @@ -47,14 +47,14 @@ public void AddSameTaskTwice_StaysAtOne() var newAggregate1 = CatalogueRepository.GetObjectByID(aggregate1.ID); compiler.AddTask(newAggregate1, null); - Assert.AreEqual(1, compiler.Tasks.Count); //should still be 1 task + Assert.That(compiler.Tasks, Has.Count.EqualTo(1)); //should still be 1 task // TN: Task was never asked to start so was still at NotScheduled so cancellation wouldn't actually happen //old task should have been asked to cancel // Assert.IsTrue(oldTask.Key.CancellationToken.IsCancellationRequested); - Assert.AreNotSame(oldTask, compiler.Tasks.Single()); //new task should not be the same as the old one - Assert.IsFalse(compiler.Tasks.Single().Key.CancellationToken.IsCancellationRequested); + Assert.That(compiler.Tasks.Single(), Is.Not.EqualTo(oldTask)); //new task should not be the same as the old one + Assert.That(compiler.Tasks.Single().Key.CancellationToken.IsCancellationRequested, Is.False); //new task should not be cancelled} finally { } finally @@ -71,25 +71,25 @@ public void AddContainer_StaysAtOne() compiler.AddTask(rootcontainer, null); //add the root container - Assert.AreEqual(1, compiler.Tasks.Count); + Assert.That(compiler.Tasks, Has.Count.EqualTo(1)); var oldTask = compiler.Tasks.First(); //adding it again with the same SQL should result in it ignoring it compiler.AddTask(rootcontainer, null); - Assert.AreEqual(1, compiler.Tasks.Count); + Assert.That(compiler.Tasks, Has.Count.EqualTo(1)); //add another aggregate into the container rootcontainer.AddChild(aggregate2, 1); compiler.AddTask(rootcontainer, null); - Assert.AreEqual(1, compiler.Tasks.Count); //should still be 1 task + Assert.That(compiler.Tasks, Has.Count.EqualTo(1)); //should still be 1 task // TN: Task was never asked to start so was still at NotScheduled so cancellation wouldn't actually happen //old task should have been asked to cancel //Assert.IsTrue(oldTask.Key.CancellationToken.IsCancellationRequested); - Assert.AreNotSame(oldTask, compiler.Tasks.Single()); //new task should not be the same as the old one - Assert.IsFalse(compiler.Tasks.Single().Key.CancellationToken - .IsCancellationRequested); //new task should not be cancelled + Assert.That(compiler.Tasks.Single(), Is.Not.EqualTo(oldTask)); //new task should not be the same as the old one + Assert.That(compiler.Tasks.Single().Key.CancellationToken + .IsCancellationRequested, Is.False); //new task should not be cancelled rootcontainer.RemoveChild(aggregate1); rootcontainer.RemoveChild(aggregate2); @@ -164,22 +164,19 @@ public void TestCompilerAddAllTasks(TestCompilerAddAllTasksTestCase testCase, bo { case TestCompilerAddAllTasksTestCase.CIC: tasks = compiler.AddAllTasks(includeSubcontainers); - Assert.AreEqual(joinable, - tasks.OfType().Single().Joinable); //should be a single joinable - Assert.AreEqual(includeSubcontainers ? 7 : 6, - tasks.Count); //all joinables, aggregates and root container + Assert.That(tasks.OfType().Single().Joinable, Is.EqualTo(joinable)); //should be a single joinable + Assert.That(tasks, Has.Count.EqualTo(includeSubcontainers ? 7 : 6)); //all joinables, aggregates and root container break; case TestCompilerAddAllTasksTestCase.RootContainer: tasks = compiler.AddTasksRecursively(Array.Empty(), cohortIdentificationConfiguration.RootCohortAggregateContainer, includeSubcontainers); - Assert.AreEqual(includeSubcontainers ? 6 : 5, - tasks.Count); //all aggregates and root container (but not joinables) + Assert.That(tasks, Has.Count.EqualTo(includeSubcontainers ? 6 : 5)); //all aggregates and root container (but not joinables) break; case TestCompilerAddAllTasksTestCase.Subcontainer: tasks = compiler.AddTasksRecursively(Array.Empty(), container1, includeSubcontainers); - Assert.AreEqual(includeSubcontainers ? 3 : 2, tasks.Count); //subcontainer and its aggregates + Assert.That(tasks, Has.Count.EqualTo(includeSubcontainers ? 3 : 2)); //subcontainer and its aggregates break; default: throw new ArgumentOutOfRangeException(nameof(testCase)); diff --git a/Rdmp.Core.Tests/CohortCreation/CohortContainerAndCloningTests.cs b/Rdmp.Core.Tests/CohortCreation/CohortContainerAndCloningTests.cs index 105dedd202..a6080fcb55 100644 --- a/Rdmp.Core.Tests/CohortCreation/CohortContainerAndCloningTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/CohortContainerAndCloningTests.cs @@ -37,11 +37,14 @@ public void AggregateOrdering_ExplicitSetting_CorrectOrder() try { - Assert.AreEqual(1, aggregate2.Order); - Assert.AreEqual(5, aggregate1.Order); - - Assert.AreEqual(rootcontainer.GetAggregateConfigurations()[0].ID, aggregate2.ID); - Assert.AreEqual(rootcontainer.GetAggregateConfigurations()[1].ID, aggregate1.ID); + Assert.Multiple(() => + { + Assert.That(aggregate2.Order, Is.EqualTo(1)); + Assert.That(aggregate1.Order, Is.EqualTo(5)); + + Assert.That(aggregate2.ID, Is.EqualTo(rootcontainer.GetAggregateConfigurations()[0].ID)); + Assert.That(aggregate1.ID, Is.EqualTo(rootcontainer.GetAggregateConfigurations()[1].ID)); + }); } finally { @@ -55,7 +58,7 @@ public void CloneChild_NamingCorrectNewObject() { //should not follow naming convention aggregate1.Name = "fish"; - Assert.IsFalse(cohortIdentificationConfiguration.IsValidNamedConfiguration(aggregate1)); + Assert.That(cohortIdentificationConfiguration.IsValidNamedConfiguration(aggregate1), Is.False); //add a clone using aggregate1 as a template var clone = cohortIdentificationConfiguration.ImportAggregateConfigurationAsIdentifierList(aggregate1, null); @@ -66,13 +69,16 @@ public void CloneChild_NamingCorrectNewObject() { //there should be 1 child var aggregateConfigurations = rootcontainer.GetAggregateConfigurations(); - Assert.AreEqual(1, aggregateConfigurations.Length); + Assert.Multiple(() => + { + Assert.That(aggregateConfigurations, Has.Length.EqualTo(1)); - //child should follow naming convention - Assert.IsTrue(cohortIdentificationConfiguration.IsValidNamedConfiguration(aggregateConfigurations[0])); + //child should follow naming convention + Assert.That(cohortIdentificationConfiguration.IsValidNamedConfiguration(aggregateConfigurations[0])); + }); //clone should have a different ID - also it was created after so should be higher ID - Assert.Greater(aggregateConfigurations[0].ID, aggregate1.ID); + Assert.That(aggregateConfigurations[0].ID, Is.GreaterThan(aggregate1.ID)); } finally { @@ -112,35 +118,43 @@ public void CloneChildWithFilter_IDsDifferent() //we are importing this graph aggregate as a new cohort identification aggregate var clone = cohortIdentificationConfiguration.ImportAggregateConfigurationAsIdentifierList(aggregate1, null); - //since its a cohort aggregate it should be identical to the origin Aggregate except it has a different ID and no count SQL - Assert.AreEqual(clone.CountSQL, null); + //since it's a cohort aggregate it should be identical to the origin Aggregate except it has a different ID and no count SQL + Assert.That(clone.CountSQL, Is.Null); //get the original sql var aggregateSql = aggregate1.GetQueryBuilder().SQL; try { - Assert.AreNotEqual(clone.ID, aggregate1.ID); - Assert.AreNotEqual(clone.RootFilterContainer_ID, aggregate1.RootFilterContainer_ID); + Assert.Multiple(() => + { + Assert.That(aggregate1.ID, Is.Not.EqualTo(clone.ID)); + Assert.That(aggregate1.RootFilterContainer_ID, Is.Not.EqualTo(clone.RootFilterContainer_ID)); + }); var cloneContainer = clone.RootFilterContainer; var cloneFilter = cloneContainer.GetFilters().Single(); - Assert.AreNotEqual(cloneContainer.ID, container.ID); - Assert.AreNotEqual(cloneFilter.ID, filter.ID); + Assert.Multiple(() => + { + Assert.That(container.ID, Is.Not.EqualTo(cloneContainer.ID)); + Assert.That(filter.ID, Is.Not.EqualTo(cloneFilter.ID)); + }); var cloneParameter = (AggregateFilterParameter)cloneFilter.GetAllParameters().Single(); - Assert.AreNotEqual(cloneParameter.ID, param.ID); + Assert.That(param.ID, Is.Not.EqualTo(cloneParameter.ID)); //it has a different ID and is part of an aggregate filter container (It is presumed to be involved with cohort identification cohortIdentificationConfiguration) which means it will be called cic_X_ var cohortAggregateSql = new CohortQueryBuilder(clone, null, null).SQL; + Assert.Multiple(() => + { -//the basic aggregate has the filter, parameter and group by - Assert.AreEqual(CollapseWhitespace( - string.Format( - @"DECLARE @sex AS varchar(50); + //the basic aggregate has the filter, parameter and group by + Assert.That(CollapseWhitespace(aggregateSql), Is.EqualTo(CollapseWhitespace( + string.Format( + @"DECLARE @sex AS varchar(50); SET @sex='M'; /*cic_{0}_UnitTestAggregate1*/ SELECT @@ -157,17 +171,16 @@ public void CloneChildWithFilter_IDsDifferent() group by [" + TestDatabaseNames.Prefix + @"ScratchArea].[dbo].[BulkData].[chi] order by -[" + TestDatabaseNames.Prefix + @"ScratchArea].[dbo].[BulkData].[chi]", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(aggregateSql)); +[" + TestDatabaseNames.Prefix + @"ScratchArea].[dbo].[BulkData].[chi]", cohortIdentificationConfiguration.ID)))); -//the expected differences are -//1. should not have the count -//2. should not have the group by -//3. should be marked with the cic comment with the ID matching the CohortIdentificationConfiguration.ID -//4. should have a distinct on the identifier column + //the expected differences are + //1. should not have the count + //2. should not have the group by + //3. should be marked with the cic comment with the ID matching the CohortIdentificationConfiguration.ID + //4. should have a distinct on the identifier column - Assert.AreEqual( - $@"DECLARE @sex AS varchar(50); + Assert.That( + cohortAggregateSql, Is.EqualTo($@"DECLARE @sex AS varchar(50); SET @sex='M'; /*cic_{cohortIdentificationConfiguration.ID}_UnitTestAggregate1*/ SELECT @@ -179,7 +192,8 @@ order by ( /*MyFilter*/ sex=@sex -)", cohortAggregateSql); +)")); + }); clone.RootFilterContainer.DeleteInDatabase(); @@ -228,13 +242,15 @@ public void CohortIdentificationConfiguration_CloneEntirely() { var clone = cohortIdentificationConfiguration.CreateClone(ThrowImmediatelyCheckNotifier.Quiet); - //the objects should be different - Assert.AreNotEqual(cohortIdentificationConfiguration.ID, clone.ID); - Assert.IsTrue(clone.Name.EndsWith("(Clone)")); + Assert.Multiple(() => + { + //the objects should be different + Assert.That(clone.ID, Is.Not.EqualTo(cohortIdentificationConfiguration.ID)); + Assert.That(clone.Name, Does.EndWith("(Clone)")); - Assert.AreNotEqual(clone.RootCohortAggregateContainer_ID, - cohortIdentificationConfiguration.RootCohortAggregateContainer_ID); - Assert.IsNotNull(clone.RootCohortAggregateContainer_ID); + Assert.That(cohortIdentificationConfiguration.RootCohortAggregateContainer_ID, Is.Not.EqualTo(clone.RootCohortAggregateContainer_ID)); + Assert.That(clone.RootCohortAggregateContainer_ID, Is.Not.Null); + }); var beforeSQL = new CohortQueryBuilder(cohortIdentificationConfiguration, null).SQL; var cloneSQL = new CohortQueryBuilder(clone, null).SQL; @@ -243,13 +259,13 @@ public void CohortIdentificationConfiguration_CloneEntirely() cloneSQL = Regex.Replace(cloneSQL, "cic_[0-9]+_", ""); //the SQL should be the same for them - Assert.AreEqual(beforeSQL, cloneSQL); + Assert.That(cloneSQL, Is.EqualTo(beforeSQL)); var containerClone = clone.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively() .Where(a => a.RootFilterContainer_ID != null) .Select(ag => ag.RootFilterContainer).Single(); - Assert.AreNotEqual(container, containerClone); + Assert.That(containerClone, Is.Not.EqualTo(container)); //cleanup phase clone.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/CohortCreation/CohortIdentificationConfigurationMergerTests.cs b/Rdmp.Core.Tests/CohortCreation/CohortIdentificationConfigurationMergerTests.cs index 73991efe6a..b14b1a0063 100644 --- a/Rdmp.Core.Tests/CohortCreation/CohortIdentificationConfigurationMergerTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/CohortIdentificationConfigurationMergerTests.cs @@ -32,48 +32,59 @@ public void TestSimpleMerge() root2.SaveToDatabase(); root2.AddChild(aggregate2, 2); - Assert.AreEqual(1, cic1.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count); - Assert.AreEqual(1, cic2.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count); + Assert.Multiple(() => + { + Assert.That(cic1.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively(), Has.Count.EqualTo(1)); + Assert.That(cic2.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively(), Has.Count.EqualTo(1)); + }); var numberOfCicsBefore = CatalogueRepository.GetAllObjects().Length; var result = merger.Merge(new[] { cic1, cic2 }, SetOperation.UNION); - //original should still be intact - Assert.AreEqual(1, cic1.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count); - Assert.AreEqual(1, cic2.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count); - - //the new merged set should contain both - Assert.AreEqual(2, result.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count); + Assert.Multiple(() => + { + //original should still be intact + Assert.That(cic1.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively(), Has.Count.EqualTo(1)); + Assert.That(cic2.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively(), Has.Count.EqualTo(1)); - Assert.IsFalse( - result.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively() - .Any(c => c.Equals(aggregate1)), - "Expected the merge to include clone aggregates not the originals! (aggregate1)"); - Assert.IsFalse( - result.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively() - .Any(c => c.Equals(aggregate2)), - "Expected the merge to include clone aggregates not the originals! (aggregate2)"); + //the new merged set should contain both + Assert.That(result.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively(), Has.Count.EqualTo(2)); + }); - // Now should be a new one - Assert.AreEqual(numberOfCicsBefore + 1, - CatalogueRepository.GetAllObjects().Length); + Assert.Multiple(() => + { + Assert.That( + result.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively() + .Any(c => c.Equals(aggregate1)), Is.False, + "Expected the merge to include clone aggregates not the originals! (aggregate1)"); + Assert.That( + result.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively() + .Any(c => c.Equals(aggregate2)), Is.False, + "Expected the merge to include clone aggregates not the originals! (aggregate2)"); + + // Now should be a new one + Assert.That(CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(numberOfCicsBefore + 1)); + }); var newCicId = result.ID; // Should have the root containers of the old configs var newRoot2 = result.RootCohortAggregateContainer.GetSubContainers().Single(c => c.Name.Equals("Root2")); var newRoot1 = result.RootCohortAggregateContainer.GetSubContainers().Single(c => c.Name.Equals("Root1")); - Assert.AreEqual(2, result.RootCohortAggregateContainer.GetSubContainers().Length); + Assert.Multiple(() => + { + Assert.That(result.RootCohortAggregateContainer.GetSubContainers(), Has.Length.EqualTo(2)); - // And should have - Assert.AreEqual($"cic_{newCicId}_UnitTestAggregate2", newRoot2.GetAggregateConfigurations()[0].Name); - Assert.AreEqual($"cic_{newCicId}_UnitTestAggregate1", newRoot1.GetAggregateConfigurations()[0].Name); + // And should have + Assert.That(newRoot2.GetAggregateConfigurations()[0].Name, Is.EqualTo($"cic_{newCicId}_UnitTestAggregate2")); + Assert.That(newRoot1.GetAggregateConfigurations()[0].Name, Is.EqualTo($"cic_{newCicId}_UnitTestAggregate1")); - Assert.AreEqual($"Merged cics (IDs {cic1.ID},{cic2.ID})", result.Name); + Assert.That(result.Name, Is.EqualTo($"Merged cics (IDs {cic1.ID},{cic2.ID})")); - Assert.IsTrue(cic1.Exists()); - Assert.IsTrue(cic2.Exists()); + Assert.That(cic1.Exists()); + Assert.That(cic2.Exists()); + }); } [Test] @@ -111,24 +122,32 @@ public void TestSimpleUnMerge() var results = merger.UnMerge(root); - // Now should be two new ones - Assert.AreEqual(numberOfCicsBefore + 2, - CatalogueRepository.GetAllObjects().Length); - Assert.AreEqual(2, results.Length); + Assert.Multiple(() => + { + // Now should be two new ones + Assert.That(CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(numberOfCicsBefore + 2)); + Assert.That(results, Has.Length.EqualTo(2)); + }); - Assert.AreEqual(SetOperation.INTERSECT, results[0].RootCohortAggregateContainer.Operation); - Assert.AreEqual(1, results[0].RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count); + Assert.Multiple(() => + { + Assert.That(results[0].RootCohortAggregateContainer.Operation, Is.EqualTo(SetOperation.INTERSECT)); + Assert.That(results[0].RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively(), Has.Count.EqualTo(1)); + }); - Assert.IsFalse( - results[0].RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively() - .Intersect(new[] { aggregate1, aggregate2, aggregate3 }).Any(), "Expected new aggregates to be new!"); + Assert.Multiple(() => + { + Assert.That( + results[0].RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively() + .Intersect(new[] { aggregate1, aggregate2, aggregate3 }).Any(), Is.False, "Expected new aggregates to be new!"); - Assert.AreEqual(SetOperation.EXCEPT, results[1].RootCohortAggregateContainer.Operation); - Assert.AreEqual(2, results[1].RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count); + Assert.That(results[1].RootCohortAggregateContainer.Operation, Is.EqualTo(SetOperation.EXCEPT)); + Assert.That(results[1].RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively(), Has.Count.EqualTo(2)); + }); - Assert.IsFalse( + Assert.That( results[1].RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively() - .Intersect(new[] { aggregate1, aggregate2, aggregate3 }).Any(), "Expected new aggregates to be new!"); + .Intersect(new[] { aggregate1, aggregate2, aggregate3 }).Any(), Is.False, "Expected new aggregates to be new!"); } [Test] @@ -151,22 +170,27 @@ public void TestSimpleImportCic() root2.SaveToDatabase(); root2.AddChild(aggregate2, 2); - Assert.AreEqual(1, cic1.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count); - Assert.AreEqual(1, cic2.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count); + Assert.Multiple(() => + { + Assert.That(cic1.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively(), Has.Count.EqualTo(1)); + Assert.That(cic2.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively(), Has.Count.EqualTo(1)); + }); var numberOfCicsBefore = CatalogueRepository.GetAllObjects().Length; //import 2 into 1 merger.Import(new[] { cic2 }, cic1.RootCohortAggregateContainer); - //no new cics - Assert.AreEqual(numberOfCicsBefore, - CatalogueRepository.GetAllObjects().Length); + Assert.Multiple(() => + { + //no new cics + Assert.That(CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(numberOfCicsBefore)); - // cic 1 should now have both aggregates - Assert.AreEqual(2, cic1.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively().Count); + // cic 1 should now have both aggregates + Assert.That(cic1.RootCohortAggregateContainer.GetAllAggregateConfigurationsRecursively(), Has.Count.EqualTo(2)); - Assert.AreEqual("Root1", cic1.RootCohortAggregateContainer.Name); - Assert.AreEqual("Root2", cic1.RootCohortAggregateContainer.GetSubContainers()[0].Name); + Assert.That(cic1.RootCohortAggregateContainer.Name, Is.EqualTo("Root1")); + Assert.That(cic1.RootCohortAggregateContainer.GetSubContainers()[0].Name, Is.EqualTo("Root2")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CohortCreation/CohortIdentificationTests.cs b/Rdmp.Core.Tests/CohortCreation/CohortIdentificationTests.cs index f5f6702618..3f135f9354 100644 --- a/Rdmp.Core.Tests/CohortCreation/CohortIdentificationTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/CohortIdentificationTests.cs @@ -35,7 +35,7 @@ protected override void SetUp() } - public void SetupTestData(ICatalogueRepository repository) + protected void SetupTestData(ICatalogueRepository repository) { BlitzMainDataTables(); diff --git a/Rdmp.Core.Tests/CohortCreation/CohortMandatoryFilterImportingTests.cs b/Rdmp.Core.Tests/CohortCreation/CohortMandatoryFilterImportingTests.cs index 73c0369a1f..20a060749e 100644 --- a/Rdmp.Core.Tests/CohortCreation/CohortMandatoryFilterImportingTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/CohortMandatoryFilterImportingTests.cs @@ -25,7 +25,7 @@ public void NoMandatoryFilters() var importedAggregateFilterContainer = importedAggregate.RootFilterContainer; //Must have a root container - Assert.IsNull(importedAggregateFilterContainer); + Assert.That(importedAggregateFilterContainer, Is.Null); importedAggregate.DeleteInDatabase(); } @@ -42,8 +42,8 @@ public void ImportCatalogueWithMandatoryFilter() //ensure that it is picked SetUp var mandatoryFilters = testData.catalogue.GetAllMandatoryFilters(); - Assert.AreEqual(1, mandatoryFilters.Length); - Assert.AreEqual(filter, mandatoryFilters[0]); + Assert.That(mandatoryFilters, Has.Length.EqualTo(1)); + Assert.That(mandatoryFilters[0], Is.EqualTo(filter)); AggregateConfiguration importedAggregate = null; @@ -52,25 +52,28 @@ public void ImportCatalogueWithMandatoryFilter() importedAggregate = cohortIdentificationConfiguration.CreateNewEmptyConfigurationForCatalogue(testData.catalogue, null); - Assert.AreEqual(ChangeDescription.NoChanges, importedAggregate.HasLocalChanges().Evaluation); + Assert.That(importedAggregate.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.NoChanges)); var importedAggregateFilterContainer = importedAggregate.RootFilterContainer; //Must have a root container - Assert.IsNotNull(importedAggregateFilterContainer); + Assert.That(importedAggregateFilterContainer, Is.Not.Null); //With an AND operation - Assert.AreEqual(FilterContainerOperation.AND, importedAggregateFilterContainer.Operation); + Assert.That(importedAggregateFilterContainer.Operation, Is.EqualTo(FilterContainerOperation.AND)); var importedFilters = importedAggregateFilterContainer.GetFilters(); - Assert.AreEqual(1, importedFilters.Length); + Assert.That(importedFilters, Has.Length.EqualTo(1)); //they are not the same object - Assert.AreNotEqual(filter, importedFilters[0]); - //the deployed filter knows its parent it was cloned from - Assert.AreEqual(filter.ID, importedFilters[0].ClonedFromExtractionFilter_ID); - //the WHERE SQL of the filters should be the same - Assert.AreEqual(filter.WhereSQL, importedFilters[0].WhereSQL); + Assert.That(importedFilters[0], Is.Not.EqualTo(filter)); + Assert.Multiple(() => + { + //the deployed filter knows its parent it was cloned from + Assert.That(importedFilters[0].ClonedFromExtractionFilter_ID, Is.EqualTo(filter.ID)); + //the WHERE SQL of the filters should be the same + Assert.That(importedFilters[0].WhereSQL, Is.EqualTo(filter.WhereSQL)); + }); } finally { @@ -103,7 +106,7 @@ public void ImportCatalogueWithSingleFilterThatHasAParameter(bool createAGlobalO .CreateAll(filter, null); var filterParameters = filter.ExtractionFilterParameters.ToArray(); - Assert.AreEqual(1, filterParameters.Length); + Assert.That(filterParameters, Has.Length.EqualTo(1)); filterParameters[0].ParameterSQL = parameterSQL; filterParameters[0].Value = "'No More than 300 Dragons Please'"; @@ -122,8 +125,8 @@ public void ImportCatalogueWithSingleFilterThatHasAParameter(bool createAGlobalO //ensure that it is picked SetUp var mandatoryFilters = testData.catalogue.GetAllMandatoryFilters(); - Assert.AreEqual(1, mandatoryFilters.Length); - Assert.AreEqual(filter, mandatoryFilters[0]); + Assert.That(mandatoryFilters, Has.Length.EqualTo(1)); + Assert.That(mandatoryFilters[0], Is.EqualTo(filter)); AggregateConfiguration importedAggregate = null; @@ -135,32 +138,35 @@ public void ImportCatalogueWithSingleFilterThatHasAParameter(bool createAGlobalO var importedAggregateFilterContainer = importedAggregate.RootFilterContainer; //Must have a root container - Assert.IsNotNull(importedAggregateFilterContainer); + Assert.That(importedAggregateFilterContainer, Is.Not.Null); //With an AND operation - Assert.AreEqual(FilterContainerOperation.AND, importedAggregateFilterContainer.Operation); + Assert.That(importedAggregateFilterContainer.Operation, Is.EqualTo(FilterContainerOperation.AND)); var importedFilters = importedAggregateFilterContainer.GetFilters(); - Assert.AreEqual(1, importedFilters.Length); + Assert.That(importedFilters, Has.Length.EqualTo(1)); //Because the configuration already has a parameter with the same declaration it should not bother to import the parameter from the underlying filter if (createAGlobalOverrideBeforeHand) { - Assert.AreEqual(0, importedFilters[0].GetAllParameters().Length); + Assert.That(importedFilters[0].GetAllParameters(), Is.Empty); } else { //Because there is no global we should be creating a clone of the parameter too var paramClones = importedFilters[0].GetAllParameters(); - Assert.AreEqual(1, paramClones.Length); + Assert.That(paramClones, Has.Length.EqualTo(1)); //clone should have same SQL and Value - Assert.AreEqual(parameterSQL, paramClones[0].ParameterSQL); - Assert.AreEqual(filterParameters[0].ParameterSQL, paramClones[0].ParameterSQL); - Assert.AreEqual(filterParameters[0].Value, paramClones[0].Value); - - //but not be the same object in database - Assert.AreNotEqual(filterParameters[0], paramClones[0]); + Assert.That(paramClones[0].ParameterSQL, Is.EqualTo(parameterSQL)); + Assert.Multiple(() => + { + Assert.That(paramClones[0].ParameterSQL, Is.EqualTo(filterParameters[0].ParameterSQL)); + Assert.That(paramClones[0].Value, Is.EqualTo(filterParameters[0].Value)); + + //but not be the same object in database + Assert.That(paramClones[0], Is.Not.EqualTo(filterParameters[0])); + }); } } finally @@ -206,7 +212,7 @@ public void ImportCatalogueWithMultipleMandatoryFilters() //ensure that both are picked SetUp as mandatory filters by catalogue var mandatoryFilters = testData.catalogue.GetAllMandatoryFilters(); - Assert.AreEqual(2, mandatoryFilters.Length); + Assert.That(mandatoryFilters, Has.Length.EqualTo(2)); AggregateConfiguration importedAggregate = null; @@ -218,14 +224,14 @@ public void ImportCatalogueWithMultipleMandatoryFilters() var importedAggregateFilterContainer = importedAggregate.RootFilterContainer; //Must have a root container - Assert.IsNotNull(importedAggregateFilterContainer); + Assert.That(importedAggregateFilterContainer, Is.Not.Null); //the AND container should be there - Assert.AreEqual(FilterContainerOperation.AND, importedAggregateFilterContainer.Operation); + Assert.That(importedAggregateFilterContainer.Operation, Is.EqualTo(FilterContainerOperation.AND)); //the filters should both be there (See above test for WHERE SQL, ID etc checking) var importedFilters = importedAggregateFilterContainer.GetFilters(); - Assert.AreEqual(2, importedFilters.Length); + Assert.That(importedFilters, Has.Length.EqualTo(2)); } finally { diff --git a/Rdmp.Core.Tests/CohortCreation/PluginCohortCompilerTests.cs b/Rdmp.Core.Tests/CohortCreation/PluginCohortCompilerTests.cs index f6c00d1717..514477dfb8 100644 --- a/Rdmp.Core.Tests/CohortCreation/PluginCohortCompilerTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/PluginCohortCompilerTests.cs @@ -48,7 +48,7 @@ public void TestIPluginCohortCompiler_PopulatesCacheCorrectly() var cmd = new ExecuteCommandAddCatalogueToCohortIdentificationSetContainer(activator, new CatalogueCombineable(myApi), cic.RootCohortAggregateContainer); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); // run the cic @@ -57,7 +57,7 @@ public void TestIPluginCohortCompiler_PopulatesCacheCorrectly() var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); // 5 random chi numbers - Assert.AreEqual(5, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(5)); // test stale cmd.AggregateCreatedIfAny.Description = "2"; @@ -69,7 +69,7 @@ public void TestIPluginCohortCompiler_PopulatesCacheCorrectly() dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); // because the rules changed to generate 2 chis only there should be a new result - Assert.AreEqual(2, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); var results = new[] { (string)dt.Rows[0][0], (string)dt.Rows[1][0] }; @@ -79,11 +79,14 @@ public void TestIPluginCohortCompiler_PopulatesCacheCorrectly() source.PreInitialize(cic, ThrowImmediatelyDataLoadEventListener.Quiet); dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(2, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); var results2 = new[] { (string)dt.Rows[0][0], (string)dt.Rows[1][0] }; - Assert.AreEqual(results[0], results2[0]); - Assert.AreEqual(results[1], results2[1]); + Assert.Multiple(() => + { + Assert.That(results2[0], Is.EqualTo(results[0])); + Assert.That(results2[1], Is.EqualTo(results[1])); + }); } [Test] @@ -108,18 +111,18 @@ public void TestIPluginCohortCompiler_TestCloneCic() // create a use of the API as an AggregateConfiguration var cmd = new ExecuteCommandAddCatalogueToCohortIdentificationSetContainer(activator, new CatalogueCombineable(myApi), cic.RootCohortAggregateContainer); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); cmd.AggregateCreatedIfAny.Description = "33"; cmd.AggregateCreatedIfAny.SaveToDatabase(); // clone the cic var cmd2 = new ExecuteCommandCloneCohortIdentificationConfiguration(activator, cic); - Assert.IsFalse(cmd2.IsImpossible, cmd2.ReasonCommandImpossible); + Assert.That(cmd2.IsImpossible, Is.False, cmd2.ReasonCommandImpossible); cmd2.Execute(); var cloneAc = cmd2.CloneCreatedIfAny.RootCohortAggregateContainer.GetAggregateConfigurations()[0]; - Assert.AreEqual("33", cloneAc.Description); + Assert.That(cloneAc.Description, Is.EqualTo("33")); } [Test] @@ -144,7 +147,7 @@ public void TestIPluginCohortCompiler_APIsCantHavePatientIndexTables() // We need something in the root container otherwise the cic won't build var cmd = new ExecuteCommandAddCatalogueToCohortIdentificationSetContainer(activator, new CatalogueCombineable(myApi), cic.RootCohortAggregateContainer); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); var regularAggregate = cmd.AggregateCreatedIfAny; @@ -152,7 +155,7 @@ public void TestIPluginCohortCompiler_APIsCantHavePatientIndexTables() var cmd2 = new ExecuteCommandAddCatalogueToCohortIdentificationAsPatientIndexTable( activator, new CatalogueCombineable(myApi), cic); - Assert.IsFalse(cmd2.IsImpossible, cmd2.ReasonCommandImpossible); + Assert.That(cmd2.IsImpossible, Is.False, cmd2.ReasonCommandImpossible); cmd2.Execute(); var joinables = cic.GetAllJoinables(); @@ -161,8 +164,7 @@ public void TestIPluginCohortCompiler_APIsCantHavePatientIndexTables() var ex = Assert.Throws(() => new JoinableCohortAggregateConfigurationUse(CatalogueRepository, regularAggregate, joinables[0])); - Assert.AreEqual("API calls cannot join with PatientIndexTables (The API call must be self contained)", - ex.Message); + Assert.That(ex.Message, Is.EqualTo("API calls cannot join with PatientIndexTables (The API call must be self contained)")); } @@ -201,7 +203,7 @@ public void TestIPluginCohortCompiler_AsPatientIndexTable() // Add the regular table var cmd = new ExecuteCommandAddCatalogueToCohortIdentificationSetContainer(activator, new CatalogueCombineable(cata), cic.RootCohortAggregateContainer); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); var regularAggregate = cmd.AggregateCreatedIfAny; @@ -209,12 +211,12 @@ public void TestIPluginCohortCompiler_AsPatientIndexTable() var cmd2 = new ExecuteCommandAddCatalogueToCohortIdentificationAsPatientIndexTable( activator, new CatalogueCombineable(myApi), cic); - Assert.IsFalse(cmd2.IsImpossible, cmd2.ReasonCommandImpossible); + Assert.That(cmd2.IsImpossible, Is.False, cmd2.ReasonCommandImpossible); cmd2.Execute(); var joinables = cic.GetAllJoinables(); - Assert.AreEqual(1, joinables.Length); + Assert.That(joinables, Has.Length.EqualTo(1)); // make them join one another new JoinableCohortAggregateConfigurationUse(CatalogueRepository, regularAggregate, joinables[0]); @@ -223,6 +225,6 @@ public void TestIPluginCohortCompiler_AsPatientIndexTable() var source = new CohortIdentificationConfigurationSource(); source.PreInitialize(cic, ThrowImmediatelyDataLoadEventListener.Quiet); var result = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(1, result.Rows.Count); + Assert.That(result.Rows, Has.Count.EqualTo(1)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortCompilerCacheJoinableTest.cs b/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortCompilerCacheJoinableTest.cs index 0852492dce..be957641bd 100644 --- a/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortCompilerCacheJoinableTest.cs +++ b/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortCompilerCacheJoinableTest.cs @@ -72,7 +72,7 @@ public void CohortIdentificationConfiguration_Join_PatientIndexTable() fe.ExecuteForwardEngineering(cata); //Should now be 1 Catalogue with all the columns (tables will have to be joined to build the query though) - Assert.AreEqual(8, cata.GetAllExtractionInformation(ExtractionCategory.Core).Length); + Assert.That(cata.GetAllExtractionInformation(ExtractionCategory.Core), Has.Length.EqualTo(8)); var ji = new JoinInfo(CatalogueRepository, rTi.ColumnInfos.Single(ci => @@ -107,8 +107,11 @@ public void CohortIdentificationConfiguration_Join_PatientIndexTable() var joinable = new JoinableCohortAggregateConfiguration(CatalogueRepository, cic, acPatIndex); - Assert.IsTrue(acPatIndex.IsCohortIdentificationAggregate); - Assert.IsTrue(acPatIndex.IsJoinablePatientIndexTable()); + Assert.Multiple(() => + { + Assert.That(acPatIndex.IsCohortIdentificationAggregate); + Assert.That(acPatIndex.IsJoinablePatientIndexTable()); + }); var compiler = new CohortCompiler(cic); @@ -117,32 +120,38 @@ public void CohortIdentificationConfiguration_Join_PatientIndexTable() var cancellation = new System.Threading.CancellationToken(); runner.Run(cancellation); - //they should not be executing and should be completed - Assert.IsFalse(compiler.Tasks.Any(t => t.Value.IsExecuting)); - Assert.AreEqual(Phase.Finished, runner.ExecutionPhase); + Assert.Multiple(() => + { + //they should not be executing and should be completed + Assert.That(compiler.Tasks.Any(t => t.Value.IsExecuting), Is.False); + Assert.That(runner.ExecutionPhase, Is.EqualTo(Phase.Finished)); + }); var manager = new CachedAggregateConfigurationResultsManager(edsCache); var cacheTableName = manager.GetLatestResultsTableUnsafe(acPatIndex, AggregateOperation.JoinableInceptionQuery); - Assert.IsNotNull(cacheTableName, "No results were cached!"); + Assert.That(cacheTableName, Is.Not.Null, "No results were cached!"); var cacheTable = To.ExpectTable(cacheTableName.GetRuntimeName()); - //chi, Date and TestCode - Assert.AreEqual(3, cacheTable.DiscoverColumns().Length); + Assert.Multiple(() => + { + //chi, Date and TestCode + Assert.That(cacheTable.DiscoverColumns(), Has.Length.EqualTo(3)); - //healthboard should be a string - Assert.AreEqual(typeof(string), cacheTable.DiscoverColumn("Healthboard").DataType.GetCSharpDataType()); + //healthboard should be a string + Assert.That(cacheTable.DiscoverColumn("Healthboard").DataType.GetCSharpDataType(), Is.EqualTo(typeof(string))); - /* Query Cache contains this: - * -Chi Date Healthboard -0101010101 2001-01-01 00:00:00.0000000 T -0202020202 2002-02-02 00:00:00.0000000 T -*/ + /* Query Cache contains this: + * + Chi Date Healthboard + 0101010101 2001-01-01 00:00:00.0000000 T + 0202020202 2002-02-02 00:00:00.0000000 T + */ - Assert.AreEqual(2, cacheTable.GetRowCount()); + Assert.That(cacheTable.GetRowCount(), Is.EqualTo(2)); + }); //Now we could add a new AggregateConfiguration that uses the joinable! } diff --git a/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderTests.cs b/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderTests.cs index 768eac84db..803e3cbed2 100644 --- a/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderTests.cs @@ -26,13 +26,12 @@ public void TestGettingAggregateJustFromConfig_DistinctCHISelect() { var builder = new CohortQueryBuilder(aggregate1, null, null); - Assert.AreEqual(CollapseWhitespace(string.Format(@"/*cic_{0}_UnitTestAggregate1*/ + Assert.That(CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace(string.Format(@"/*cic_{0}_UnitTestAggregate1*/ SELECT distinct [" + _scratchDatabaseName + @"].[dbo].[BulkData].[chi] FROM -[" + _scratchDatabaseName + @"].[dbo].[BulkData]", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builder.SQL)); +[" + _scratchDatabaseName + @"].[dbo].[BulkData]", cohortIdentificationConfiguration.ID)))); } [Test] @@ -40,14 +39,13 @@ public void TestGettingAggregateJustFromConfig_SelectStar() { var builder = new CohortQueryBuilder(aggregate1, null, null); - Assert.AreEqual(CollapseWhitespace( + Assert.That(CollapseWhitespace(builder.GetDatasetSampleSQL()), Is.EqualTo(CollapseWhitespace( string.Format(@"/*cic_{0}_UnitTestAggregate1*/ SELECT TOP 1000 * FROM - [" + _scratchDatabaseName + @"].[dbo].[BulkData]", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builder.GetDatasetSampleSQL())); + [" + _scratchDatabaseName + @"].[dbo].[BulkData]", cohortIdentificationConfiguration.ID)))); } @@ -63,7 +61,7 @@ public void Test_GetDatasetSampleSQL_WithHAVING() var builder = new CohortQueryBuilder(aggregate1, null, null); - Assert.AreEqual(CollapseWhitespace( + Assert.That(CollapseWhitespace(builder.GetDatasetSampleSQL()), Is.EqualTo(CollapseWhitespace( string.Format(@"/*cic_{0}_UnitTestAggregate1*/ SELECT distinct @@ -74,14 +72,14 @@ TOP 1000 group by [" + _scratchDatabaseName + @"].[dbo].[BulkData].[chi] HAVING - count(*)>1", cohortIdentificationConfiguration.ID)), CollapseWhitespace(builder.GetDatasetSampleSQL())); + count(*)>1", cohortIdentificationConfiguration.ID)))); } [Test] public void TestGettingAggregateSQLFromEntirity() { - Assert.AreEqual(null, aggregate1.GetCohortAggregateContainerIfAny()); + Assert.That(aggregate1.GetCohortAggregateContainerIfAny(), Is.EqualTo(null)); //set the order so that 2 comes before 1 rootcontainer.AddChild(aggregate2, 1); @@ -89,11 +87,11 @@ public void TestGettingAggregateSQLFromEntirity() var builder = new CohortQueryBuilder(cohortIdentificationConfiguration, null); - Assert.AreEqual(rootcontainer, aggregate1.GetCohortAggregateContainerIfAny()); + Assert.That(aggregate1.GetCohortAggregateContainerIfAny(), Is.EqualTo(rootcontainer)); try { - Assert.AreEqual( - CollapseWhitespace(string.Format( + Assert.That( +CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace(string.Format( @"( /*cic_{0}_UnitTestAggregate2*/ SELECT @@ -112,7 +110,7 @@ public void TestGettingAggregateSQLFromEntirity() [" + _scratchDatabaseName + @"].[dbo].[BulkData] )" , cohortIdentificationConfiguration.ID)) - , CollapseWhitespace(builder.SQL)); +)); } finally { @@ -141,13 +139,15 @@ public void TestOrdering_AggregateThenContainer() try { var allConfigurations = rootcontainer.GetAllAggregateConfigurationsRecursively(); - Assert.IsTrue(allConfigurations.Contains(aggregate1)); - Assert.IsTrue(allConfigurations.Contains(aggregate2)); - Assert.IsTrue(allConfigurations.Contains(aggregate3)); + Assert.That(allConfigurations, Does.Contain(aggregate1)); + Assert.That(allConfigurations, Does.Contain(aggregate2)); + Assert.Multiple(() => + { + Assert.That(allConfigurations, Does.Contain(aggregate3)); - Assert.AreEqual( - CollapseWhitespace(string.Format( - @"( + Assert.That( + CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace(string.Format( + @"( /*cic_{0}_UnitTestAggregate1*/ SELECT distinct @@ -177,8 +177,8 @@ public void TestOrdering_AggregateThenContainer() ) )", cohortIdentificationConfiguration.ID)) - , - CollapseWhitespace(builder.SQL)); + )); + }); } finally { @@ -207,8 +207,8 @@ public void TestOrdering_ContainerThenAggregate() try { - Assert.AreEqual( - CollapseWhitespace( + Assert.That( +CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"( @@ -240,7 +240,7 @@ public void TestOrdering_ContainerThenAggregate() FROM [" + _scratchDatabaseName + @"].[dbo].[BulkData] )", cohortIdentificationConfiguration.ID)) - , CollapseWhitespace(builder.SQL)); +)); } finally { @@ -285,8 +285,8 @@ public void TestGettingAggregateSQLFromEntirity_IncludingParametersAtTop() try { - Assert.AreEqual( - CollapseWhitespace( + Assert.That( +CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"DECLARE @abracadabra AS int; SET @abracadabra=1; @@ -314,12 +314,12 @@ public void TestGettingAggregateSQLFromEntirity_IncludingParametersAtTop() ) ) ", cohortIdentificationConfiguration.ID)) - , CollapseWhitespace(builder.SQL)); +)); var builder2 = new CohortQueryBuilder(aggregate1, null, null); - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builder2.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"DECLARE @abracadabra AS int; SET @abracadabra=1; @@ -333,14 +333,13 @@ public void TestGettingAggregateSQLFromEntirity_IncludingParametersAtTop() ( /*hithere*/ 1=@abracadabra -)", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builder2.SQL)); +)", cohortIdentificationConfiguration.ID)))); var selectStar = new CohortQueryBuilder(aggregate1, null, null).GetDatasetSampleSQL(); - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(selectStar), Is.EqualTo(CollapseWhitespace( string.Format( @"DECLARE @abracadabra AS int; SET @abracadabra=1; @@ -355,8 +354,7 @@ TOP 1000 ( /*hithere*/ 1=@abracadabra - )", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(selectStar)); + )", cohortIdentificationConfiguration.ID)))); } finally { @@ -383,8 +381,8 @@ public void TestGettingAggregateSQLFromEntirity_StopEarly() try { - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @" ( @@ -404,16 +402,15 @@ public void TestGettingAggregateSQLFromEntirity_StopEarly() FROM [" + _scratchDatabaseName + @"].[dbo].[BulkData] ) -", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builder.SQL)); +", cohortIdentificationConfiguration.ID)))); var builder2 = new CohortQueryBuilder(rootcontainer, null, null) { StopContainerWhenYouReach = null }; - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builder2.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @" ( @@ -442,8 +439,7 @@ public void TestGettingAggregateSQLFromEntirity_StopEarly() FROM [" + _scratchDatabaseName + @"].[dbo].[BulkData] ) -", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builder2.SQL)); +", cohortIdentificationConfiguration.ID)))); } finally { @@ -485,8 +481,8 @@ Aggregate 4 try { - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @" ( @@ -519,8 +515,7 @@ Aggregate 4 ) ) -", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builder.SQL)); +", cohortIdentificationConfiguration.ID)))); } finally { @@ -550,8 +545,8 @@ public void TestHavingSQL() rootcontainer.AddChild(container1); var builder = new CohortQueryBuilder(rootcontainer, null, null); - Assert.AreEqual( - CollapseWhitespace( + Assert.That( +CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @" ( @@ -593,7 +588,7 @@ group by ) ", cohortIdentificationConfiguration.ID)) - , CollapseWhitespace(builder.SQL)); +)); } finally { @@ -670,8 +665,8 @@ public void TestGettingAggregateSQLFromEntirity_TwoFilterParametersPerDataset(bo try { if (valuesAreSame) - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"DECLARE @bob AS varchar(10); SET @bob='Boom!'; @@ -709,11 +704,10 @@ public void TestGettingAggregateSQLFromEntirity_TwoFilterParametersPerDataset(bo @bob = 'bob' ) ) -", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builder.SQL)); +", cohortIdentificationConfiguration.ID)))); else - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"DECLARE @bob AS varchar(10); SET @bob='Grenades Are Go'; @@ -753,8 +747,7 @@ public void TestGettingAggregateSQLFromEntirity_TwoFilterParametersPerDataset(bo @bob_2 = 'bob' ) ) -", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builder.SQL)); +", cohortIdentificationConfiguration.ID)))); } finally { @@ -774,7 +767,7 @@ public void TestGettingAggregateSQLFromEntirity_TwoFilterParametersPerDataset(bo [Test] public void TestGettingAggregateSQL_Aggregate_IsDisabled() { - Assert.AreEqual(null, aggregate1.GetCohortAggregateContainerIfAny()); + Assert.That(aggregate1.GetCohortAggregateContainerIfAny(), Is.EqualTo(null)); //set the order so that 2 comes before 1 rootcontainer.AddChild(aggregate2, 1); @@ -784,13 +777,13 @@ public void TestGettingAggregateSQL_Aggregate_IsDisabled() aggregate1.IsDisabled = true; aggregate1.SaveToDatabase(); - Assert.AreEqual(rootcontainer, aggregate1.GetCohortAggregateContainerIfAny()); + Assert.That(aggregate1.GetCohortAggregateContainerIfAny(), Is.EqualTo(rootcontainer)); var builder = new CohortQueryBuilder(cohortIdentificationConfiguration, null); try { - Assert.AreEqual( - CollapseWhitespace(string.Format( + Assert.That( +CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace(string.Format( @"( /*cic_{0}_UnitTestAggregate2*/ SELECT @@ -800,7 +793,7 @@ public void TestGettingAggregateSQL_Aggregate_IsDisabled() [" + _scratchDatabaseName + @"].[dbo].[BulkData] )" , cohortIdentificationConfiguration.ID)) - , CollapseWhitespace(builder.SQL)); +)); } finally { @@ -866,8 +859,8 @@ public void TestGettingAggregateSQLFromEntirity_Filter_IsDisabled() try { - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"DECLARE @bob AS varchar(10); SET @bob='Grenades Are Go'; @@ -904,8 +897,7 @@ public void TestGettingAggregateSQLFromEntirity_Filter_IsDisabled() @bob_2 = 'bob' ) ) -", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builder.SQL)); +", cohortIdentificationConfiguration.ID)))); } finally { diff --git a/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderTestsInvolvingTableValuedParameters.cs b/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderTestsInvolvingTableValuedParameters.cs index 032b99c501..b5c2557ddc 100644 --- a/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderTestsInvolvingTableValuedParameters.cs +++ b/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderTestsInvolvingTableValuedParameters.cs @@ -15,9 +15,9 @@ namespace Rdmp.Core.Tests.CohortCreation.QueryTests; public class CohortQueryBuilderTestsInvolvingTableValuedParameters : DatabaseTests { - private TestableTableValuedFunction _function = new(); + private readonly TestableTableValuedFunction _function = new(); - public void CreateFunction() + private void CreateFunction() { _function.Create(GetCleanedServer(DatabaseType.MicrosoftSQLServer), CatalogueRepository); } @@ -58,7 +58,7 @@ public void CohortGenerationDifferingTableValuedParametersTest() new AggregateDimension(CatalogueRepository, _function.ExtractionInformations[1], config1); new AggregateDimension(CatalogueRepository, _function.ExtractionInformations[1], config2); - Assert.IsNull(cic.RootCohortAggregateContainer_ID); + Assert.That(cic.RootCohortAggregateContainer_ID, Is.Null); //create a root container for it var container = new CohortAggregateContainer(CatalogueRepository, SetOperation.INTERSECT); @@ -72,8 +72,8 @@ public void CohortGenerationDifferingTableValuedParametersTest() container.AddChild(config2, 1); var builder = new CohortQueryBuilder(cic, null); - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"DECLARE @startNumber AS int; SET @startNumber=5; @@ -101,8 +101,7 @@ public void CohortGenerationDifferingTableValuedParametersTest() [" + TestDatabaseNames.Prefix + @"ScratchArea]..MyAwesomeFunction(@startNumber,@stopNumber,@name) AS MyAwesomeFunction ) -", cic.ID)), - CollapseWhitespace(builder.SQL)); +", cic.ID)))); //now override JUST @name var param1 = new AnyTableSqlParameter(CatalogueRepository, config1, "DECLARE @name AS varchar(50);") @@ -119,8 +118,8 @@ public void CohortGenerationDifferingTableValuedParametersTest() var builder2 = new CohortQueryBuilder(cic, null); - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builder2.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"DECLARE @startNumber AS int; SET @startNumber=5; @@ -150,8 +149,7 @@ public void CohortGenerationDifferingTableValuedParametersTest() [" + TestDatabaseNames.Prefix + @"ScratchArea]..MyAwesomeFunction(@startNumber,@stopNumber,@name_2) AS MyAwesomeFunction ) -", cic.ID)), - CollapseWhitespace(builder2.SQL)); +", cic.ID)))); } finally { diff --git a/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderWithCacheTests.cs b/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderWithCacheTests.cs index ea1a9f1478..731a8cd79c 100644 --- a/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderWithCacheTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortQueryBuilderWithCacheTests.cs @@ -59,8 +59,8 @@ public void TestGettingAggregateJustFromConfig_DistinctCHISelect() var builder = new CohortQueryBuilder(cohortIdentificationConfiguration, null); try { - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @" ( @@ -71,8 +71,7 @@ public void TestGettingAggregateJustFromConfig_DistinctCHISelect() FROM [" + TestDatabaseNames.Prefix + @"ScratchArea].[dbo].[BulkData] ) -", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builder.SQL)); +", cohortIdentificationConfiguration.ID)))); var server = queryCacheDatabase.Server; using (var con = server.GetConnection()) @@ -96,8 +95,8 @@ public void TestGettingAggregateJustFromConfig_DistinctCHISelect() var builderCached = new CohortQueryBuilder(cohortIdentificationConfiguration, null); - Assert.AreEqual( - CollapseWhitespace( + Assert.That( + CollapseWhitespace(builderCached.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @" ( @@ -106,8 +105,7 @@ public void TestGettingAggregateJustFromConfig_DistinctCHISelect() "]..[IndexedExtractionIdentifierList_AggregateConfiguration" + aggregate1.ID + @"] ) -", cohortIdentificationConfiguration.ID)), - CollapseWhitespace(builderCached.SQL)); +", cohortIdentificationConfiguration.ID)))); } finally { diff --git a/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortSummaryQueryBuilderTests.cs b/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortSummaryQueryBuilderTests.cs index caeab8701c..a5dbc7f59d 100644 --- a/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortSummaryQueryBuilderTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/QueryTests/CohortSummaryQueryBuilderTests.cs @@ -85,18 +85,16 @@ protected override void SetUp() public void ConstructorArguments_SameAggregateTwice() { var ex = Assert.Throws(() => new CohortSummaryQueryBuilder(acCohort, acCohort, null)); - Assert.AreEqual( - "Summary and Cohort should be different aggregates. Summary should be a graphable useful aggregate while cohort should return a list of private identifiers", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Summary and Cohort should be different aggregates. Summary should be a graphable useful aggregate while cohort should return a list of private identifiers")); } [Test] public void ConstructorArguments_Param1AccidentallyACohort() { var ex = Assert.Throws(() => new CohortSummaryQueryBuilder(acCohort, acDataset, null)); - Assert.AreEqual( - "The first argument to constructor CohortSummaryQueryBuilder should be a basic AggregateConfiguration (i.e. not a cohort) but the argument you passed ('cic_Agg1_Cohort') was a cohort identification configuration aggregate", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("The first argument to constructor CohortSummaryQueryBuilder should be a basic AggregateConfiguration (i.e. not a cohort) but the argument you passed ('cic_Agg1_Cohort') was a cohort identification configuration aggregate")); } [Test] @@ -105,9 +103,8 @@ public void ConstructorArguments_Param2AccidentallyAnAggregate() //change it in memory so it doesn't look like a cohort aggregate anymore acCohort.Name = "RegularAggregate"; var ex = Assert.Throws(() => new CohortSummaryQueryBuilder(acDataset, acCohort, null)); - Assert.AreEqual( - "The second argument to constructor CohortSummaryQueryBuilder should be a cohort identification aggregate (i.e. have a single AggregateDimension marked IsExtractionIdentifier and have a name starting with cic_) but the argument you passed ('RegularAggregate') was NOT a cohort identification configuration aggregate", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("The second argument to constructor CohortSummaryQueryBuilder should be a cohort identification aggregate (i.e. have a single AggregateDimension marked IsExtractionIdentifier and have a name starting with cic_) but the argument you passed ('RegularAggregate') was NOT a cohort identification configuration aggregate")); acCohort.RevertToDatabaseState(); } @@ -117,9 +114,8 @@ public void ConstructorArguments_DifferentDatasets() acCohort.Catalogue_ID = -999999; var ex = Assert.Throws(() => new CohortSummaryQueryBuilder(acDataset, acCohort, null)); - Assert.IsTrue( - ex.Message.StartsWith( - "Constructor arguments to CohortSummaryQueryBuilder must belong to the same dataset")); + Assert.That( + ex.Message, Does.StartWith("Constructor arguments to CohortSummaryQueryBuilder must belong to the same dataset")); acCohort.RevertToDatabaseState(); } @@ -137,7 +133,7 @@ public void QueryGeneration_BasicQuery() { var sql = acDataset.GetQueryBuilder().SQL; - Assert.AreEqual(@"/*Agg2_Dataset*/ + Assert.That(sql, Is.EqualTo(@"/*Agg2_Dataset*/ SELECT Year, count(*) AS MyCount @@ -146,7 +142,7 @@ public void QueryGeneration_BasicQuery() group by Year order by -Year", sql); +Year")); } [Test] @@ -157,7 +153,7 @@ public void QueryGeneration_WithLinkedCohort_WHERECHIIN() var ex = Assert.Throws(() => csqb.GetAdjustedAggregateBuilder(CohortSummaryAdjustment.WhereExtractionIdentifiersIn)); - Assert.AreEqual("No Query Caching Server configured", ex.Message); + Assert.That(ex.Message, Is.EqualTo("No Query Caching Server configured")); } [Test] @@ -172,7 +168,7 @@ public void QueryGeneration_Parameters_DifferentValues_WHERECHIIN() var ex = Assert.Throws(() => csqb.GetAdjustedAggregateBuilder(CohortSummaryAdjustment.WhereExtractionIdentifiersIn)); - Assert.AreEqual("No Query Caching Server configured", ex.Message); + Assert.That(ex.Message, Is.EqualTo("No Query Caching Server configured")); } finally { @@ -188,7 +184,7 @@ public void QueryGeneration_NoCohortWhereLogic() var builder = csqb.GetAdjustedAggregateBuilder(CohortSummaryAdjustment.WhereRecordsIn); - Assert.AreEqual(@"/*Agg2_Dataset*/ + Assert.That(builder.SQL, Is.EqualTo(@"/*Agg2_Dataset*/ SELECT Year, count(*) AS MyCount @@ -197,7 +193,7 @@ public void QueryGeneration_NoCohortWhereLogic() group by Year order by -Year", builder.SQL); +Year")); } [Test] @@ -218,7 +214,7 @@ public void QueryGeneration_BothHaveWHEREContainerAndParameters() var builder = csqb.GetAdjustedAggregateBuilder(CohortSummaryAdjustment.WhereRecordsIn); - Assert.AreEqual(CollapseWhitespace(@"DECLARE @bob AS varchar(50); + Assert.That(CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace(@"DECLARE @bob AS varchar(50); SET @bob='zomber'; /*Agg2_Dataset*/ SELECT @@ -242,7 +238,7 @@ public void QueryGeneration_BothHaveWHEREContainerAndParameters() group by Year order by -Year"), CollapseWhitespace(builder.SQL)); +Year"))); } finally { diff --git a/Rdmp.Core.Tests/CohortCreation/QueryTests/JoinableCohortConfigurationTests.cs b/Rdmp.Core.Tests/CohortCreation/QueryTests/JoinableCohortConfigurationTests.cs index 297f2aaf1e..b07f94ed60 100644 --- a/Rdmp.Core.Tests/CohortCreation/QueryTests/JoinableCohortConfigurationTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/QueryTests/JoinableCohortConfigurationTests.cs @@ -39,8 +39,11 @@ public void CreateJoinable() joinable = new JoinableCohortAggregateConfiguration(CatalogueRepository, cohortIdentificationConfiguration, aggregate1); - Assert.AreEqual(joinable.CohortIdentificationConfiguration_ID, cohortIdentificationConfiguration.ID); - Assert.AreEqual(joinable.AggregateConfiguration_ID, aggregate1.ID); + Assert.Multiple(() => + { + Assert.That(cohortIdentificationConfiguration.ID, Is.EqualTo(joinable.CohortIdentificationConfiguration_ID)); + Assert.That(aggregate1.ID, Is.EqualTo(joinable.AggregateConfiguration_ID)); + }); } finally { @@ -56,9 +59,8 @@ public void CreateJoinable_IsAlreadyInAContainer() var ex = Assert.Throws(() => new JoinableCohortAggregateConfiguration(CatalogueRepository, cohortIdentificationConfiguration, aggregate1)); - Assert.AreEqual( - "Cannot make aggregate UnitTestAggregate1 into a Joinable aggregate because it is already in a CohortAggregateContainer", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Cannot make aggregate UnitTestAggregate1 into a Joinable aggregate because it is already in a CohortAggregateContainer")); cohortIdentificationConfiguration.RootCohortAggregateContainer.RemoveChild(aggregate1); } @@ -72,9 +74,8 @@ public void CreateJoinable_NoIsExtractionIdentifier() var ex = Assert.Throws(() => new JoinableCohortAggregateConfiguration(CatalogueRepository, cohortIdentificationConfiguration, aggregate1)); - Assert.AreEqual( - "Cannot make aggregate UnitTestAggregate1 into a Joinable aggregate because it has 0 columns marked IsExtractionIdentifier", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Cannot make aggregate UnitTestAggregate1 into a Joinable aggregate because it has 0 columns marked IsExtractionIdentifier")); } [Test] @@ -90,7 +91,7 @@ public void CreateJoinable_AddTwice() var ex = Assert.Throws(() => new JoinableCohortAggregateConfiguration(CatalogueRepository, cohortIdentificationConfiguration, aggregate1)); - Assert.IsTrue(ex.Message.Contains("ix_eachAggregateCanOnlyBeJoinableOnOneProject")); + Assert.That(ex.Message, Does.Contain("ix_eachAggregateCanOnlyBeJoinableOnOneProject")); } } finally @@ -109,8 +110,8 @@ public void CreateUsers() aggregate1); joinable.AddUser(aggregate2); - Assert.IsTrue(joinable.Users.Length == 1); - Assert.AreEqual(aggregate2, joinable.Users[0].AggregateConfiguration); + Assert.That(joinable.Users, Has.Length.EqualTo(1)); + Assert.That(joinable.Users[0].AggregateConfiguration, Is.EqualTo(aggregate2)); } finally { @@ -128,9 +129,8 @@ public void CreateUsers_DuplicateUser() { joinable.AddUser(aggregate2); var ex = Assert.Throws(() => joinable.AddUser(aggregate2)); - Assert.AreEqual( - $"AggregateConfiguration 'UnitTestAggregate2' already uses 'Patient Index Table:cic_{cohortIdentificationConfiguration.ID}_UnitTestAggregate1'. Only one patient index table join is permitted.", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo($"AggregateConfiguration 'UnitTestAggregate2' already uses 'Patient Index Table:cic_{cohortIdentificationConfiguration.ID}_UnitTestAggregate1'. Only one patient index table join is permitted.")); } finally { @@ -147,8 +147,7 @@ public void CreateUsers_SelfReferrential() try { var ex = Assert.Throws(() => joinable.AddUser(aggregate1)); - Assert.AreEqual("Cannot configure AggregateConfiguration UnitTestAggregate1 as a Join user to itself!", - ex.Message); + Assert.That(ex.Message, Is.EqualTo("Cannot configure AggregateConfiguration UnitTestAggregate1 as a Join user to itself!")); } finally { @@ -168,9 +167,8 @@ public void CreateUsers_ToAnyOtherJoinable() try { var ex = Assert.Throws(() => joinable.AddUser(aggregate2)); - Assert.AreEqual( - "Cannot add user UnitTestAggregate2 because that AggregateConfiguration is itself a JoinableCohortAggregateConfiguration", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Cannot add user UnitTestAggregate2 because that AggregateConfiguration is itself a JoinableCohortAggregateConfiguration")); } finally { @@ -192,9 +190,8 @@ public void CreateUsers_ToNoExtractionIdentifierTable() try { var ex = Assert.Throws(() => joinable.AddUser(aggregate2)); - Assert.AreEqual( - "Cannot configure AggregateConfiguration UnitTestAggregate2 as join user because it does not contain exactly 1 IsExtractionIdentifier dimension", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Cannot configure AggregateConfiguration UnitTestAggregate2 as join user because it does not contain exactly 1 IsExtractionIdentifier dimension")); } finally { @@ -222,14 +219,14 @@ public void QueryBuilderTest() using var dbReader = new SqlCommand(builder.SQL, con).ExecuteReader(); //can read at least one row - Assert.IsTrue(dbReader.Read()); + Assert.That(dbReader.Read()); } var expectedTableAlias = $"ix{joinable2.ID}"; //after joinables - Assert.AreEqual( - string.Format( + Assert.That( +builder.SQL, Is.EqualTo(string.Format( @"/*cic_{1}_UnitTestAggregate1*/ SELECT distinct @@ -245,7 +242,7 @@ LEFT Join ( [" + TestDatabaseNames.Prefix + @"ScratchArea].[dbo].[BulkData] ){0} on [" + TestDatabaseNames.Prefix + @"ScratchArea].[dbo].[BulkData].[chi] = {0}.chi", expectedTableAlias, - cohortIdentificationConfiguration.ID), builder.SQL); + cohortIdentificationConfiguration.ID))); } finally { @@ -305,13 +302,13 @@ public void QueryBuilderTest_AdditionalColumn() using var dbReader = new SqlCommand(builder.SQL, con).ExecuteReader(); //can read at least one row - Assert.IsTrue(dbReader.Read()); + Assert.That(dbReader.Read()); } //after joinables - Assert.AreEqual( - CollapseWhitespace( + Assert.That( +CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"/*cic_{1}_UnitTestAggregate1*/ SELECT @@ -338,7 +335,7 @@ SELECT distinct ( /*Within 1 year of event*/ ABS(DATEDIFF(year, {0}.dtCreated, [" + TestDatabaseNames.Prefix + @"ScratchArea].[dbo].[BulkData].dtCreated)) <= 1 -)", expectedTableAlias, cohortIdentificationConfiguration.ID)), CollapseWhitespace(builder.SQL)); +)", expectedTableAlias, cohortIdentificationConfiguration.ID)))); } finally { @@ -430,7 +427,7 @@ public void QueryBuilderTest_JoinableCloning() Console.WriteLine( "//////////////////////////////////////////////END COMPARISON//////////////////////////////////////////////"); - Assert.AreEqual(builderSql, cloneBuilderSql); + Assert.That(cloneBuilderSql, Is.EqualTo(builderSql)); ////////////////Cleanup Database////////////////////////////// @@ -525,14 +522,14 @@ public void JoinablesWithCache() using var dbReader = new SqlCommand(builder.SQL, con).ExecuteReader(); //can read at least one row - Assert.IsTrue(dbReader.Read()); + Assert.That(dbReader.Read()); } var expectedTableAlias = $"ix{joinable2.ID}"; //after joinables - Assert.AreEqual( - CollapseWhitespace( + Assert.That( +CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"/*cic_{2}_UnitTestAggregate1*/ SELECT @@ -550,7 +547,7 @@ LEFT Join ( aggregate2.ID, //{1} cohortIdentificationConfiguration.ID, //{2} queryCachingDatabaseName) //{3} - ), CollapseWhitespace(builder.SQL)); + ))); } finally { diff --git a/Rdmp.Core.Tests/CohortCreation/SimpleCohortIdentificationTests.cs b/Rdmp.Core.Tests/CohortCreation/SimpleCohortIdentificationTests.cs index 13cf973454..d8dfa093af 100644 --- a/Rdmp.Core.Tests/CohortCreation/SimpleCohortIdentificationTests.cs +++ b/Rdmp.Core.Tests/CohortCreation/SimpleCohortIdentificationTests.cs @@ -20,20 +20,23 @@ public void CreateNewCohortIdentificationConfiguration_SaveAndReload() try { - Assert.IsTrue(config.Exists()); - Assert.AreEqual("franky", config.Name); + Assert.Multiple(() => + { + Assert.That(config.Exists()); + Assert.That(config.Name, Is.EqualTo("franky")); + }); config.Description = "Hi there"; config.SaveToDatabase(); var config2 = CatalogueRepository.GetObjectByID(config.ID); - Assert.AreEqual("Hi there", config2.Description); + Assert.That(config2.Description, Is.EqualTo("Hi there")); } finally { config.DeleteInDatabase(); - Assert.IsFalse(config.Exists()); + Assert.That(config.Exists(), Is.False); } } @@ -44,13 +47,13 @@ public void ContainerCreate() try { - Assert.AreEqual(SetOperation.UNION, container.Operation); + Assert.That(container.Operation, Is.EqualTo(SetOperation.UNION)); container.Operation = SetOperation.INTERSECT; container.SaveToDatabase(); var container2 = CatalogueRepository.GetObjectByID(container.ID); - Assert.AreEqual(SetOperation.INTERSECT, container2.Operation); + Assert.That(container2.Operation, Is.EqualTo(SetOperation.INTERSECT)); } finally { @@ -67,20 +70,23 @@ public void Container_Subcontainering() var container2 = new CohortAggregateContainer(CatalogueRepository, SetOperation.INTERSECT); try { - Assert.AreEqual(0, container.GetSubContainers().Length); + Assert.That(container.GetSubContainers(), Is.Empty); - Assert.AreEqual(0, container.GetSubContainers().Length); + Assert.That(container.GetSubContainers(), Is.Empty); //set container to parent container.AddChild(container2); //container 1 should now contain container 2 - Assert.AreEqual(1, container.GetSubContainers().Length); - Assert.Contains(container2, container.GetSubContainers()); - - //container 2 should not have any children - Assert.AreEqual(0, container2.GetSubContainers().Length); + Assert.That(container.GetSubContainers(), Has.Length.EqualTo(1)); + Assert.Multiple(() => + { + Assert.That(container.GetSubContainers(), Does.Contain(container2)); + + //container 2 should not have any children + Assert.That(container2.GetSubContainers(), Is.Empty); + }); } finally { diff --git a/Rdmp.Core.Tests/CommandExecution/AxisAndPivotCLITests.cs b/Rdmp.Core.Tests/CommandExecution/AxisAndPivotCLITests.cs index 3597a350ce..6de240d339 100644 --- a/Rdmp.Core.Tests/CommandExecution/AxisAndPivotCLITests.cs +++ b/Rdmp.Core.Tests/CommandExecution/AxisAndPivotCLITests.cs @@ -21,9 +21,8 @@ public void SetPivot_DimensionNonExistant() var cmd = new ExecuteCommandSetPivot(GetMockActivator(), ac, "fff"); var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual( - "Could not find AggregateDimension fff in Aggregate My graph so could not set it as a pivot dimension. Try adding the column to the aggregate first", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Could not find AggregateDimension fff in Aggregate My graph so could not set it as a pivot dimension. Try adding the column to the aggregate first")); } [Test] @@ -39,12 +38,12 @@ public void SetPivot_Exists() var cmd = new ExecuteCommandSetPivot(GetMockActivator(), ac, "frogmarch"); cmd.Execute(); - Assert.AreEqual(dim.ID, ac.PivotOnDimensionID); + Assert.That(ac.PivotOnDimensionID, Is.EqualTo(dim.ID)); cmd = new ExecuteCommandSetPivot(GetMockActivator(), ac, null); cmd.Execute(); - Assert.IsNull(ac.PivotOnDimensionID); + Assert.That(ac.PivotOnDimensionID, Is.Null); } [Test] @@ -61,8 +60,7 @@ public void SetPivot_ExistsButIsADate() var cmd = new ExecuteCommandSetPivot(GetMockActivator(), ac, "frogmarch"); var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual("AggregateDimension frogmarch is a Date so cannot set it as a Pivot for Aggregate My graph", - ex.Message); + Assert.That(ex.Message, Is.EqualTo("AggregateDimension frogmarch is a Date so cannot set it as a Pivot for Aggregate My graph")); } [Test] @@ -73,9 +71,8 @@ public void SetAxis_DimensionNonExistant() var cmd = new ExecuteCommandSetAxis(GetMockActivator(), ac, "fff"); var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual( - "Could not find AggregateDimension fff in Aggregate My graph so could not set it as an axis dimension. Try adding the column to the aggregate first", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Could not find AggregateDimension fff in Aggregate My graph so could not set it as an axis dimension. Try adding the column to the aggregate first")); } [Test] @@ -89,17 +86,17 @@ public void SetAxis_Exists() dim.Alias = "frogmarch"; dim.ColumnInfo.Data_type = "datetime"; - Assert.IsNull(ac.GetAxisIfAny()); + Assert.That(ac.GetAxisIfAny(), Is.Null); var cmd = new ExecuteCommandSetAxis(GetMockActivator(), ac, "frogmarch"); cmd.Execute(); - Assert.IsNotNull(ac.GetAxisIfAny()); + Assert.That(ac.GetAxisIfAny(), Is.Not.Null); cmd = new ExecuteCommandSetAxis(GetMockActivator(), ac, null); cmd.Execute(); - Assert.IsNull(ac.GetAxisIfAny()); + Assert.That(ac.GetAxisIfAny(), Is.Null); } [Test] @@ -115,7 +112,6 @@ public void SetAxis_ExistsButIsNotADate() var cmd = new ExecuteCommandSetAxis(GetMockActivator(), ac, "frogmarch"); var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual("AggregateDimension frogmarch is not a Date so cannot set it as an axis for Aggregate My graph", - ex.Message); + Assert.That(ex.Message, Is.EqualTo("AggregateDimension frogmarch is not a Date so cannot set it as an axis for Aggregate My graph")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/CommandCliTests.cs b/Rdmp.Core.Tests/CommandExecution/CommandCliTests.cs index 246768e000..fb3f04fa1f 100644 --- a/Rdmp.Core.Tests/CommandExecution/CommandCliTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/CommandCliTests.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using NSubstitute; using Rdmp.Core.CommandExecution; using Rdmp.Core.CommandLine.Interactive; @@ -31,12 +32,19 @@ protected CommandInvoker GetInvoker() { DisallowInput = true }); - invoker.CommandImpossible += (s, c) => throw new Exception(c.Command.ReasonCommandImpossible); + invoker.CommandImpossible += static (s, c) => throw new Exception(c.Command.ReasonCommandImpossible); return invoker; } - protected IBasicActivateItems GetMockActivator() + private readonly Lazy _mockActivator; + + protected CommandCliTests() + { + _mockActivator = new Lazy(MakeMockActivator, LazyThreadSafetyMode.ExecutionAndPublication); + } + + private IBasicActivateItems MakeMockActivator() { var mock = Substitute.For(); mock.RepositoryLocator.Returns(RepositoryLocator); @@ -44,6 +52,8 @@ protected IBasicActivateItems GetMockActivator() return mock; } + protected IBasicActivateItems GetMockActivator() => _mockActivator.Value; + /// /// Runs the provided string which should start after the cmd e.g. the bit after rdmp cmd /// diff --git a/Rdmp.Core.Tests/CommandExecution/CommandInvokerTests.cs b/Rdmp.Core.Tests/CommandExecution/CommandInvokerTests.cs index 145adca75f..d3705a678a 100644 --- a/Rdmp.Core.Tests/CommandExecution/CommandInvokerTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/CommandInvokerTests.cs @@ -72,7 +72,7 @@ public override void Execute() { base.Execute(); Console.Write($"Arg was {_arg}"); - Assert.IsNotNull(_arg); + Assert.That(_arg, Is.Not.Null); } } @@ -92,8 +92,11 @@ public override void Execute() base.Execute(); Console.Write($"_a was {_a}"); Console.Write($"_b was {_b}"); - Assert.IsNotNull(_a); - Assert.IsNotNull(_b); + Assert.Multiple(() => + { + Assert.That(_a, Is.Not.Null); + Assert.That(_b, Is.Not.Null); + }); } } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAddNewFilterContainerTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAddNewFilterContainerTests.cs index 17e77483b2..007559bc8a 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAddNewFilterContainerTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAddNewFilterContainerTests.cs @@ -21,14 +21,17 @@ public void TestNormalCase() var ac = WhenIHaveA(); var cmd = new ExecuteCommandAddNewFilterContainer(new ThrowImmediatelyActivator(RepositoryLocator), ac); - Assert.IsNull(ac.RootFilterContainer_ID); + Assert.Multiple(() => + { + Assert.That(ac.RootFilterContainer_ID, Is.Null); - Assert.IsNull(cmd.ReasonCommandImpossible); - Assert.IsFalse(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Is.Null); + Assert.That(cmd.IsImpossible, Is.False); + }); cmd.Execute(); - Assert.IsNotNull(ac.RootFilterContainer_ID); + Assert.That(ac.RootFilterContainer_ID, Is.Not.Null); } [Test] @@ -37,12 +40,15 @@ public void Impossible_BecauseAlreadyHasContainer() var ac = WhenIHaveA(); ac.CreateRootContainerIfNotExists(); - Assert.IsNotNull(ac.RootFilterContainer_ID); + Assert.That(ac.RootFilterContainer_ID, Is.Not.Null); var cmd = new ExecuteCommandAddNewFilterContainer(new ThrowImmediatelyActivator(RepositoryLocator), ac); - Assert.AreEqual("There is already a root filter container on this object", cmd.ReasonCommandImpossible); - Assert.IsTrue(cmd.IsImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.ReasonCommandImpossible, Is.EqualTo("There is already a root filter container on this object")); + Assert.That(cmd.IsImpossible); + }); } [Test] @@ -54,11 +60,14 @@ public void Impossible_BecauseAPI() c.Name = $"{PluginCohortCompiler.ApiPrefix}MyAwesomeAPI"; c.SaveToDatabase(); - Assert.IsTrue(c.IsApiCall()); + Assert.That(c.IsApiCall()); var cmd = new ExecuteCommandAddNewFilterContainer(new ThrowImmediatelyActivator(RepositoryLocator), ac); - Assert.AreEqual("Filters cannot be added to API calls", cmd.ReasonCommandImpossible); - Assert.IsTrue(cmd.IsImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.ReasonCommandImpossible, Is.EqualTo("Filters cannot be added to API calls")); + Assert.That(cmd.IsImpossible); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAddPipelineComponentTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAddPipelineComponentTests.cs index b27c66e9a8..d9d1353ab5 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAddPipelineComponentTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAddPipelineComponentTests.cs @@ -21,9 +21,12 @@ public void TestCreatePipelineWithCommands() { var p = WhenIHaveA(); - Assert.IsNull(p.Source); - Assert.IsNull(p.Destination); - Assert.IsEmpty(p.PipelineComponents); + Assert.Multiple(() => + { + Assert.That(p.Source, Is.Null); + Assert.That(p.Destination, Is.Null); + Assert.That(p.PipelineComponents, Is.Empty); + }); Run("AddPipelineComponent", $"Pipeline:{p.ID}", nameof(DelimitedFlatFileDataFlowSource)); @@ -34,21 +37,30 @@ public void TestCreatePipelineWithCommands() p.ClearAllInjections(); - Assert.IsNotNull(p.Source); - Assert.AreEqual(typeof(DelimitedFlatFileDataFlowSource), p.Source.GetClassAsSystemType()); - Assert.IsNotEmpty(p.Source.GetAllArguments()); - - Assert.AreEqual(4, p.PipelineComponents.Count); - - Assert.AreEqual(1, p.PipelineComponents[1].Order); - Assert.AreEqual(typeof(ColumnSwapper), p.PipelineComponents[1].GetClassAsSystemType()); - - Assert.AreEqual(2, p.PipelineComponents[2].Order); - Assert.AreEqual(typeof(CleanStrings), p.PipelineComponents[2].GetClassAsSystemType()); - - Assert.IsNotNull(p.Destination); - Assert.AreEqual(typeof(ExecuteFullExtractionToDatabaseMSSql), p.Destination.GetClassAsSystemType()); - Assert.IsNotEmpty(p.Destination.GetAllArguments()); + Assert.That(p.Source, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(p.Source.GetClassAsSystemType(), Is.EqualTo(typeof(DelimitedFlatFileDataFlowSource))); + Assert.That(p.Source.GetAllArguments(), Is.Not.Empty); + + Assert.That(p.PipelineComponents, Has.Count.EqualTo(4)); + }); + + Assert.Multiple(() => + { + Assert.That(p.PipelineComponents[1].Order, Is.EqualTo(1)); + Assert.That(p.PipelineComponents[1].GetClassAsSystemType(), Is.EqualTo(typeof(ColumnSwapper))); + + Assert.That(p.PipelineComponents[2].Order, Is.EqualTo(2)); + Assert.That(p.PipelineComponents[2].GetClassAsSystemType(), Is.EqualTo(typeof(CleanStrings))); + + Assert.That(p.Destination, Is.Not.Null); + }); + Assert.Multiple(() => + { + Assert.That(p.Destination.GetClassAsSystemType(), Is.EqualTo(typeof(ExecuteFullExtractionToDatabaseMSSql))); + Assert.That(p.Destination.GetAllArguments(), Is.Not.Empty); + }); } [Test] @@ -56,13 +68,13 @@ public void TestCreatePipeline_TooManySources() { var p = WhenIHaveA(); - Assert.IsNull(p.Source); + Assert.That(p.Source, Is.Null); Run("AddPipelineComponent", $"Pipeline:{p.ID}", nameof(DelimitedFlatFileDataFlowSource)); var ex = Assert.Throws(() => Run("AddPipelineComponent", $"Pipeline:{p.ID}", nameof(DelimitedFlatFileDataFlowSource))); - Assert.AreEqual("Pipeline 'My Pipeline' already has a source", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Pipeline 'My Pipeline' already has a source")); } [Test] @@ -70,12 +82,12 @@ public void TestCreatePipeline_TooManyDestinations() { var p = WhenIHaveA(); - Assert.IsNull(p.Source); + Assert.That(p.Source, Is.Null); Run("AddPipelineComponent", $"Pipeline:{p.ID}", nameof(ExecuteFullExtractionToDatabaseMSSql)); var ex = Assert.Throws(() => Run("AddPipelineComponent", $"Pipeline:{p.ID}", nameof(ExecuteFullExtractionToDatabaseMSSql))); - Assert.AreEqual("Pipeline 'My Pipeline' already has a destination", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Pipeline 'My Pipeline' already has a destination")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAlterTableMakeDistinctTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAlterTableMakeDistinctTests.cs index 0d29270e8c..f06255b984 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAlterTableMakeDistinctTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandAlterTableMakeDistinctTests.cs @@ -36,18 +36,18 @@ public void Test(DatabaseType dbType) Import(tbl, out var tblInfo, out _); - Assert.AreEqual(5, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(5)); var activator = new ConsoleInputManager(RepositoryLocator, ThrowImmediatelyCheckNotifier.Quiet) { DisallowInput = true }; var cmd = new ExecuteCommandAlterTableMakeDistinct(activator, tblInfo, 700, true); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); - Assert.AreEqual(2, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(2)); tbl.CreatePrimaryKey(tbl.DiscoverColumn("fff")); @@ -55,6 +55,6 @@ public void Test(DatabaseType dbType) var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual("Table 'MyTable' has primary key columns so cannot contain duplication", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Table 'MyTable' has primary key columns so cannot contain duplication")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandConfirmLogsTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandConfirmLogsTests.cs index 46531505df..241b95e81f 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandConfirmLogsTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandConfirmLogsTests.cs @@ -35,7 +35,7 @@ public void ConfirmLogs_NoEntries_Throws() var cmd = new ExecuteCommandConfirmLogs(new ThrowImmediatelyActivator(RepositoryLocator), lmd); var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual("There are no log entries for MyLmd", ex.Message); + Assert.That(ex.Message, Is.EqualTo("There are no log entries for MyLmd")); } [TestCase(true)] @@ -78,13 +78,13 @@ public void ConfirmLogs_SadEntry_BecauseNeverEnded_Throws() var lm = new LogManager(lmd.GetDistinctLoggingDatabase()); lm.CreateNewLoggingTaskIfNotExists("FFF"); - // we have created log entry but it did not have an end time. This is a sad entry because it never completed + // we have created log entry, but it did not have an end time. This is a sad entry because it never completed lm.CreateDataLoadInfo("FFF", "pack o' cards", "going down gambling", null, true); var cmd = new ExecuteCommandConfirmLogs(new ThrowImmediatelyActivator(RepositoryLocator), lmd); var ex = Assert.Throws(() => cmd.Execute()); - StringAssert.IsMatch("Latest logs for MyLmd .* indicate that it did not complete", ex.Message); + Assert.That(ex.Message, Does.Match("Latest logs for MyLmd .* indicate that it did not complete")); } [Test] @@ -106,7 +106,7 @@ public void ConfirmLogs_SadEntryWithEx_Throws() var cmd = new ExecuteCommandConfirmLogs(new ThrowImmediatelyActivator(RepositoryLocator), lmd); var ex = Assert.Throws(() => cmd.Execute()); - StringAssert.IsMatch("Latest logs for MyLmd .* indicate that it failed", ex.Message); + Assert.That(ex.Message, Does.Match("Latest logs for MyLmd .* indicate that it failed")); } @@ -134,8 +134,8 @@ public void ConfirmLogs_NotWithinTime_Throws() var cmd = new ExecuteCommandConfirmLogs(new ThrowImmediatelyActivator(RepositoryLocator), lmd, "00:00:01"); var ex = Assert.Throws(() => cmd.Execute()); - StringAssert.IsMatch( - "Latest logged activity for MyLmd is .*. This is older than the requested date threshold:.*", ex.Message); + Assert.That( +ex.Message, Does.Match("Latest logged activity for MyLmd is .*. This is older than the requested date threshold:.*")); } [Test] @@ -185,6 +185,6 @@ public void ConfirmLogs_With2CacheProgress_Throws() var cmd2 = new ExecuteCommandConfirmLogs(new ThrowImmediatelyActivator(RepositoryLocator), cp2, null); var ex = Assert.Throws(() => cmd2.Execute()); - Assert.AreEqual("There are no log entries for MyCoolCache", ex.Message); + Assert.That(ex.Message, Is.EqualTo("There are no log entries for MyCoolCache")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateDatasetTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateDatasetTests.cs new file mode 100644 index 0000000000..3bc17eb85c --- /dev/null +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateDatasetTests.cs @@ -0,0 +1,33 @@ + +using NUnit.Framework; +using Rdmp.Core.CommandExecution.AtomicCommands; +using System; +using System.Linq; +using Rdmp.Core.CommandExecution; + +namespace Rdmp.Core.Tests.CommandExecution; + +public class ExecuteCommandCreateDatasetTests : CommandCliTests +{ + [Test] + public void TestDatasetCreationOKParameters() { + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(),"dataset"); + Assert.DoesNotThrow(()=>cmd.Execute()); + } + + [Test] + public void TestDatasetCreationNoParameters() + { + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), null); + Assert.Throws(cmd.Execute); + } + + [Test] + public void TestDatasetCreationOKExtendedParameters() + { + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), "dataset2","somedoi","some source"); + Assert.DoesNotThrow(cmd.Execute); + var founddataset = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().Where(ds => ds.Name == "dataset2" && ds.DigitalObjectIdentifier == "somedoi" && ds.Source == "some source").First(); + Assert.That(founddataset,Is.Not.Null); + } +} diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateNewDataLoadDirectoryTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateNewDataLoadDirectoryTests.cs index 323f6a89fb..639f2976ed 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateNewDataLoadDirectoryTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateNewDataLoadDirectoryTests.cs @@ -21,7 +21,7 @@ public void TestCreateNewDataLoadDirectory_CreateDeepFolder_NoLmd() Run("CreateNewDataLoadDirectory", "null", toCreate); - Assert.IsTrue(Directory.Exists(root)); + Assert.That(Directory.Exists(root)); } [Test] @@ -31,11 +31,14 @@ public void TestCreateNewDataLoadDirectory_WithLoadMetadata() if (Directory.Exists(root)) Directory.Delete(root, true); var lmd = WhenIHaveA(); - Assert.IsNull(lmd.LocationOfFlatFiles); + Assert.That(lmd.LocationOfFlatFiles, Is.Null); Run("CreateNewDataLoadDirectory", $"LoadMetadata:{lmd.ID}", root); - Assert.IsTrue(Directory.Exists(root)); - Assert.AreEqual(root, lmd.LocationOfFlatFiles); + Assert.Multiple(() => + { + Assert.That(Directory.Exists(root)); + Assert.That(lmd.LocationOfFlatFiles, Is.EqualTo(root)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateNewFilterCliTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateNewFilterCliTests.cs index 76dcbcf11a..dcae5c403c 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateNewFilterCliTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandCreateNewFilterCliTests.cs @@ -24,11 +24,14 @@ public void TestNewFilterForAggregate() var ac = WhenIHaveA(); // has no container to start with (no filters) - Assert.IsNull(ac.RootFilterContainer_ID); + Assert.That(ac.RootFilterContainer_ID, Is.Null); Run("CreateNewFilter", $"{nameof(AggregateConfiguration)}:{ac.ID}"); - Assert.IsNotNull(ac.RootFilterContainer_ID, "Should now have a container"); - Assert.AreEqual(1, ac.RootFilterContainer.GetFilters().Length, "Expected a single new filter"); + Assert.Multiple(() => + { + Assert.That(ac.RootFilterContainer_ID, Is.Not.Null, "Should now have a container"); + Assert.That(ac.RootFilterContainer.GetFilters(), Has.Length.EqualTo(1), "Expected a single new filter"); + }); } [Test] @@ -37,11 +40,14 @@ public void TestNewFilterForExtractionConfiguration() var sds = WhenIHaveA(); // has no container to start with (no filters) - Assert.IsNull(sds.RootFilterContainer_ID); + Assert.That(sds.RootFilterContainer_ID, Is.Null); Run("CreateNewFilter", $"{nameof(SelectedDataSets)}:{sds.ID}"); - Assert.IsNotNull(sds.RootFilterContainer_ID, "Should now have a container"); - Assert.AreEqual(1, sds.RootFilterContainer.GetFilters().Length, "Expected a single new filter"); + Assert.Multiple(() => + { + Assert.That(sds.RootFilterContainer_ID, Is.Not.Null, "Should now have a container"); + Assert.That(sds.RootFilterContainer.GetFilters(), Has.Length.EqualTo(1), "Expected a single new filter"); + }); } [Test] @@ -50,11 +56,14 @@ public void TestNewFilterForCatalogue() var ei = WhenIHaveA(); // no Catalogue level filters - Assert.IsEmpty(ei.ExtractionFilters); + Assert.That(ei.ExtractionFilters, Is.Empty); Run("CreateNewFilter", $"{nameof(ExtractionInformation)}:{ei.ID}", "My cool filter", "hb='t'"); var f = ei.ExtractionFilters.Single(); - Assert.AreEqual("My cool filter", f.Name); - Assert.AreEqual("hb='t'", f.WhereSQL); + Assert.Multiple(() => + { + Assert.That(f.Name, Is.EqualTo("My cool filter")); + Assert.That(f.WhereSQL, Is.EqualTo("hb='t'")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeleteDatasetTest.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeleteDatasetTest.cs new file mode 100644 index 0000000000..c48f6693ed --- /dev/null +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeleteDatasetTest.cs @@ -0,0 +1,32 @@ +using NUnit.Framework; +using Rdmp.Core.CommandExecution.AtomicCommands; +using System; +using System.Linq; + +namespace Rdmp.Core.Tests.CommandExecution; + +internal class ExecuteCommandDeleteDatasetTest: CommandCliTests +{ + + [Test] + public void TestDeleteExistingDataset() + { + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), "dataset"); + Assert.DoesNotThrow(() => cmd.Execute()); + Assert.That(GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(1)); + var founddataset = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().Where(ds => ds.Name == "dataset").First(); + var delCmd = new ExecuteCommandDeleteDataset(GetMockActivator(), founddataset); + Assert.DoesNotThrow(() => delCmd.Execute()); + Assert.That(GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects(), Is.Empty); + } + + [Test] + public void TestDeleteNonExistantDataset() + { + Assert.That(GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects(), Is.Empty); + var founddataset = new Core.Curation.Data.Dataset(); + var delCmd = new ExecuteCommandDeleteDataset(GetMockActivator(), founddataset); + Assert.Throws(() => delCmd.Execute()); + Assert.That(GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects(), Is.Empty); + } +} \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeleteTestsCli.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeleteTestsCli.cs index 99b124c39c..e36192b063 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeleteTestsCli.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeleteTestsCli.cs @@ -16,12 +16,15 @@ internal class ExecuteCommandDeleteTestsCli : CommandCliTests public void TestDeletingACatalogue_NoneInDbIsFine() { var prev = RepositoryLocator.CatalogueRepository.GetAllObjects(); - Assert.IsEmpty(prev); + Assert.Multiple(() => + { + Assert.That(prev, Is.Empty); - Assert.AreEqual(0, Run("delete", "Catalogue:bob")); + Assert.That(Run("delete", "Catalogue:bob"), Is.EqualTo(0)); + }); var now = RepositoryLocator.CatalogueRepository.GetAllObjects(); - Assert.IsEmpty(now); + Assert.That(now, Is.Empty); } [Test] @@ -30,8 +33,11 @@ public void TestDeletingACatalogue_DeleteBecauseMatches() var cata = WhenIHaveA(); cata.Name = "bob"; - Assert.AreEqual(0, Run("delete", "Catalogue:bob")); - Assert.IsFalse(cata.Exists()); + Assert.Multiple(() => + { + Assert.That(Run("delete", "Catalogue:bob"), Is.EqualTo(0)); + Assert.That(cata.Exists(), Is.False); + }); } [Test] @@ -40,10 +46,13 @@ public void TestDeletingACatalogue_DoesNotMatchPattern() var cata = WhenIHaveA(); cata.Name = "ffff"; - Assert.AreEqual(0, Run("delete", "Catalogue:bob")); + Assert.Multiple(() => + { + Assert.That(Run("delete", "Catalogue:bob"), Is.EqualTo(0)); - // should not have been deleted because name does not match what is sought to be deleted - Assert.IsTrue(cata.Exists()); + // should not have been deleted because name does not match what is sought to be deleted + Assert.That(cata.Exists()); + }); //cleanup cata.DeleteInDatabase(); @@ -59,8 +68,7 @@ public void TestDeleteMany_ThrowsBecauseNotExpected() // delete all catalogues var ex = Assert.Throws(() => Run("delete", "Catalogue")); - Assert.AreEqual(ex.Message, - "Allow delete many is false but multiple objects were matched for deletion (Mycata,Mycata)"); + Assert.That(ex?.Message, Is.EqualTo("Allow delete many is false but multiple objects were matched for deletion (Mycata,Mycata)")); c1.DeleteInDatabase(); c2.DeleteInDatabase(); @@ -73,11 +81,14 @@ public void TestDeleteMany_Allowed() var c1 = WhenIHaveA(); var c2 = WhenIHaveA(); - // delete all catalogues - Assert.AreEqual(0, Run("delete", "Catalogue", "true")); + Assert.Multiple(() => + { + // delete all catalogues + Assert.That(Run("delete", "Catalogue", "true"), Is.EqualTo(0)); - Assert.IsFalse(c1.Exists()); - Assert.IsFalse(c2.Exists()); + Assert.That(c1.Exists(), Is.False); + Assert.That(c2.Exists(), Is.False); + }); } [Test] @@ -88,9 +99,8 @@ public void TestDeleteMany_BadParameterFormat() // delete all catalogues var ex = Assert.Throws(() => Run("delete", "Catalogue", "FLIBBLE!")); - Assert.AreEqual( - "Expected parameter at index 1 to be a System.Boolean (for parameter 'deleteMany') but it was FLIBBLE!", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Expected parameter at index 1 to be a System.Boolean (for parameter 'deleteMany') but it was FLIBBLE!")); c1.DeleteInDatabase(); } diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeprecateTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeprecateTests.cs index 6fb1daa05f..ba1a59a2ec 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeprecateTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandDeprecateTests.cs @@ -16,10 +16,10 @@ public void TestDeprecateCommand() { var c = WhenIHaveA(); - Assert.IsFalse(c.IsDeprecated); + Assert.That(c.IsDeprecated, Is.False); Run("Deprecate", $"Catalogue:{c.ID}"); - Assert.IsTrue(c.IsDeprecated); + Assert.That(c.IsDeprecated); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandLinkCatalogueToDatasetTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandLinkCatalogueToDatasetTests.cs new file mode 100644 index 0000000000..95da47a552 --- /dev/null +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandLinkCatalogueToDatasetTests.cs @@ -0,0 +1,119 @@ +using System; +using System.Linq; +using NUnit.Framework; +using Rdmp.Core.CommandExecution; +using Rdmp.Core.CommandExecution.AtomicCommands; +using Rdmp.Core.Curation.Data; + +namespace Rdmp.Core.Tests.CommandExecution; + +internal class ExecuteCommandLinkCatalogueToDatasetTests : CommandCliTests +{ + + [Test] + public void TestLinkCatalogueToDataset() + { + var _cata1 = new Catalogue(GetMockActivator().RepositoryLocator.CatalogueRepository, "Dataset1"); + var _cata2 = new Catalogue(GetMockActivator().RepositoryLocator.CatalogueRepository, "Dataset2"); + _cata1.SaveToDatabase(); + _cata2.SaveToDatabase(); + var _t1 = new TableInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "T1"); + var _t2 = new TableInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "T2"); + _t1.SaveToDatabase(); + _t2.SaveToDatabase(); + var _c1 = new ColumnInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "test.db", "varchar(10)", _t1); + var _c2 = new ColumnInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "test.db", "int", _t2); + _c1.SaveToDatabase(); + _c2.SaveToDatabase(); + var _ci1 = new CatalogueItem(GetMockActivator().RepositoryLocator.CatalogueRepository, _cata1, "PrivateIdentifierA"); + _ci1.SetColumnInfo(_c1); + var _ci2 = new CatalogueItem(GetMockActivator().RepositoryLocator.CatalogueRepository, _cata2, "PrivateIdentifierB"); + _ci2.SetColumnInfo(_c2); + _ci1.SaveToDatabase(); + _ci2.SaveToDatabase(); + + + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), "dataset"); + Assert.DoesNotThrow(cmd.Execute); + var founddataset = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().First(); + var foundCatalogue = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().Where(c => c.Name == "Dataset1").First(); + var linkCmd = new ExecuteCommandLinkCatalogueToDataset(GetMockActivator(), foundCatalogue, founddataset); + Assert.DoesNotThrow(linkCmd.Execute); + var columInfo = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects(); + foreach (var ci in columInfo) + { + Assert.That(ci.Dataset_ID, Is.EqualTo(founddataset.ID)); + } + founddataset.DeleteInDatabase(); + foundCatalogue.DeleteInDatabase(); + + } + [Test] + public void TestLinkCatalogueToDatasetNotAll() + { + var _cata1 = new Catalogue(GetMockActivator().RepositoryLocator.CatalogueRepository, "Dataset1"); + var _cata2 = new Catalogue(GetMockActivator().RepositoryLocator.CatalogueRepository, "Dataset2"); + _cata1.SaveToDatabase(); + _cata2.SaveToDatabase(); + var _t1 = new TableInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "T1"); + var _t2 = new TableInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "T2"); + _t1.SaveToDatabase(); + _t2.SaveToDatabase(); + var _c1 = new ColumnInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "test.db", "varchar(10)", _t1); + var _c2 = new ColumnInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "test.db", "int", _t2); + _c1.SaveToDatabase(); + _c2.SaveToDatabase(); + var _ci1 = new CatalogueItem(GetMockActivator().RepositoryLocator.CatalogueRepository, _cata1, "PrivateIdentifierA"); + _ci1.SetColumnInfo(_c1); + var _ci2 = new CatalogueItem(GetMockActivator().RepositoryLocator.CatalogueRepository, _cata2, "PrivateIdentifierB"); + _ci2.SetColumnInfo(_c2); + _ci1.SaveToDatabase(); + _ci2.SaveToDatabase(); + + + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), "dataset"); + Assert.DoesNotThrow(cmd.Execute); + var founddataset = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().First(); + var foundCatalogue = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().Where(c => c.Name == "Dataset1").First(); + var linkCmd = new ExecuteCommandLinkCatalogueToDataset(GetMockActivator(), foundCatalogue, founddataset, false); + Assert.DoesNotThrow(linkCmd.Execute); + var columInfo = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().Where(ci => _cata1.CatalogueItems.Contains(ci)); + foreach (var ci in columInfo) + { + Assert.That(ci.ColumnInfo.Dataset_ID, Is.EqualTo(founddataset.ID)); + } + + var columInfo2 = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().Where(ci => _cata2.CatalogueItems.Contains(ci)); + foreach (var ci in columInfo2) + { + Assert.That(ci.ColumnInfo.Dataset_ID, Is.Null); + } + + } + [Test] + public void TestLinkCatalogueToDatasetBadCatalogue() + { + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), "dataset"); + Assert.DoesNotThrow(cmd.Execute); + var founddataset = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().First(); + var linkCmd = new ExecuteCommandLinkCatalogueToDataset(GetMockActivator(), null, founddataset, false); + Assert.Throws(linkCmd.Execute); + } + + [Test] + public void TestLinkCatalogueToDatasetBadDataset() + { + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), "dataset"); + Assert.DoesNotThrow(cmd.Execute); + var founddataset = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().First(); + var linkCmd = new ExecuteCommandLinkCatalogueToDataset(GetMockActivator(), new Catalogue(GetMockActivator().RepositoryLocator.CatalogueRepository,"catalogue"), null, false); + Assert.Throws(linkCmd.Execute); + } + + [Test] + public void TestLinkCatalogueToDatasetBadEverything() + { + var linkCmd = new ExecuteCommandLinkCatalogueToDataset(GetMockActivator(), null, null, false); + Assert.Throws(linkCmd.Execute); + } +} \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandLinkCoulmnInfoWithDatasetTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandLinkCoulmnInfoWithDatasetTests.cs new file mode 100644 index 0000000000..2fb4d0a7b9 --- /dev/null +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandLinkCoulmnInfoWithDatasetTests.cs @@ -0,0 +1,113 @@ +using System; +using System.Linq; +using NUnit.Framework; +using Rdmp.Core.CommandExecution.AtomicCommands; +using Rdmp.Core.Curation.Data; + +namespace Rdmp.Core.Tests.CommandExecution; + +internal class ExecuteCommandLinkCoulmnInfoWithDatasetTests: CommandCliTests +{ + [Test] + public void TestLinkColumnInfoToDataset() + { + var _cata1 = new Catalogue(GetMockActivator().RepositoryLocator.CatalogueRepository, "Dataset1"); + var _cata2 = new Catalogue(GetMockActivator().RepositoryLocator.CatalogueRepository, "Dataset2"); + _cata1.SaveToDatabase(); + _cata2.SaveToDatabase(); + var _t1 = new TableInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "T1"); + var _t2 = new TableInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "T2"); + _t1.SaveToDatabase(); + _t2.SaveToDatabase(); + var _c1 = new ColumnInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "test.db", "varchar(10)", _t1); + var _c2 = new ColumnInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "test.db", "int", _t2); + _c1.SaveToDatabase(); + _c2.SaveToDatabase(); + var _ci1 = new CatalogueItem(GetMockActivator().RepositoryLocator.CatalogueRepository, _cata1, "PrivateIdentifierA"); + _ci1.SetColumnInfo(_c1); + var _ci2 = new CatalogueItem(GetMockActivator().RepositoryLocator.CatalogueRepository, _cata2, "PrivateIdentifierB"); + _ci2.SetColumnInfo(_c2); + _ci1.SaveToDatabase(); + _ci2.SaveToDatabase(); + + + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), "dataset"); + Assert.DoesNotThrow(() => cmd.Execute()); + var founddataset = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().First(); + var foundCatalogue = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().Where(c => c.Name == "Dataset1").First(); + var linkCmd = new ExecuteCommandLinkColumnInfoToDataset(GetMockActivator(), _c1, founddataset); + Assert.DoesNotThrow(() => linkCmd.Execute()); + var columInfo = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects(); + foreach (var ci in columInfo) + { + Assert.That(ci.Dataset_ID, Is.EqualTo(founddataset.ID)); + } + } + [Test] + public void TestLinkColumnInfoToDatasetNotAll() + { + var _cata1 = new Catalogue(GetMockActivator().RepositoryLocator.CatalogueRepository, "Dataset1"); + var _cata2 = new Catalogue(GetMockActivator().RepositoryLocator.CatalogueRepository, "Dataset2"); + _cata1.SaveToDatabase(); + _cata2.SaveToDatabase(); + var _t1 = new TableInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "T1"); + var _t2 = new TableInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "T2"); + _t1.SaveToDatabase(); + _t2.SaveToDatabase(); + var _c1 = new ColumnInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "test.db", "varchar(10)", _t1); + var _c2 = new ColumnInfo(GetMockActivator().RepositoryLocator.CatalogueRepository, "test.db", "int", _t2); + _c1.SaveToDatabase(); + _c2.SaveToDatabase(); + var _ci1 = new CatalogueItem(GetMockActivator().RepositoryLocator.CatalogueRepository, _cata1, "PrivateIdentifierA"); + _ci1.SetColumnInfo(_c1); + var _ci2 = new CatalogueItem(GetMockActivator().RepositoryLocator.CatalogueRepository, _cata2, "PrivateIdentifierB"); + _ci2.SetColumnInfo(_c2); + _ci1.SaveToDatabase(); + _ci2.SaveToDatabase(); + + + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), "dataset"); + Assert.DoesNotThrow(() => cmd.Execute()); + var founddataset = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().First(); + var foundCatalogue = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().Where(c => c.Name == "Dataset1").First(); + var linkCmd = new ExecuteCommandLinkColumnInfoToDataset(GetMockActivator(), _c1, founddataset, false); + Assert.DoesNotThrow(() => linkCmd.Execute()); + var columInfo = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().Where(ci => _cata1.CatalogueItems.Contains(ci)); + foreach (var ci in columInfo) + { + Assert.That(ci.ColumnInfo.Dataset_ID, Is.EqualTo(founddataset.ID)); + } + + var columInfo2 = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().Where(ci => _cata2.CatalogueItems.Contains(ci)); + foreach (var ci in columInfo2) + { + Assert.That(ci.ColumnInfo.Dataset_ID, Is.Null); + } + } + [Test] + public void TestLinkCatalogueToDatasetBadColumnInfo() + { + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), "dataset"); + Assert.DoesNotThrow(() => cmd.Execute()); + var founddataset = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().First(); + var linkCmd = new ExecuteCommandLinkColumnInfoToDataset(GetMockActivator(), null, founddataset, false); + Assert.Throws(() => linkCmd.Execute()); + } + + [Test] + public void TestLinkColumInfoToDatasetBadDataset() + { + var cmd = new ExecuteCommandCreateDataset(GetMockActivator(), "dataset"); + Assert.DoesNotThrow(() => cmd.Execute()); + var founddataset = GetMockActivator().RepositoryLocator.CatalogueRepository.GetAllObjects().First(); + var linkCmd = new ExecuteCommandLinkColumnInfoToDataset(GetMockActivator(), new ColumnInfo(), null, false); + Assert.Throws(() => linkCmd.Execute()); + } + + [Test] + public void TestLinkColumnInfoToDatasetBadEverything() + { + var linkCmd = new ExecuteCommandLinkColumnInfoToDataset(GetMockActivator(), null, null, false); + Assert.Throws(() => linkCmd.Execute()); + } +} \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandListTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandListTests.cs index bc3d18bc14..8778b404f8 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandListTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandListTests.cs @@ -21,7 +21,7 @@ public void Test_ExecuteCommandList_NoCataloguesParsing() foreach (var cat in RepositoryLocator.CatalogueRepository.GetAllObjects()) cat.DeleteInDatabase(); - Assert.IsEmpty(RepositoryLocator.CatalogueRepository.GetAllObjects(), + Assert.That(RepositoryLocator.CatalogueRepository.GetAllObjects(), Is.Empty, "Failed to clear CatalogueRepository"); GetInvoker().ExecuteCommand(typeof(ExecuteCommandList), @@ -49,7 +49,7 @@ public void Test_ExecuteCommandList_OneCatalogue() var mock = GetMockActivator(); var cmd = new ExecuteCommandList(mock, new[] { c }); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandRefreshBrokenCohortsTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandRefreshBrokenCohortsTests.cs index eb852b8af4..b2420034c2 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandRefreshBrokenCohortsTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandRefreshBrokenCohortsTests.cs @@ -20,7 +20,7 @@ internal class ExecuteCommandRefreshBrokenCohortsTests public void TestBrokenCohort() { var repo = new MemoryDataExportRepository(); - + var ect = new ExternalCohortTable(repo, "yarg", FAnsi.DatabaseType.MicrosoftSQLServer) { Server = "IDontExist", @@ -45,7 +45,7 @@ public void TestBrokenCohort() DisallowInput = true }; - Assert.AreEqual(1, ((DataExportChildProvider)activator.CoreChildProvider).ForbidListedSources.Count); + Assert.That(((DataExportChildProvider)activator.CoreChildProvider).ForbidListedSources, Has.Count.EqualTo(1)); var cmd = new ExecuteCommandRefreshBrokenCohorts(activator) { @@ -54,19 +54,25 @@ public void TestBrokenCohort() NoPublish = true }; - Assert.IsFalse(cmd.IsImpossible); + Assert.That(cmd.IsImpossible, Is.False); cmd.Execute(); //now no forbidden cohorts - Assert.IsEmpty(((DataExportChildProvider)activator.CoreChildProvider).ForbidListedSources); + Assert.That(((DataExportChildProvider)activator.CoreChildProvider).ForbidListedSources, Is.Empty); cmd = new ExecuteCommandRefreshBrokenCohorts(activator); - Assert.IsTrue(cmd.IsImpossible); - Assert.AreEqual("There are no broken ExternalCohortTable to clear status on", cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Is.EqualTo("There are no broken ExternalCohortTable to clear status on")); + }); cmd = new ExecuteCommandRefreshBrokenCohorts(activator, ect); - Assert.IsTrue(cmd.IsImpossible); - Assert.AreEqual("'yarg' is not broken", cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Is.EqualTo("'yarg' is not broken")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandReplacedByTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandReplacedByTests.cs index e1408fed57..8a11b3c9cb 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandReplacedByTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandReplacedByTests.cs @@ -21,9 +21,12 @@ public void CommandImpossible_BecauseNotDeprecated() var cmd = new ExecuteCommandReplacedBy(GetMockActivator(), c1, c2); - Assert.IsTrue(cmd.IsImpossible); - StringAssert.Contains("is not marked IsDeprecated", cmd.ReasonCommandImpossible); - } + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Does.Contain("is not marked IsDeprecated")); + }); + } [Test] public void CommandImpossible_BecauseDifferentTypes() @@ -36,9 +39,12 @@ public void CommandImpossible_BecauseDifferentTypes() var cmd = new ExecuteCommandReplacedBy(GetMockActivator(), c1, ci1); - Assert.IsTrue(cmd.IsImpossible); - StringAssert.Contains("because it is a different object Type", cmd.ReasonCommandImpossible); - } + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Does.Contain("because it is a different object Type")); + }); + } [Test] public void CommandImpossible_Allowed() @@ -50,7 +56,7 @@ public void CommandImpossible_Allowed() c1.SaveToDatabase(); var cmd = new ExecuteCommandReplacedBy(GetMockActivator(), c1, c2); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); @@ -58,24 +64,27 @@ public void CommandImpossible_Allowed() .GetAllObjectsWhere("Name", ExtendedProperty.ReplacedBy) .Single(r => r.IsReferenceTo(c1)); - Assert.IsTrue(replacement.IsReferenceTo(c1)); - Assert.AreEqual(c2.ID.ToString(), replacement.Value); + Assert.Multiple(() => + { + Assert.That(replacement.IsReferenceTo(c1)); + Assert.That(replacement.Value, Is.EqualTo(c2.ID.ToString())); + }); - // running command multiple times shouldn't result in duplicate objects - cmd.Execute(); + // running command multiple times shouldn't result in duplicate objects + cmd.Execute(); cmd.Execute(); cmd.Execute(); cmd.Execute(); - Assert.AreEqual(1, RepositoryLocator.CatalogueRepository + Assert.That(RepositoryLocator.CatalogueRepository .GetAllObjectsWhere("Name", ExtendedProperty.ReplacedBy) - .Count(r => r.IsReferenceTo(c1))); + .Count(r => r.IsReferenceTo(c1)), Is.EqualTo(1)); cmd = new ExecuteCommandReplacedBy(GetMockActivator(), c1, null); cmd.Execute(); - Assert.IsEmpty(RepositoryLocator.CatalogueRepository + Assert.That(RepositoryLocator.CatalogueRepository .GetAllObjectsWhere("Name", ExtendedProperty.ReplacedBy) - .Where(r => r.IsReferenceTo(c1))); + .Where(r => r.IsReferenceTo(c1)), Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetArgumentTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetArgumentTests.cs index ce41dcd9b1..fa78720ecc 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetArgumentTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetArgumentTests.cs @@ -21,9 +21,11 @@ public void TestSetArgument_WrongArgCount() var picker = new CommandLineObjectPicker(new[] { "yyy" }, GetActivator()); var cmd = new ExecuteCommandSetArgument(GetMockActivator(), picker); - Assert.IsTrue(cmd.IsImpossible); - Assert.AreEqual("Wrong number of parameters supplied to command, expected 3 but got 1", - cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Is.EqualTo("Wrong number of parameters supplied to command, expected 3 but got 1")); + }); } [Test] @@ -34,8 +36,11 @@ public void TestSetArgument_NotAHost() var picker = new CommandLineObjectPicker(new[] { $"Catalogue:{c.ID}", "fff", "yyy" }, GetActivator()); var cmd = new ExecuteCommandSetArgument(GetMockActivator(), picker); - Assert.IsTrue(cmd.IsImpossible); - Assert.AreEqual("First parameter must be an IArgumentHost", cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Is.EqualTo("First parameter must be an IArgumentHost")); + }); } [Test] @@ -47,8 +52,11 @@ public void TestSetArgument_NoArgumentFound() var picker = new CommandLineObjectPicker(new[] { $"ProcessTask:{pt.ID}", "fff", "yyy" }, GetActivator()); var cmd = new ExecuteCommandSetArgument(GetMockActivator(), picker); - Assert.IsTrue(cmd.IsImpossible); - StringAssert.StartsWith("Could not find argument called 'fff' on ", cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Does.StartWith("Could not find argument called 'fff' on ")); + }); } [Test] @@ -65,9 +73,11 @@ public void TestSetArgument_ArgumentWrongType() var picker = new CommandLineObjectPicker(new[] { $"ProcessTask:{pt.ID}", "fff", "yyy" }, GetActivator()); var cmd = new ExecuteCommandSetArgument(GetMockActivator(), picker); - Assert.IsTrue(cmd.IsImpossible); - StringAssert.StartsWith("Provided value 'yyy' does not match expected Type 'Int32' of ", - cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Does.StartWith("Provided value 'yyy' does not match expected Type 'Int32' of ")); + }); } @@ -80,13 +90,13 @@ public void TestSetArgument_Int_Valid() pta.Name = "fff"; pta.SetType(typeof(int)); - Assert.IsNull(pta.Value); + Assert.That(pta.Value, Is.Null); var picker = new CommandLineObjectPicker(new[] { $"ProcessTask:{pt.ID}", "fff", "5" }, GetActivator()); Assert.DoesNotThrow(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandSetArgument), picker)); - Assert.AreEqual(5, pta.GetValueAsSystemType()); + Assert.That(pta.GetValueAsSystemType(), Is.EqualTo(5)); } [Test] @@ -102,14 +112,14 @@ public void TestSetArgument_Catalogue_Valid() pta.Name = "fff"; pta.SetType(typeof(Catalogue)); - Assert.IsNull(pta.Value); + Assert.That(pta.Value, Is.Null); var picker = new CommandLineObjectPicker(new[] { $"ProcessTask:{pt.ID}", "fff", $"Catalogue:kapow splat" }, GetActivator()); Assert.DoesNotThrow(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandSetArgument), picker)); - Assert.AreEqual(cata, pta.GetValueAsSystemType()); + Assert.That(pta.GetValueAsSystemType(), Is.EqualTo(cata)); } [Test] @@ -127,14 +137,14 @@ public void TestSetArgument_CatalogueArrayOf1_Valid() pca.Name = "ggg"; pca.SetType(typeof(Catalogue[])); - Assert.IsNull(pca.Value); + Assert.That(pca.Value, Is.Null); var picker = new CommandLineObjectPicker(new[] { $"PipelineComponent:{pc.ID}", "ggg", $"Catalogue:lolzzzyy" }, GetActivator()); Assert.DoesNotThrow(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandSetArgument), picker)); - Assert.Contains(cata1, (System.Collections.ICollection)pca.GetValueAsSystemType()); + Assert.That((System.Collections.ICollection)pca.GetValueAsSystemType(), Does.Contain(cata1)); } [Test] @@ -155,15 +165,15 @@ public void TestSetArgument_CatalogueArrayOf2_Valid() pca.Name = "ggg"; pca.SetType(typeof(Catalogue[])); - Assert.IsNull(pca.Value); + Assert.That(pca.Value, Is.Null); var picker = new CommandLineObjectPicker(new[] { $"PipelineComponent:{pc.ID}", "ggg", $"Catalogue:kapow*" }, GetActivator()); Assert.DoesNotThrow(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandSetArgument), picker)); - Assert.Contains(cata1, (System.Collections.ICollection)pca.GetValueAsSystemType()); - Assert.Contains(cata2, (System.Collections.ICollection)pca.GetValueAsSystemType()); + Assert.That((System.Collections.ICollection)pca.GetValueAsSystemType(), Does.Contain(cata1)); + Assert.That((System.Collections.ICollection)pca.GetValueAsSystemType(), Does.Contain(cata2)); } [Test] @@ -183,13 +193,13 @@ public void TestSetArgument_CatalogueArray_SetToNull_Valid() pca.SetValue(new Catalogue[] { cata1 }); pca.SaveToDatabase(); - Assert.Contains(cata1, (System.Collections.ICollection)pca.GetValueAsSystemType()); + Assert.That((System.Collections.ICollection)pca.GetValueAsSystemType(), Does.Contain(cata1)); var picker = new CommandLineObjectPicker(new[] { $"PipelineComponent:{pc.ID}", "ggg", $"Null" }, GetActivator()); Assert.DoesNotThrow(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandSetArgument), picker)); - Assert.IsNull(pca.GetValueAsSystemType()); + Assert.That(pca.GetValueAsSystemType(), Is.Null); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetExtendedPropertyTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetExtendedPropertyTests.cs index 364ce8bc8f..74f1cf94c8 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetExtendedPropertyTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetExtendedPropertyTests.cs @@ -21,8 +21,11 @@ public void CommandImpossible_BecausePropertyDoesNotExist() var cmd = new ExecuteCommandSetExtendedProperty(GetMockActivator(), new[] { c1 }, "blarg", "fff"); - Assert.IsTrue(cmd.IsImpossible); - StringAssert.StartsWith("blarg is not a known property. Known properties are:", cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Does.StartWith("blarg is not a known property. Known properties are:")); + }); } [Test] @@ -31,16 +34,18 @@ public void SetIsTemplate_OnMultipleObjects() var ac1 = WhenIHaveA(); var ac2 = WhenIHaveA(); - - Assert.IsEmpty( - Repository.CatalogueRepository.GetExtendedProperties(ac1)); - Assert.IsEmpty( - Repository.CatalogueRepository.GetExtendedProperties(ac2)); + Assert.Multiple(() => + { + Assert.That( + Repository.CatalogueRepository.GetExtendedProperties(ac1), Is.Empty); + Assert.That( + Repository.CatalogueRepository.GetExtendedProperties(ac2), Is.Empty); + }); var cmd = new ExecuteCommandSetExtendedProperty(GetMockActivator(), new[] { ac1, ac2 }, ExtendedProperty.IsTemplate, "true"); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); @@ -49,8 +54,11 @@ public void SetIsTemplate_OnMultipleObjects() foreach (var dec in new[] { declaration1, declaration2 }) { - Assert.AreEqual("IsTemplate", dec.Name); - Assert.AreEqual("true", dec.Value); + Assert.Multiple(() => + { + Assert.That(dec.Name, Is.EqualTo("IsTemplate")); + Assert.That(dec.Value, Is.EqualTo("true")); + }); } // now clear that status @@ -58,14 +66,17 @@ public void SetIsTemplate_OnMultipleObjects() cmd = new ExecuteCommandSetExtendedProperty(GetMockActivator(), new[] { ac1, ac2 }, ExtendedProperty.IsTemplate, null); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); - // should now be back where we started - Assert.IsEmpty( - Repository.CatalogueRepository.GetExtendedProperties(ac1)); - Assert.IsEmpty( - Repository.CatalogueRepository.GetExtendedProperties(ac2)); + Assert.Multiple(() => + { + // should now be back where we started + Assert.That( + Repository.CatalogueRepository.GetExtendedProperties(ac1), Is.Empty); + Assert.That( + Repository.CatalogueRepository.GetExtendedProperties(ac2), Is.Empty); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetExtractionIdentifierTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetExtractionIdentifierTests.cs index ebf0a8ef94..8948b94949 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetExtractionIdentifierTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSetExtractionIdentifierTests.cs @@ -27,7 +27,7 @@ public void TestSetExtractionIdentifier_Catalogue() null, "happyfun"); cmd.Execute(); - Assert.IsTrue(ei1.IsExtractionIdentifier); + Assert.That(ei1.IsExtractionIdentifier); } [Test] @@ -43,21 +43,27 @@ public void TestSetExtractionIdentifier_Catalogue_PickOther() ei1.IsExtractionIdentifier = true; ei1.SaveToDatabase(); - // before we run the command the primary ei1 is the identifier - Assert.IsTrue(ei1.IsExtractionIdentifier); - Assert.IsFalse(otherEi.IsExtractionIdentifier); + Assert.Multiple(() => + { + // before we run the command the primary ei1 is the identifier + Assert.That(ei1.IsExtractionIdentifier); + Assert.That(otherEi.IsExtractionIdentifier, Is.False); + }); - // by picking the second (FFF) we should switch - var cmd = new ExecuteCommandSetExtractionIdentifier(GetMockActivator(), ei1.CatalogueItem.Catalogue, + // by picking the second (FFF) we should switch + var cmd = new ExecuteCommandSetExtractionIdentifier(GetMockActivator(), ei1.CatalogueItem.Catalogue, null, "FFF"); cmd.Execute(); - // original should no longer be the extraction identifer - Assert.IsFalse(ei1.IsExtractionIdentifier); + Assert.Multiple(() => + { + // original should no longer be the extraction identifer + Assert.That(ei1.IsExtractionIdentifier, Is.False); - // and the one picked should now be the only one - Assert.IsTrue(otherEi.IsExtractionIdentifier); - } + // and the one picked should now be the only one + Assert.That(otherEi.IsExtractionIdentifier); + }); + } [Test] public void TestSetExtractionIdentifier_Catalogue_ButColumnDoesNotExist() @@ -72,7 +78,7 @@ public void TestSetExtractionIdentifier_Catalogue_ButColumnDoesNotExist() new ExecuteCommandSetExtractionIdentifier(GetMockActivator(), ei1.CatalogueItem.Catalogue, null, "trollolo") .Execute()); - Assert.AreEqual("Could not find column(s) trollolo amongst available columns (happyfun)", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Could not find column(s) trollolo amongst available columns (happyfun)")); } @@ -93,10 +99,13 @@ public void TestSetExtractionIdentifier_Configuration() , "happyfun"); cmd.Execute(); - // affects extraction specific version - Assert.IsTrue(ec1.IsExtractionIdentifier); + Assert.Multiple(() => + { + // affects extraction specific version + Assert.That(ec1.IsExtractionIdentifier); - // but not master - Assert.IsFalse(ec1.CatalogueExtractionInformation.IsExtractionIdentifier); - } + // but not master + Assert.That(ec1.CatalogueExtractionInformation.IsExtractionIdentifier, Is.False); + }); + } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSimilarTests.cs b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSimilarTests.cs index 486314c57c..ac0b8e05a5 100644 --- a/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSimilarTests.cs +++ b/Rdmp.Core.Tests/CommandExecution/ExecuteCommandSimilarTests.cs @@ -23,7 +23,7 @@ public void FindSameName_MixedCaps() var activator = new ThrowImmediatelyActivator(RepositoryLocator); var cmd = new ExecuteCommandSimilar(activator, cata1, false); - Assert.AreEqual(cata2, cmd.Matched.Single()); + Assert.That(cmd.Matched.Single(), Is.EqualTo(cata2)); cata1.DeleteInDatabase(); cata2.DeleteInDatabase(); @@ -38,7 +38,7 @@ public void FindDifferent_ColumnInfosSame() var activator = new ThrowImmediatelyActivator(RepositoryLocator); var cmd = new ExecuteCommandSimilar(activator, c1, true); - Assert.IsEmpty(cmd.Matched); + Assert.That(cmd.Matched, Is.Empty); c1.DeleteInDatabase(); c2.DeleteInDatabase(); @@ -56,7 +56,7 @@ public void FindDifferent_ColumnInfosDiffer_OnType() var activator = new ThrowImmediatelyActivator(RepositoryLocator); var cmd = new ExecuteCommandSimilar(activator, c1, true); - Assert.AreEqual(c2, cmd.Matched.Single()); + Assert.That(cmd.Matched.Single(), Is.EqualTo(c2)); c1.DeleteInDatabase(); c2.DeleteInDatabase(); @@ -74,7 +74,7 @@ public void FindDifferent_ColumnInfosDiffer_OnCollation() var activator = new ThrowImmediatelyActivator(RepositoryLocator); var cmd = new ExecuteCommandSimilar(activator, c1, true); - Assert.AreEqual(c2, cmd.Matched.Single()); + Assert.That(cmd.Matched.Single(), Is.EqualTo(c2)); c1.DeleteInDatabase(); c2.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/CommandExecution/TestCommandsAreSupported.cs b/Rdmp.Core.Tests/CommandExecution/TestCommandsAreSupported.cs index 5a96722f23..d57a3c5c19 100644 --- a/Rdmp.Core.Tests/CommandExecution/TestCommandsAreSupported.cs +++ b/Rdmp.Core.Tests/CommandExecution/TestCommandsAreSupported.cs @@ -172,6 +172,6 @@ public void Init() // [TestCase(typeof(ExecuteCommandSetDataAccessContextForCredentials))] // Not currently CLI compatible public void TestIsSupported(Type t) { - Assert.IsNull(invoker.WhyCommandNotSupported(t), $"Type {t} was not supported by CommandInvoker"); + Assert.That(invoker.WhyCommandNotSupported(t), Is.Null, $"Type {t} was not supported by CommandInvoker"); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandAssociateCatalogueWithLoadMetadata.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandAssociateCatalogueWithLoadMetadata.cs index 02b623e25e..dc0bd49a85 100644 --- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandAssociateCatalogueWithLoadMetadata.cs +++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandAssociateCatalogueWithLoadMetadata.cs @@ -20,8 +20,11 @@ public void TestExecuteCommandAssociateCatalogueWithLoadMetadata_Simple() var cata1 = new Catalogue(RepositoryLocator.CatalogueRepository, "fff"); var cata2 = new Catalogue(RepositoryLocator.CatalogueRepository, "bbb"); - Assert.IsNull(cata1.LoadMetadata); - Assert.IsNull(cata2.LoadMetadata); + Assert.Multiple(() => + { + Assert.That(cata1.LoadMetadata, Is.Null); + Assert.That(cata2.LoadMetadata, Is.Null); + }); var lmd = new LoadMetadata(RepositoryLocator.CatalogueRepository, "mylmd"); @@ -31,7 +34,10 @@ public void TestExecuteCommandAssociateCatalogueWithLoadMetadata_Simple() cata1.RevertToDatabaseState(); cata2.RevertToDatabaseState(); - Assert.AreEqual(lmd.ID, cata1.LoadMetadata_ID); - Assert.IsNull(cata2.LoadMetadata); + Assert.Multiple(() => + { + Assert.That(cata1.LoadMetadata_ID, Is.EqualTo(lmd.ID)); + Assert.That(cata2.LoadMetadata, Is.Null); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandClearUserSettings.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandClearUserSettings.cs index eb2e3d0b6f..3491944822 100644 --- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandClearUserSettings.cs +++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandClearUserSettings.cs @@ -7,7 +7,6 @@ using NUnit.Framework; using Rdmp.Core.CommandExecution.AtomicCommands; using Rdmp.Core.CommandLine.Interactive.Picking; -using Rdmp.Core.ReusableLibraryCode.Checks; using Rdmp.Core.ReusableLibraryCode.Settings; namespace Rdmp.Core.Tests.CommandExecution; @@ -24,11 +23,11 @@ public void Test_ClearUserSettings() invoker.ExecuteCommand(typeof(ExecuteCommandSetUserSetting), new CommandLineObjectPicker(new[] { nameof(UserSettings.Wait5SecondsAfterStartupUI), "true" }, activator)); - Assert.IsTrue(UserSettings.Wait5SecondsAfterStartupUI); + Assert.That(UserSettings.Wait5SecondsAfterStartupUI); invoker.ExecuteCommand(typeof(ExecuteCommandSetUserSetting), new CommandLineObjectPicker(new[] { nameof(UserSettings.Wait5SecondsAfterStartupUI), "false" }, activator)); - Assert.IsFalse(UserSettings.Wait5SecondsAfterStartupUI); + Assert.That(UserSettings.Wait5SecondsAfterStartupUI, Is.False); invoker.ExecuteCommand(typeof(ExecuteCommandClearUserSettings), new CommandLineObjectPicker(System.Array.Empty(), activator)); - Assert.IsTrue(UserSettings.Wait5SecondsAfterStartupUI); + Assert.That(UserSettings.Wait5SecondsAfterStartupUI); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribe.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribe.cs index 608893fd1d..a07f74cea2 100644 --- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribe.cs +++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribe.cs @@ -25,7 +25,7 @@ public void TestDescribeCatalogue() c.Description = "fish"; var describe = new ExecuteCommandDescribe(mock, new[] { c }); - Assert.IsFalse(describe.IsImpossible, describe.ReasonCommandImpossible); + Assert.That(describe.IsImpossible, Is.False, describe.ReasonCommandImpossible); describe.Execute(); diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribeCommand.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribeCommand.cs index 801ffce86a..098973c594 100644 --- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribeCommand.cs +++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandDescribeCommand.cs @@ -24,10 +24,10 @@ private void AssertHelpIs(string expectedHelp, Type forCommand) var cmd = new ExecuteCommandDescribe(activator, new CommandLineObjectPicker(new[] { forCommand.Name }, activator)); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); - StringAssert.Contains(expectedHelp, cmd.HelpShown); + Assert.That(cmd.HelpShown, Does.Contain(expectedHelp)); } [Test] diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandImportFilterContainerTree.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandImportFilterContainerTree.cs index 1acda692f4..096643c7f6 100644 --- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandImportFilterContainerTree.cs +++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandImportFilterContainerTree.cs @@ -36,7 +36,7 @@ public void TestImportTree_FromCohortIdentificationConfiguration_ToSelectedDatas ac.RootFilterContainer.AddChild(filterToImport); //there should be no root container - Assert.IsNull(sds.RootFilterContainer); + Assert.That(sds.RootFilterContainer, Is.Null); //run the command var mgr = new ConsoleInputManager(RepositoryLocator, ThrowImmediatelyCheckNotifier.Quiet) @@ -45,16 +45,19 @@ public void TestImportTree_FromCohortIdentificationConfiguration_ToSelectedDatas }; var cmd = new ExecuteCommandImportFilterContainerTree(mgr, sds, ac); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); sds.ClearAllInjections(); - Assert.IsNotNull(sds.RootFilterContainer); - Assert.AreEqual(1, sds.RootFilterContainer.GetFilters().Length); - Assert.AreEqual("MyFilter", sds.RootFilterContainer.GetFilters()[0].Name); - Assert.AreEqual("true", sds.RootFilterContainer.GetFilters()[0].WhereSQL); + Assert.That(sds.RootFilterContainer, Is.Not.Null); + Assert.That(sds.RootFilterContainer.GetFilters(), Has.Length.EqualTo(1)); + Assert.Multiple(() => + { + Assert.That(sds.RootFilterContainer.GetFilters()[0].Name, Is.EqualTo("MyFilter")); + Assert.That(sds.RootFilterContainer.GetFilters()[0].WhereSQL, Is.EqualTo("true")); - Assert.AreNotEqual(filterToImport.GetType(), sds.RootFilterContainer.GetFilters()[0].GetType()); + Assert.That(sds.RootFilterContainer.GetFilters()[0].GetType(), Is.Not.EqualTo(filterToImport.GetType())); + }); } [Test] @@ -79,7 +82,7 @@ public void TestImportTree_FromSelectedDatasets_ToCohortIdentificationConfigurat cic.RootCohortAggregateContainer.AddChild(ac, 1); //there should be no root container - Assert.IsNull(ac.RootFilterContainer); + Assert.That(ac.RootFilterContainer, Is.Null); //run the command var mgr = new ConsoleInputManager(RepositoryLocator, ThrowImmediatelyCheckNotifier.Quiet) @@ -88,16 +91,19 @@ public void TestImportTree_FromSelectedDatasets_ToCohortIdentificationConfigurat }; var cmd = new ExecuteCommandImportFilterContainerTree(mgr, ac, sds); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); ac.ClearAllInjections(); - Assert.IsNotNull(ac.RootFilterContainer); - Assert.AreEqual(1, ac.RootFilterContainer.GetFilters().Length); - Assert.AreEqual("MyFilter", ac.RootFilterContainer.GetFilters()[0].Name); - Assert.AreEqual("true", ac.RootFilterContainer.GetFilters()[0].WhereSQL); + Assert.That(ac.RootFilterContainer, Is.Not.Null); + Assert.That(ac.RootFilterContainer.GetFilters(), Has.Length.EqualTo(1)); + Assert.Multiple(() => + { + Assert.That(ac.RootFilterContainer.GetFilters()[0].Name, Is.EqualTo("MyFilter")); + Assert.That(ac.RootFilterContainer.GetFilters()[0].WhereSQL, Is.EqualTo("true")); - Assert.AreNotEqual(filterToImport.GetType(), ac.RootFilterContainer.GetFilters()[0].GetType()); + Assert.That(ac.RootFilterContainer.GetFilters()[0].GetType(), Is.Not.EqualTo(filterToImport.GetType())); + }); } @@ -126,7 +132,7 @@ public void TestImportTree_FromCohortIdentificationConfiguration_ToSelectedDatas root.AddChild(new AggregateFilterContainer(Repository, FilterContainerOperation.OR)); //there should be no root container - Assert.IsNull(sds.RootFilterContainer); + Assert.That(sds.RootFilterContainer, Is.Null); //run the command var mgr = new ConsoleInputManager(RepositoryLocator, ThrowImmediatelyCheckNotifier.Quiet) @@ -135,17 +141,23 @@ public void TestImportTree_FromCohortIdentificationConfiguration_ToSelectedDatas }; var cmd = new ExecuteCommandImportFilterContainerTree(mgr, sds, ac); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); sds.ClearAllInjections(); - Assert.AreEqual(FilterContainerOperation.OR, sds.RootFilterContainer.Operation); - Assert.IsNotNull(sds.RootFilterContainer); - Assert.AreEqual(1, sds.RootFilterContainer.GetFilters().Length); + Assert.Multiple(() => + { + Assert.That(sds.RootFilterContainer.Operation, Is.EqualTo(FilterContainerOperation.OR)); + Assert.That(sds.RootFilterContainer, Is.Not.Null); + }); + Assert.That(sds.RootFilterContainer.GetFilters(), Has.Length.EqualTo(1)); var subContainers = sds.RootFilterContainer.GetSubContainers(); - Assert.AreEqual(2, subContainers.Length); - Assert.AreEqual(1, subContainers.Count(e => e.Operation == FilterContainerOperation.AND)); - Assert.AreEqual(1, subContainers.Count(e => e.Operation == FilterContainerOperation.OR)); + Assert.That(subContainers, Has.Length.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(subContainers.Count(e => e.Operation == FilterContainerOperation.AND), Is.EqualTo(1)); + Assert.That(subContainers.Count(e => e.Operation == FilterContainerOperation.OR), Is.EqualTo(1)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandImportTableInfo.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandImportTableInfo.cs index 410d05d1ed..7a9d3c98d1 100644 --- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandImportTableInfo.cs +++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandImportTableInfo.cs @@ -19,9 +19,8 @@ public void Test_ImportTableInfo_NoArguments() var ex = Assert.Throws(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandImportTableInfo), new CommandLineObjectPicker(Array.Empty(), GetActivator()))); - StringAssert.StartsWith( - "Expected parameter at index 0 to be a FAnsi.Discovery.DiscoveredTable (for parameter 'table') but it was Missing", - ex.Message); + Assert.That( + ex.Message, Does.StartWith("Expected parameter at index 0 to be a FAnsi.Discovery.DiscoveredTable (for parameter 'table') but it was Missing")); } [Test] @@ -30,9 +29,8 @@ public void Test_ImportTableInfo_MalformedArgument() var ex = Assert.Throws(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandImportTableInfo), new CommandLineObjectPicker(new string[] { "MyTable" }, GetActivator()))); - StringAssert.StartsWith( - "Expected parameter at index 0 to be a FAnsi.Discovery.DiscoveredTable (for parameter 'table') but it was MyTable", - ex.Message); + Assert.That( + ex.Message, Does.StartWith("Expected parameter at index 0 to be a FAnsi.Discovery.DiscoveredTable (for parameter 'table') but it was MyTable")); } [Test] @@ -44,6 +42,6 @@ public void Test_ImportTableInfo_NoTable() var ex = Assert.Throws(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandImportTableInfo), new CommandLineObjectPicker(new string[] { tbl, "true" }, GetActivator()))); - StringAssert.StartsWith("Could not reach server myServerAddress", ex.Message); + Assert.That(ex.Message, Does.StartWith("Could not reach server myServerAddress")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandNewObject.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandNewObject.cs index 1205cf0f7f..6b99827b36 100644 --- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandNewObject.cs +++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandNewObject.cs @@ -22,7 +22,7 @@ public void Test_NewObjectCommand_NoArguments() var ex = Assert.Throws(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandNewObject), new CommandLineObjectPicker(Array.Empty(), GetActivator()))); - StringAssert.StartsWith("First parameter must be a Type", ex.Message); + Assert.That(ex.Message, Does.StartWith("First parameter must be a Type")); } [Test] @@ -31,41 +31,40 @@ public void Test_NewObjectCommand_NonExistentTypeArgument() var ex = Assert.Throws(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandNewObject), new CommandLineObjectPicker(new[] { "Fissdlkfldfj" }, GetActivator()))); - StringAssert.StartsWith("First parameter must be a Type", ex.Message); + Assert.That(ex.Message, Does.StartWith("First parameter must be a Type")); } [Test] public void Test_NewObjectCommand_WrongTypeArgument() { var picker = new CommandLineObjectPicker(new[] { "UnitTests" }, GetActivator()); - Assert.AreEqual(typeof(UnitTests), picker[0].Type); + Assert.That(picker[0].Type, Is.EqualTo(typeof(UnitTests))); var ex = Assert.Throws(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandNewObject), picker)); - StringAssert.StartsWith("Type must be derived from DatabaseEntity", ex.Message); + Assert.That(ex.Message, Does.StartWith("Type must be derived from DatabaseEntity")); } [Test] public void Test_NewObjectCommand_MissingNameArgument() { var picker = new CommandLineObjectPicker(new[] { "Catalogue" }, GetActivator()); - Assert.AreEqual(typeof(Catalogue), picker[0].Type); + Assert.That(picker[0].Type, Is.EqualTo(typeof(Catalogue))); var ex = Assert.Throws(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandNewObject), picker)); - StringAssert.StartsWith("Value needed for parameter 'name' (of type 'System.String')", ex.Message); + Assert.That(ex.Message, Does.StartWith("Value needed for parameter 'name' (of type 'System.String')")); } [Test] public void Test_NewObjectCommand_Success() { var picker = new CommandLineObjectPicker(new[] { "Catalogue", "lolzeeeyeahyeah" }, GetActivator()); - Assert.AreEqual(typeof(Catalogue), picker[0].Type); + Assert.That(picker[0].Type, Is.EqualTo(typeof(Catalogue))); Assert.DoesNotThrow(() => GetInvoker().ExecuteCommand(typeof(ExecuteCommandNewObject), picker)); - Assert.Contains("lolzeeeyeahyeah", - RepositoryLocator.CatalogueRepository.GetAllObjects().Select(c => c.Name).ToArray()); + Assert.That(RepositoryLocator.CatalogueRepository.GetAllObjects().Select(c => c.Name).ToArray(), Does.Contain("lolzeeeyeahyeah")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSet.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSet.cs index f878ddfe6f..d9bcc78475 100644 --- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSet.cs +++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSet.cs @@ -25,7 +25,7 @@ public void Test_CatalogueDescription_Normal() }, GetActivator())); cata.RevertToDatabaseState(); - Assert.AreEqual("Some long description", cata.Description); + Assert.That(cata.Description, Is.EqualTo("Some long description")); } [Test] @@ -43,7 +43,7 @@ public void Test_CatalogueDescription_Null() }, GetActivator())); cata.RevertToDatabaseState(); - Assert.IsNull(cata.Description); + Assert.That(cata.Description, Is.Null); } [Test] @@ -61,17 +61,23 @@ public void TestExecuteCommandSet_SetArrayValueFromCLI() var ids = $"{t1.ID},{t2.ID},{t3.ID},{t4.ID}"; - Assert.IsNull(pta.Value); - Assert.IsNull(pta.GetValueAsSystemType()); + Assert.Multiple(() => + { + Assert.That(pta.Value, Is.Null); + Assert.That(pta.GetValueAsSystemType(), Is.Null); + }); GetInvoker().ExecuteCommand(typeof(ExecuteCommandSet), new CommandLineObjectPicker(new[] { "ProcessTaskArgument:TablesToIsolate", "Value", ids }, GetActivator())); - Assert.AreEqual(ids, pta.Value); + Assert.Multiple(() => + { + Assert.That(pta.Value, Is.EqualTo(ids)); - Assert.Contains(t1, (TableInfo[])pta.GetValueAsSystemType()); - Assert.Contains(t2, (TableInfo[])pta.GetValueAsSystemType()); - Assert.Contains(t3, (TableInfo[])pta.GetValueAsSystemType()); - Assert.Contains(t4, (TableInfo[])pta.GetValueAsSystemType()); + Assert.That((TableInfo[])pta.GetValueAsSystemType(), Does.Contain(t1)); + }); + Assert.That((TableInfo[])pta.GetValueAsSystemType(), Does.Contain(t2)); + Assert.That((TableInfo[])pta.GetValueAsSystemType(), Does.Contain(t3)); + Assert.That((TableInfo[])pta.GetValueAsSystemType(), Does.Contain(t4)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSetUserSetting.cs b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSetUserSetting.cs index e95324837e..0c9c5f7674 100644 --- a/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSetUserSetting.cs +++ b/Rdmp.Core.Tests/CommandExecution/TestExecuteCommandSetUserSetting.cs @@ -22,36 +22,38 @@ public void Test_CatalogueDescription_Normal() GetInvoker().ExecuteCommand(typeof(ExecuteCommandSetUserSetting), new CommandLineObjectPicker(new[] { "Wait5SecondsAfterStartupUI", "true" }, GetActivator())); - Assert.IsTrue(UserSettings.Wait5SecondsAfterStartupUI); + Assert.That(UserSettings.Wait5SecondsAfterStartupUI); GetInvoker().ExecuteCommand(typeof(ExecuteCommandSetUserSetting), new CommandLineObjectPicker(new[] { "Wait5SecondsAfterStartupUI", "false" }, GetActivator())); - Assert.IsFalse(UserSettings.Wait5SecondsAfterStartupUI); + Assert.That(UserSettings.Wait5SecondsAfterStartupUI, Is.False); } [Test] public void TestSettingErrorCodeValue_InvalidValue() { var cmd = new ExecuteCommandSetUserSetting(GetActivator(), "R001", "foo"); - Assert.IsTrue(cmd.IsImpossible); - Assert.AreEqual(cmd.ReasonCommandImpossible, - "Invalid enum value. When setting an error code you must supply a value of one of :Success,Warning,Fail"); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Is.EqualTo("Invalid enum value. When setting an error code you must supply a value of one of :Success,Warning,Fail")); + }); } [Test] public void TestSettingErrorCodeValue_Success() { - Assert.AreEqual("R001", ErrorCodes.ExistingExtractionTableInDatabase.Code); + Assert.That(ErrorCodes.ExistingExtractionTableInDatabase.Code, Is.EqualTo("R001")); var before = UserSettings.GetErrorReportingLevelFor(ErrorCodes.ExistingExtractionTableInDatabase); - Assert.AreNotEqual(CheckResult.Success, before); + Assert.That(before, Is.Not.EqualTo(CheckResult.Success)); var cmd = new ExecuteCommandSetUserSetting(GetActivator(), "R001", "Success"); - Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible); + Assert.That(cmd.IsImpossible, Is.False, cmd.ReasonCommandImpossible); cmd.Execute(); var after = UserSettings.GetErrorReportingLevelFor(ErrorCodes.ExistingExtractionTableInDatabase); - Assert.AreEqual(CheckResult.Success, after); + Assert.That(after, Is.EqualTo(CheckResult.Success)); //reset the original state of the system (the default) UserSettings.SetErrorReportingLevelFor(ErrorCodes.ExistingExtractionTableInDatabase, before); diff --git a/Rdmp.Core.Tests/CommandLine/AbstractBaseRunnerTests.cs b/Rdmp.Core.Tests/CommandLine/AbstractBaseRunnerTests.cs index 1b0dccbbac..2960dfe5b8 100644 --- a/Rdmp.Core.Tests/CommandLine/AbstractBaseRunnerTests.cs +++ b/Rdmp.Core.Tests/CommandLine/AbstractBaseRunnerTests.cs @@ -35,7 +35,7 @@ public void GetObjectFromCommandLineString_CatalogueByID() WhenIHaveA(); WhenIHaveA(); var r = new TestRunner(); - Assert.AreEqual(c, TestRunner.GetObjectFromCommandLineString(RepositoryLocator, c.ID.ToString())); + Assert.That(TestRunner.GetObjectFromCommandLineString(RepositoryLocator, c.ID.ToString()), Is.EqualTo(c)); } [Test] @@ -48,7 +48,7 @@ public void GetObjectFromCommandLineString_CatalogueByPattern() WhenIHaveA(); WhenIHaveA(); var r = new TestRunner(); - Assert.AreEqual(c, TestRunner.GetObjectFromCommandLineString(RepositoryLocator, "Catalogue:*go*")); + Assert.That(TestRunner.GetObjectFromCommandLineString(RepositoryLocator, "Catalogue:*go*"), Is.EqualTo(c)); } [Test] @@ -58,7 +58,7 @@ public void GetObjectFromCommandLineString_ProjectByID() WhenIHaveA(); WhenIHaveA(); var r = new TestRunner(); - Assert.AreEqual(c, TestRunner.GetObjectFromCommandLineString(RepositoryLocator, c.ID.ToString())); + Assert.That(TestRunner.GetObjectFromCommandLineString(RepositoryLocator, c.ID.ToString()), Is.EqualTo(c)); } [Test] @@ -71,7 +71,7 @@ public void GetObjectFromCommandLineString_ProjectByPattern() WhenIHaveA(); WhenIHaveA(); var r = new TestRunner(); - Assert.AreEqual(c, TestRunner.GetObjectFromCommandLineString(RepositoryLocator, "Project:*go*")); + Assert.That(TestRunner.GetObjectFromCommandLineString(RepositoryLocator, "Project:*go*"), Is.EqualTo(c)); } /// @@ -92,7 +92,7 @@ public void GetObjectFromCommandLineString_Null(string expression) WhenIHaveA(); WhenIHaveA(); var r = new TestRunner(); - Assert.IsNull(TestRunner.GetObjectFromCommandLineString(RepositoryLocator, expression)); + Assert.That(TestRunner.GetObjectFromCommandLineString(RepositoryLocator, expression), Is.Null); } /// @@ -112,7 +112,7 @@ public void GetObjectsFromCommandLineString_Null(string expression) WhenIHaveA(); WhenIHaveA(); var r = new TestRunner(); - Assert.IsEmpty(TestRunner.GetObjectsFromCommandLineString(RepositoryLocator, expression)); + Assert.That(TestRunner.GetObjectsFromCommandLineString(RepositoryLocator, expression), Is.Empty); } @@ -127,9 +127,12 @@ public void GetObjectsFromCommandLineString_CatalogueByID() var results = TestRunner.GetObjectsFromCommandLineString(RepositoryLocator, $"{c.ID},{c2.ID}") .ToArray(); - Assert.AreEqual(2, results.Length); - Assert.AreSame(c, results[0]); - Assert.AreSame(c2, results[1]); + Assert.That(results, Has.Length.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(results[0], Is.SameAs(c)); + Assert.That(results[1], Is.SameAs(c2)); + }); } [Test] @@ -149,9 +152,9 @@ public void GetObjectsFromCommandLineString_CatalogueByPattern() var results = TestRunner.GetObjectsFromCommandLineString(RepositoryLocator, "Catalogue:*go*") .ToArray(); - Assert.AreEqual(2, results.Length); - Assert.Contains(c, results); - Assert.Contains(c2, results); + Assert.That(results, Has.Length.EqualTo(2)); + Assert.That(results, Does.Contain(c)); + Assert.That(results, Does.Contain(c2)); } private class TestRunner : Runner diff --git a/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndCacheTest.cs b/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndCacheTest.cs index f214a8bafc..a0817140af 100644 --- a/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndCacheTest.cs +++ b/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndCacheTest.cs @@ -91,14 +91,14 @@ public void FireItUpManually() cachingHost.Start(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); // should be numDaysToCache days in cache - Assert.AreEqual(NumDaysToCache, _LoadDirectory.Cache.GetFiles("*.csv").Length); + Assert.That(_LoadDirectory.Cache.GetFiles("*.csv"), Has.Length.EqualTo(NumDaysToCache)); // make sure each file is named as expected var cacheFiles = _LoadDirectory.Cache.GetFiles().Select(fi => fi.Name).ToArray(); for (var i = -NumDaysToCache; i < 0; i++) { var filename = $"{DateTime.Now.AddDays(i):yyyyMMdd}.csv"; - Assert.IsTrue(cacheFiles.Contains(filename), filename + " not found"); + Assert.That(cacheFiles, Does.Contain(filename), filename + " not found"); } } @@ -107,7 +107,7 @@ public void RunEndToEndCacheTest() { var t = Task.Factory.StartNew(() => { - Assert.AreEqual(0, _LoadDirectory.Cache.GetFiles("*.csv").Length); + Assert.That(_LoadDirectory.Cache.GetFiles("*.csv"), Is.Empty); var auto = new CacheRunner(new CacheOptions { CacheProgress = _cp.ID.ToString(), Command = CommandLineActivity.run }); @@ -115,6 +115,6 @@ public void RunEndToEndCacheTest() ThrowImmediatelyCheckNotifier.Quiet, new GracefulCancellationToken()); }); - Assert.True(t.Wait(60000)); + Assert.That(t.Wait(60000)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndDLECacheTest.cs b/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndDLECacheTest.cs index 59bbe968c4..8789b92415 100644 --- a/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndDLECacheTest.cs +++ b/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndDLECacheTest.cs @@ -68,19 +68,22 @@ public void RunEndToEndDLECacheTest() RunDLE(timeoutInMilliseconds); - Assert.AreEqual(10, RowsNow - RowsBefore); + Assert.Multiple(() => + { + Assert.That(RowsNow - RowsBefore, Is.EqualTo(10)); - Assert.AreEqual(0, LoadDirectory.Cache.GetFiles().Length); - Assert.AreEqual(0, LoadDirectory.ForLoading.GetFiles().Length); - Assert.AreEqual(1, LoadDirectory.ForArchiving.GetFiles().Length); + Assert.That(LoadDirectory.Cache.GetFiles(), Is.Empty); + Assert.That(LoadDirectory.ForLoading.GetFiles(), Is.Empty); + Assert.That(LoadDirectory.ForArchiving.GetFiles(), Has.Length.EqualTo(1)); + }); var archiveFile = LoadDirectory.ForArchiving.GetFiles()[0]; - Assert.AreEqual(".zip", archiveFile.Extension); + Assert.That(archiveFile.Extension, Is.EqualTo(".zip")); //load progress should be updated to the largest date in the cache (2001-01-09) lp.RevertToDatabaseState(); - Assert.AreEqual(lp.DataLoadProgress, new DateTime(2001, 01, 09)); + Assert.That(new DateTime(2001, 01, 09), Is.EqualTo(lp.DataLoadProgress)); cp.DeleteInDatabase(); lp.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndDLETest.cs b/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndDLETest.cs index 0c36ecc140..e23f5e5c16 100644 --- a/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndDLETest.cs +++ b/Rdmp.Core.Tests/CommandLine/AutomationLoopTests/EndToEndDLETest.cs @@ -55,11 +55,14 @@ public void TestDle_DodgyColumnNames(DatabaseType dbType) cata.LoadMetadata_ID = lmd.ID; cata.SaveToDatabase(); - Assert.AreEqual(0, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(0)); RunDLE(lmd, 30000, true); - Assert.AreEqual(1, tbl.GetRowCount()); - Assert.AreEqual("fishon", tbl.GetDataTable().Rows[0][",,,,"]); + Assert.Multiple(() => + { + Assert.That(tbl.GetRowCount(), Is.EqualTo(1)); + Assert.That(tbl.GetDataTable().Rows[0][",,,,"], Is.EqualTo("fishon")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandLine/CommandLineObjectPickerTests.cs b/Rdmp.Core.Tests/CommandLine/CommandLineObjectPickerTests.cs index 5d652bf868..683429da0e 100644 --- a/Rdmp.Core.Tests/CommandLine/CommandLineObjectPickerTests.cs +++ b/Rdmp.Core.Tests/CommandLine/CommandLineObjectPickerTests.cs @@ -33,11 +33,14 @@ public void Test_RandomGarbage_GeneratesRawValueOnly() const string str = "Shiver me timbers"; var picker = new CommandLineObjectPicker(new[] { str }, GetActivator()); - Assert.AreEqual(str, picker[0].RawValue); - Assert.IsNull(picker[0].DatabaseEntities); - Assert.IsNull(picker[0].Database); - Assert.IsNull(picker[0].Table); - Assert.IsNull(picker[0].Type); + Assert.Multiple(() => + { + Assert.That(picker[0].RawValue, Is.EqualTo(str)); + Assert.That(picker[0].DatabaseEntities, Is.Null); + Assert.That(picker[0].Database, Is.Null); + Assert.That(picker[0].Table, Is.Null); + Assert.That(picker[0].Type, Is.Null); + }); } [Test] @@ -47,13 +50,13 @@ public void Test_PickCatalogueByID_PickOne() var picker = new CommandLineObjectPicker(new[] { $"Catalogue:{cata.ID}" }, GetActivator()); - Assert.AreEqual(cata, picker[0].DatabaseEntities.Single()); + Assert.That(picker[0].DatabaseEntities.Single(), Is.EqualTo(cata)); //specifying the same ID twice shouldn't return duplicate objects picker = new CommandLineObjectPicker(new[] { $"Catalogue:{cata.ID},{cata.ID}" }, GetActivator()); - Assert.AreEqual(cata, picker[0].DatabaseEntities.Single()); + Assert.That(picker[0].DatabaseEntities.Single(), Is.EqualTo(cata)); } /// @@ -66,16 +69,19 @@ public void Test_PickerForWhitespace(string val) { var picker = new CommandLineObjectPicker(new[] { val }, GetActivator()); - Assert.AreEqual(1, picker.Length); - - Assert.IsNull(picker[0].Database); - Assert.IsNull(picker[0].DatabaseEntities); - Assert.IsFalse(picker[0].ExplicitNull); - Assert.AreEqual(val, picker[0].RawValue); - Assert.IsNull(picker[0].Type); + Assert.That(picker.Length, Is.EqualTo(1)); - Assert.AreEqual(val, picker[0].GetValueForParameterOfType(typeof(string))); - Assert.IsTrue(picker.HasArgumentOfType(0, typeof(string))); + Assert.Multiple(() => + { + Assert.That(picker[0].Database, Is.Null); + Assert.That(picker[0].DatabaseEntities, Is.Null); + Assert.That(picker[0].ExplicitNull, Is.False); + Assert.That(picker[0].RawValue, Is.EqualTo(val)); + Assert.That(picker[0].Type, Is.Null); + + Assert.That(picker[0].GetValueForParameterOfType(typeof(string)), Is.EqualTo(val)); + Assert.That(picker.HasArgumentOfType(0, typeof(string))); + }); } [Test] @@ -86,9 +92,9 @@ public void Test_PickCatalogueByID_PickTwo() var picker = new CommandLineObjectPicker(new[] { $"Catalogue:{cata1.ID},{cata2.ID}" }, GetActivator()); - Assert.AreEqual(2, picker[0].DatabaseEntities.Count); - Assert.Contains(cata1, picker[0].DatabaseEntities); - Assert.Contains(cata2, picker[0].DatabaseEntities); + Assert.That(picker[0].DatabaseEntities, Has.Count.EqualTo(2)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(cata1)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(cata2)); } [Test] @@ -108,9 +114,9 @@ public void Test_PickCatalogueByName_PickTwo() var picker = new CommandLineObjectPicker(new[] { $"Catalogue:lol*" }, GetActivator()); - Assert.AreEqual(2, picker[0].DatabaseEntities.Count); - Assert.Contains(cata1, picker[0].DatabaseEntities); - Assert.Contains(cata2, picker[0].DatabaseEntities); + Assert.That(picker[0].DatabaseEntities, Has.Count.EqualTo(2)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(cata1)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(cata2)); } [Test] @@ -119,27 +125,30 @@ public void TestPicker_TypeYieldsEmptyArrayOfObjects() foreach (var cat in RepositoryLocator.CatalogueRepository.GetAllObjects()) cat.DeleteInDatabase(); - Assert.IsEmpty(RepositoryLocator.CatalogueRepository.GetAllObjects()); + Assert.That(RepositoryLocator.CatalogueRepository.GetAllObjects(), Is.Empty); //when interpreting the string "Catalogue" for a command var picker = new CommandLineObjectPicker(new[] { "Catalogue" }, GetActivator()); - //we can pick it as either a Catalogue or a collection of all the Catalogues - Assert.AreEqual(typeof(Catalogue), picker.Arguments.Single().Type); - Assert.IsEmpty(picker.Arguments.Single().DatabaseEntities); - - //when interpretting as a Type we get Catalogue - Assert.IsTrue(picker.Arguments.First().HasValueOfType(typeof(Type))); - Assert.AreEqual(typeof(Catalogue), picker.Arguments.Single().GetValueForParameterOfType(typeof(Type))); - - //if it is looking for an ienumerable of objects - Assert.IsTrue(picker.Arguments.First().HasValueOfType(typeof(IMapsDirectlyToDatabaseTable[]))); - Assert.IsEmpty((IMapsDirectlyToDatabaseTable[])picker.Arguments.First() - .GetValueForParameterOfType(typeof(IMapsDirectlyToDatabaseTable[]))); - - Assert.IsTrue(picker.Arguments.First().HasValueOfType(typeof(Catalogue[]))); - Assert.IsEmpty( - ((Catalogue[])picker.Arguments.First().GetValueForParameterOfType(typeof(Catalogue[]))).ToArray()); + Assert.Multiple(() => + { + //we can pick it as either a Catalogue or a collection of all the Catalogues + Assert.That(picker.Arguments.Single().Type, Is.EqualTo(typeof(Catalogue))); + Assert.That(picker.Arguments.Single().DatabaseEntities, Is.Empty); + + //when interpretting as a Type we get Catalogue + Assert.That(picker.Arguments.First().HasValueOfType(typeof(Type))); + Assert.That(picker.Arguments.Single().GetValueForParameterOfType(typeof(Type)), Is.EqualTo(typeof(Catalogue))); + + //if it is looking for an ienumerable of objects + Assert.That(picker.Arguments.First().HasValueOfType(typeof(IMapsDirectlyToDatabaseTable[]))); + Assert.That((IMapsDirectlyToDatabaseTable[])picker.Arguments.First() + .GetValueForParameterOfType(typeof(IMapsDirectlyToDatabaseTable[])), Is.Empty); + + Assert.That(picker.Arguments.First().HasValueOfType(typeof(Catalogue[]))); + Assert.That( + ((Catalogue[])picker.Arguments.First().GetValueForParameterOfType(typeof(Catalogue[]))).ToArray(), Is.Empty); + }); } [TestCase(typeof(PickDatabase))] @@ -157,20 +166,22 @@ public void Pickers_ShouldAllHaveValidExamples_MatchingRegex(Type pickerType) var picker = (PickObjectBase)ObjectConstructor.Construct(pickerType, GetActivator(new RepositoryProvider(mem))); - Assert.IsNotEmpty(picker.Help, "No Help for picker {0}", picker); - Assert.IsNotEmpty(picker.Format, "No Format for picker {0}", picker); - Assert.IsNotNull(picker.Examples, "No Examples for picker {0}", picker); - Assert.IsNotEmpty(picker.Examples, "No Examples for picker {0}", picker); + Assert.Multiple(() => + { + Assert.That(picker.Help, Is.Not.Empty, $"No Help for picker {picker}"); + Assert.That(picker.Format, Is.Not.Empty, $"No Format for picker {picker}"); + Assert.That(picker.Examples, Is.Not.Null, $"No Examples for picker {picker}"); + }); + Assert.That(picker.Examples, Is.Not.Empty, $"No Examples for picker {picker}"); foreach (var example in picker.Examples) { //examples should be matched by the picker! - Assert.IsTrue(picker.IsMatch(example, 0), - "Example of picker '{0}' did not match the regex,listed example is '{1}'", picker, example); + Assert.That(picker.IsMatch(example, 0), $"Example of picker '{picker}' did not match the regex,listed example is '{example}'"); var result = picker.Parse(example, 0); - Assert.IsNotNull(result); + Assert.That(result, Is.Not.Null); } } @@ -179,8 +190,11 @@ public void PickTypeName() { var picker = new CommandLineObjectPicker(new[] { "Name" }, GetActivator()); - Assert.IsNull(picker[0].Type); - Assert.AreEqual("Name", picker[0].RawValue); + Assert.Multiple(() => + { + Assert.That(picker[0].Type, Is.Null); + Assert.That(picker[0].RawValue, Is.EqualTo("Name")); + }); } [TestCase("null")] @@ -188,7 +202,7 @@ public void PickTypeName() public void PickNull(string nullString) { var picker = new CommandLineObjectPicker(new[] { nullString }, GetActivator()); - Assert.IsTrue(picker[0].ExplicitNull); + Assert.That(picker[0].ExplicitNull); } [Test] @@ -202,8 +216,11 @@ public void Test_PickCatalogueByName_WithShortCode() var picker = new CommandLineObjectPicker(new[] { $"c:*io*" }, GetActivator()); - Assert.AreEqual(cata1, picker[0].DatabaseEntities[0]); - Assert.AreEqual(1, picker[0].DatabaseEntities.Count); + Assert.Multiple(() => + { + Assert.That(picker[0].DatabaseEntities[0], Is.EqualTo(cata1)); + Assert.That(picker[0].DatabaseEntities, Has.Count.EqualTo(1)); + }); } [Test] @@ -214,9 +231,9 @@ public void Test_PickCatalogueByID_WithShortCode() var picker = new CommandLineObjectPicker(new[] { $"c:{cata1.ID},{cata2.ID}" }, GetActivator()); - Assert.AreEqual(2, picker[0].DatabaseEntities.Count); - Assert.Contains(cata1, picker[0].DatabaseEntities); - Assert.Contains(cata2, picker[0].DatabaseEntities); + Assert.That(picker[0].DatabaseEntities, Has.Count.EqualTo(2)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(cata1)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(cata2)); } [Test] @@ -229,9 +246,9 @@ public void Test_PickCatalogueByTypeOnly_WithShortCode() // so this would be the use case 'rdmp cmd list Catalogue' where user can instead write 'rdmp cmd list c' var picker = new CommandLineObjectPicker(new[] { $"c" }, GetActivator()); - Assert.AreEqual(2, picker[0].DatabaseEntities.Count); - Assert.Contains(cata1, picker[0].DatabaseEntities); - Assert.Contains(cata2, picker[0].DatabaseEntities); + Assert.That(picker[0].DatabaseEntities, Has.Count.EqualTo(2)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(cata1)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(cata2)); } [Test] @@ -247,10 +264,10 @@ public void Test_PickWithPropertyQuery_CatalogueItemsByCatalogue() var cataId = ci.Catalogue.ID; var picker = new CommandLineObjectPicker(new[] { $"CatalogueItem?Catalogue_ID:{cataId}" }, GetActivator()); - Assert.AreEqual(2, picker[0].DatabaseEntities.Count); - Assert.Contains(ci, picker[0].DatabaseEntities); - Assert.Contains(ci2, picker[0].DatabaseEntities); - Assert.IsFalse(picker[0].DatabaseEntities.Contains(ci3)); + Assert.That(picker[0].DatabaseEntities, Has.Count.EqualTo(2)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(ci)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(ci2)); + Assert.That(picker[0].DatabaseEntities, Does.Not.Contain(ci3)); } [Test] @@ -267,10 +284,10 @@ public void Test_PickWithPropertyQuery_CatalogueByFolder() var picker = new CommandLineObjectPicker(new[] { $"Catalogue?Folder:*hi*" }, GetActivator()); - Assert.AreEqual(2, picker[0].DatabaseEntities.Count); - Assert.Contains(c1, picker[0].DatabaseEntities); - Assert.Contains(c3, picker[0].DatabaseEntities); - Assert.IsFalse(picker[0].DatabaseEntities.Contains(c2)); + Assert.That(picker[0].DatabaseEntities, Has.Count.EqualTo(2)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(c1)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(c3)); + Assert.That(picker[0].DatabaseEntities, Does.Not.Contain(c2)); } [Test] @@ -286,8 +303,8 @@ public void Test_PickWithPropertyQuery_PeriodicityNull() var picker = new CommandLineObjectPicker(new[] { $"Catalogue?PivotCategory_ExtractionInformation_ID:null" }, GetActivator()); - Assert.AreEqual(1, picker[0].DatabaseEntities.Count); - Assert.Contains(c2, picker[0].DatabaseEntities); + Assert.That(picker[0].DatabaseEntities, Has.Count.EqualTo(1)); + Assert.That(picker[0].DatabaseEntities, Does.Contain(c2)); } [Test] @@ -295,6 +312,6 @@ public void Test_PickWithPropertyQuery_UnknownProperty() { var ex = Assert.Throws(() => new CommandLineObjectPicker(new[] { $"Catalogue?Blarg:null" }, GetActivator())); - Assert.AreEqual("Unknown property 'Blarg'. Did not exist on Type 'Catalogue'", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Unknown property 'Blarg'. Did not exist on Type 'Catalogue'")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandLine/ExampleDatasetsCreationTests.cs b/Rdmp.Core.Tests/CommandLine/ExampleDatasetsCreationTests.cs index 2e6469c49b..1f64d19a13 100644 --- a/Rdmp.Core.Tests/CommandLine/ExampleDatasetsCreationTests.cs +++ b/Rdmp.Core.Tests/CommandLine/ExampleDatasetsCreationTests.cs @@ -23,9 +23,12 @@ internal class ExampleDatasetsCreationTests : DatabaseTests [Test] public void Test_ExampleDatasetsCreation() { - //Should be empty RDMP metadata database - Assert.AreEqual(0, CatalogueRepository.GetAllObjects().Length); - Assert.AreEqual(0, CatalogueRepository.GetAllObjects().Length); + Assert.Multiple(() => + { + //Should be empty RDMP metadata database + Assert.That(CatalogueRepository.GetAllObjects(), Is.Empty); + Assert.That(CatalogueRepository.GetAllObjects(), Is.Empty); + }); //create the pipelines var pipes = new CataloguePipelinesAndReferencesCreation(RepositoryLocator, null, null); @@ -39,10 +42,13 @@ public void Test_ExampleDatasetsCreation() //should be at least 2 views (marked as view) var views = CatalogueRepository.GetAllObjects().Count(ti => ti.IsView); - Assert.GreaterOrEqual(views, 2); + Assert.Multiple(() => + { + Assert.That(views, Is.GreaterThanOrEqualTo(2)); - //should have at least created some catalogues, graphs etc - Assert.GreaterOrEqual(CatalogueRepository.GetAllObjects().Length, 4); - Assert.GreaterOrEqual(CatalogueRepository.GetAllObjects().Length, 4); + //should have at least created some catalogues, graphs etc + Assert.That(CatalogueRepository.GetAllObjects(), Has.Length.GreaterThanOrEqualTo(4)); + Assert.That(CatalogueRepository.GetAllObjects(), Has.Length.GreaterThanOrEqualTo(4)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandLine/NewObjectPoolTests.cs b/Rdmp.Core.Tests/CommandLine/NewObjectPoolTests.cs index 140780c124..d09c4ada43 100644 --- a/Rdmp.Core.Tests/CommandLine/NewObjectPoolTests.cs +++ b/Rdmp.Core.Tests/CommandLine/NewObjectPoolTests.cs @@ -22,13 +22,16 @@ public void TwoCataloguesWithSameName_NoSession() // When there is only one object we can pick it by name var picker = new CommandLineObjectPicker(new string[] { "Catalogue:Hey" }, GetActivator()); - Assert.IsTrue(picker.HasArgumentOfType(0, typeof(Catalogue))); - Assert.AreEqual(cata1, picker.Arguments.First().GetValueForParameterOfType(typeof(Catalogue))); + Assert.Multiple(() => + { + Assert.That(picker.HasArgumentOfType(0, typeof(Catalogue))); + Assert.That(picker.Arguments.First().GetValueForParameterOfType(typeof(Catalogue)), Is.EqualTo(cata1)); + }); // But when there are 2 objects we don't know which to pick so cannot pick a Catalogue new Catalogue(Repository, "Hey"); var picker2 = new CommandLineObjectPicker(new string[] { "Catalogue:Hey" }, GetActivator()); - Assert.IsFalse(picker2.HasArgumentOfType(0, typeof(Catalogue))); + Assert.That(picker2.HasArgumentOfType(0, typeof(Catalogue)), Is.False); } [Test] @@ -40,15 +43,21 @@ public void TwoCataloguesWithSameName_WithSession() // When there is only one object we can pick it by name var picker = new CommandLineObjectPicker(new string[] { "Catalogue:Hey" }, GetActivator()); - Assert.IsTrue(picker.HasArgumentOfType(0, typeof(Catalogue))); - Assert.AreEqual(cata1, picker.Arguments.First().GetValueForParameterOfType(typeof(Catalogue))); + Assert.Multiple(() => + { + Assert.That(picker.HasArgumentOfType(0, typeof(Catalogue))); + Assert.That(picker.Arguments.First().GetValueForParameterOfType(typeof(Catalogue)), Is.EqualTo(cata1)); + }); // There are now 2 objects with the same name but because we are in a session we can pick the latest var cata2 = new Catalogue(Repository, "Hey"); var picker2 = new CommandLineObjectPicker(new string[] { "Catalogue:Hey" }, GetActivator()); - Assert.IsTrue(picker2.HasArgumentOfType(0, typeof(Catalogue))); - Assert.AreEqual(cata2, picker2.Arguments.First().GetValueForParameterOfType(typeof(Catalogue))); + Assert.Multiple(() => + { + Assert.That(picker2.HasArgumentOfType(0, typeof(Catalogue))); + Assert.That(picker2.Arguments.First().GetValueForParameterOfType(typeof(Catalogue)), Is.EqualTo(cata2)); + }); } } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandLine/PickTableTests.cs b/Rdmp.Core.Tests/CommandLine/PickTableTests.cs index 3b424bf03e..90c338e4bf 100644 --- a/Rdmp.Core.Tests/CommandLine/PickTableTests.cs +++ b/Rdmp.Core.Tests/CommandLine/PickTableTests.cs @@ -23,16 +23,19 @@ public void TestPickTable() @"Table:v_cool:Schema:dbo:IsView:True:DatabaseType:MicrosoftSQLServer:Name:MyDb:Server=localhost\sqlexpress;Trusted_Connection=True;", 0); - Assert.IsNotNull(result.Table); + Assert.That(result.Table, Is.Not.Null); - Assert.AreEqual(TableType.View, result.Table.TableType); - Assert.AreEqual("dbo", result.Table.Schema); + Assert.Multiple(() => + { + Assert.That(result.Table.TableType, Is.EqualTo(TableType.View)); + Assert.That(result.Table.Schema, Is.EqualTo("dbo")); - Assert.AreEqual("v_cool", result.Table.GetRuntimeName()); - Assert.AreEqual("MyDb", result.Table.Database.GetRuntimeName()); - Assert.AreEqual("localhost\\sqlexpress", result.Table.Database.Server.Name); - Assert.AreEqual(DatabaseType.MicrosoftSQLServer, result.Table.Database.Server.DatabaseType); - Assert.IsNull(result.Table.Database.Server.ExplicitPasswordIfAny); - Assert.IsNull(result.Table.Database.Server.ExplicitUsernameIfAny); + Assert.That(result.Table.GetRuntimeName(), Is.EqualTo("v_cool")); + Assert.That(result.Table.Database.GetRuntimeName(), Is.EqualTo("MyDb")); + Assert.That(result.Table.Database.Server.Name, Is.EqualTo("localhost\\sqlexpress")); + Assert.That(result.Table.Database.Server.DatabaseType, Is.EqualTo(DatabaseType.MicrosoftSQLServer)); + Assert.That(result.Table.Database.Server.ExplicitPasswordIfAny, Is.Null); + Assert.That(result.Table.Database.Server.ExplicitUsernameIfAny, Is.Null); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommandLine/RdmpScriptTests.cs b/Rdmp.Core.Tests/CommandLine/RdmpScriptTests.cs index ff58860664..c23dce3fb9 100644 --- a/Rdmp.Core.Tests/CommandLine/RdmpScriptTests.cs +++ b/Rdmp.Core.Tests/CommandLine/RdmpScriptTests.cs @@ -38,10 +38,13 @@ public void RdmpScript_NewObject_Catalogue(string command, string expectedName) var exitCode = runner.Run(RepositoryLocator, ThrowImmediatelyDataLoadEventListener.Quiet, ThrowImmediatelyCheckNotifier.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(0, exitCode); - Assert.AreEqual(1, RepositoryLocator.CatalogueRepository.GetAllObjects().Length); + Assert.Multiple(() => + { + Assert.That(exitCode, Is.EqualTo(0)); + Assert.That(RepositoryLocator.CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(1)); + }); - Assert.AreEqual(expectedName, RepositoryLocator.CatalogueRepository.GetAllObjects().Single().Name); + Assert.That(RepositoryLocator.CatalogueRepository.GetAllObjects().Single().Name, Is.EqualTo(expectedName)); } [TestCase("NewObject Catalogue 'fffff'", "NewObject CatalogueItem Catalogue:*fff* 'bbbb'", "bbbb")] @@ -70,11 +73,14 @@ public void RdmpScript_NewObject_CatalogueItem(string cataCommand, string cataIt var exitCode = runner.Run(RepositoryLocator, ThrowImmediatelyDataLoadEventListener.Quiet, ThrowImmediatelyCheckNotifier.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(0, exitCode); - Assert.AreEqual(1, RepositoryLocator.CatalogueRepository.GetAllObjects().Length); + Assert.Multiple(() => + { + Assert.That(exitCode, Is.EqualTo(0)); + Assert.That(RepositoryLocator.CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(1)); + }); var ci = RepositoryLocator.CatalogueRepository.GetAllObjects().Single().CatalogueItems.Single(); - Assert.AreEqual(expectedCataItemName, ci.Name); + Assert.That(ci.Name, Is.EqualTo(expectedCataItemName)); } [Test] @@ -82,18 +88,24 @@ public void Test_SplitCommandLine() { var vals = ExecuteCommandRunner.SplitCommandLine("NewObject CatalogueItem 'Catalogue:\"fff\"' 'bbbb'") .ToArray(); - Assert.AreEqual("NewObject", vals[0]); - Assert.AreEqual("CatalogueItem", vals[1]); - Assert.AreEqual("Catalogue:\"fff\"", vals[2]); - Assert.AreEqual("bbbb", vals[3]); + Assert.Multiple(() => + { + Assert.That(vals[0], Is.EqualTo("NewObject")); + Assert.That(vals[1], Is.EqualTo("CatalogueItem")); + Assert.That(vals[2], Is.EqualTo("Catalogue:\"fff\"")); + Assert.That(vals[3], Is.EqualTo("bbbb")); + }); } [Test] public void Test_SplitCommandLine_QuotesInStrings() { var vals = ExecuteCommandRunner.SplitCommandLine("NewObject CatalogueItem bb\"'bb'").ToArray(); - Assert.AreEqual("NewObject", vals[0]); - Assert.AreEqual("CatalogueItem", vals[1]); - Assert.AreEqual("bb\"'bb'", vals[2]); + Assert.Multiple(() => + { + Assert.That(vals[0], Is.EqualTo("NewObject")); + Assert.That(vals[1], Is.EqualTo("CatalogueItem")); + Assert.That(vals[2], Is.EqualTo("bb\"'bb'")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/CommentStoreTests.cs b/Rdmp.Core.Tests/CommentStoreTests.cs index 8c56debef5..e806765010 100644 --- a/Rdmp.Core.Tests/CommentStoreTests.cs +++ b/Rdmp.Core.Tests/CommentStoreTests.cs @@ -27,9 +27,9 @@ Does some stuff store.AddXmlDoc(doc.FirstChild); - Assert.AreEqual( - @"Does some stuff" - , store["WindowFactory"]); + Assert.That( +store["WindowFactory"], Is.EqualTo(@"Does some stuff" +)); } [Test] @@ -49,9 +49,9 @@ Does some stuff store.AddXmlDoc(doc.FirstChild); - Assert.AreEqual( - @"Does some stuff" - , store["WindowFactory"]); + Assert.That( +store["WindowFactory"], Is.EqualTo(@"Does some stuff" +)); } [Test] @@ -73,11 +73,11 @@ this is next para store.AddXmlDoc(doc.FirstChild); - Assert.AreEqual( - @"Does some stuff This is still one para + Assert.That( +store["WindowFactory"], Is.EqualTo(@"Does some stuff This is still one para this is next para" - , store["WindowFactory"]); +)); } @@ -97,10 +97,10 @@ public void Test_CommentStoreXmlDoc_EmptyElements() //also shouldn't bomb but should be 0 store.AddXmlDoc(doc.FirstChild.FirstChild); - Assert.IsEmpty(store); + Assert.That(store, Is.Empty); store.AddXmlDoc(doc.FirstChild); - Assert.IsEmpty(store); + Assert.That(store, Is.Empty); doc.LoadXml( @" @@ -108,7 +108,7 @@ public void Test_CommentStoreXmlDoc_EmptyElements() "); store.AddXmlDoc(doc.FirstChild); - Assert.IsEmpty(store); + Assert.That(store, Is.Empty); doc.LoadXml( @@ -117,7 +117,7 @@ public void Test_CommentStoreXmlDoc_EmptyElements() "); store.AddXmlDoc(doc.FirstChild); - Assert.IsNotEmpty(store); + Assert.That(store, Is.Not.Empty); } @@ -142,11 +142,11 @@ this is next para store.AddXmlDoc(doc.FirstChild); - Assert.AreEqual( - @"Does some stuff This is still one para + Assert.That( +store["WindowFactory"], Is.EqualTo(@"Does some stuff This is still one para this is next para" - , store["WindowFactory"]); +)); } @@ -172,10 +172,10 @@ got it? store.AddXmlDoc(doc.FirstChild); - Assert.AreEqual( - @"Does some stuff And some more stuff IObjectCollectionControl (for RDMPCollectionUI see WindowManager ). + Assert.That( +store["WindowFactory"], Is.EqualTo(@"Does some stuff And some more stuff IObjectCollectionControl (for RDMPCollectionUI see WindowManager ). paragraph 2 got it?" - , store["WindowFactory"]); +)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Anonymisation/ANOMigrationTests.cs b/Rdmp.Core.Tests/Curation/Anonymisation/ANOMigrationTests.cs index 3e6a2855b7..4983d223c3 100644 --- a/Rdmp.Core.Tests/Curation/Anonymisation/ANOMigrationTests.cs +++ b/Rdmp.Core.Tests/Curation/Anonymisation/ANOMigrationTests.cs @@ -116,9 +116,12 @@ private void DeleteANOEndpoint() [Order(1)] public void PKsAreCorrect() { - Assert.IsTrue(_columnInfos.Single(c => c.GetRuntimeName().Equals("AdmissionDate")).IsPrimaryKey); - Assert.IsTrue(_columnInfos.Single(c => c.GetRuntimeName().Equals("Condition1")).IsPrimaryKey); - Assert.IsTrue(_columnInfos.Single(c => c.GetRuntimeName().Equals("CHI")).IsPrimaryKey); + Assert.Multiple(() => + { + Assert.That(_columnInfos.Single(c => c.GetRuntimeName().Equals("AdmissionDate")).IsPrimaryKey); + Assert.That(_columnInfos.Single(c => c.GetRuntimeName().Equals("Condition1")).IsPrimaryKey); + Assert.That(_columnInfos.Single(c => c.GetRuntimeName().Equals("CHI")).IsPrimaryKey); + }); } [Test] @@ -132,9 +135,8 @@ public void ConvertPrimaryKeyColumn() converter.ConvertFullColumnInfo(s => true, ThrowImmediatelyCheckNotifier.Quiet)); //say yes to everything it proposes - StringAssert.IsMatch( - @"Could not perform transformation because column \[(.*)\]\.\[dbo\]\.\[.*\]\.\[Condition1\] is not droppable", - ex.Message); + Assert.That( + ex.Message, Does.Match(@"Could not perform transformation because column \[(.*)\]\.\[dbo\]\.\[.*\]\.\[Condition1\] is not droppable")); } diff --git a/Rdmp.Core.Tests/Curation/Anonymisation/ANOStoreFunctionalityTests.cs b/Rdmp.Core.Tests/Curation/Anonymisation/ANOStoreFunctionalityTests.cs index f88acb705e..420289a77a 100644 --- a/Rdmp.Core.Tests/Curation/Anonymisation/ANOStoreFunctionalityTests.cs +++ b/Rdmp.Core.Tests/Curation/Anonymisation/ANOStoreFunctionalityTests.cs @@ -24,7 +24,7 @@ public void CanAccessANODatabase_Directly() var cmd = server.GetCommand("Select version from RoundhousE.Version", con); var version = new Version(cmd.ExecuteScalar().ToString()); - Assert.GreaterOrEqual(version, new Version("0.0.0.0")); + Assert.That(version, Is.GreaterThanOrEqualTo(new Version("0.0.0.0"))); con.Close(); } @@ -40,7 +40,7 @@ public void CanAccessANODatabase_ViaExternalServerPointer() DatabaseCommandHelper.GetCommand("Select version from RoundhousE.Version", connection)) { var version = new Version(cmd.ExecuteScalar().ToString()); - Assert.GreaterOrEqual(version, new Version("0.0.0.0")); + Assert.That(version, Is.GreaterThanOrEqualTo(new Version("0.0.0.0"))); } connection.Close(); @@ -55,7 +55,7 @@ public void CanAccessIdentifierDumpDatabase_Directly() var cmd = IdentifierDump_Database.Server.GetCommand("Select version from RoundhousE.Version", con); var version = new Version(cmd.ExecuteScalar().ToString()); - Assert.GreaterOrEqual(version, new Version("0.0.0.0")); + Assert.That(version, Is.GreaterThanOrEqualTo(new Version("0.0.0.0"))); con.Close(); } @@ -70,7 +70,7 @@ public void CanAccessIdentifierDumpDatabase_ViaExternalServerPointer() using (var cmd = DatabaseCommandHelper.GetCommand("Select version from RoundhousE.Version", connection)) { var version = new Version(cmd.ExecuteScalar().ToString()); - Assert.GreaterOrEqual(version, new Version("0.0.0.0")); + Assert.That(version, Is.GreaterThanOrEqualTo(new Version("0.0.0.0"))); } diff --git a/Rdmp.Core.Tests/Curation/Anonymisation/ANOTableTests.cs b/Rdmp.Core.Tests/Curation/Anonymisation/ANOTableTests.cs index 09fd40ac5f..6715308ee3 100644 --- a/Rdmp.Core.Tests/Curation/Anonymisation/ANOTableTests.cs +++ b/Rdmp.Core.Tests/Curation/Anonymisation/ANOTableTests.cs @@ -34,7 +34,7 @@ public class ANOTableTests : TestsRequiringANOStore public void CreateAnANOTable_PushAs(string datatypeForPush) { var anoTable = GetANOTable(); - Assert.AreEqual("ANOMyTable", anoTable.TableName); + Assert.That(anoTable.TableName, Is.EqualTo("ANOMyTable")); anoTable.NumberOfCharactersToUseInAnonymousRepresentation = 20; anoTable.NumberOfIntegersToUseInAnonymousRepresentation = 20; anoTable.PushToANOServerAsNewTable(datatypeForPush, ThrowImmediatelyCheckNotifier.Quiet); @@ -43,14 +43,17 @@ public void CreateAnANOTable_PushAs(string datatypeForPush) .SingleOrDefault(t => t.GetRuntimeName().Equals("ANOMyTable")); //server should have - Assert.NotNull(discoveredTable); - Assert.IsTrue(discoveredTable.Exists()); + Assert.That(discoveredTable, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(discoveredTable.Exists()); - //yes that's right hte table name and column name are the same here \|/ - Assert.AreEqual(datatypeForPush, discoveredTable.DiscoverColumn("MyTable").DataType.SQLType); + //yes that's right hte table name and column name are the same here \|/ + Assert.That(discoveredTable.DiscoverColumn("MyTable").DataType.SQLType, Is.EqualTo(datatypeForPush)); - //20 + 20 + _ + A - Assert.AreEqual("varchar(42)", discoveredTable.DiscoverColumn("ANOMyTable").DataType.SQLType); + //20 + 20 + _ + A + Assert.That(discoveredTable.DiscoverColumn("ANOMyTable").DataType.SQLType, Is.EqualTo("varchar(42)")); + }); anoTable.DeleteInDatabase(); } @@ -62,7 +65,7 @@ public void CreateAnANOTable_Revertable() anoTable.NumberOfCharactersToUseInAnonymousRepresentation = 63; anoTable.RevertToDatabaseState(); - Assert.AreEqual(1, anoTable.NumberOfCharactersToUseInAnonymousRepresentation); + Assert.That(anoTable.NumberOfCharactersToUseInAnonymousRepresentation, Is.EqualTo(1)); anoTable.DeleteInDatabase(); } @@ -70,7 +73,7 @@ public void CreateAnANOTable_Revertable() public void CreateAnANOTable_Check() { var anoTable = GetANOTable(); - Assert.AreEqual("ANOMyTable", anoTable.TableName); + Assert.That(anoTable.TableName, Is.EqualTo("ANOMyTable")); anoTable.Check(new AcceptAllCheckNotifier()); anoTable.DeleteInDatabase(); } @@ -83,7 +86,7 @@ public void DuplicateSuffix_Throws() { var ex = Assert.Throws(() => new ANOTable(CatalogueRepository, anoTable.Server, "DuplicateSuffix", anoTable.Suffix)); - Assert.AreEqual("There is already another ANOTable with the suffix 'A'", ex.Message); + Assert.That(ex.Message, Is.EqualTo("There is already another ANOTable with the suffix 'A'")); } finally { @@ -99,7 +102,7 @@ public void CreateAnANOTable_CharCountNegative() { anoTable.NumberOfCharactersToUseInAnonymousRepresentation = -500; var ex = Assert.Throws(anoTable.SaveToDatabase); - Assert.AreEqual("NumberOfCharactersToUseInAnonymousRepresentation cannot be negative", ex.Message); + Assert.That(ex.Message, Is.EqualTo("NumberOfCharactersToUseInAnonymousRepresentation cannot be negative")); } finally { @@ -116,7 +119,7 @@ public void CreateAnANOTable_IntCountNegative() { anoTable.NumberOfIntegersToUseInAnonymousRepresentation = -500; var ex = Assert.Throws(anoTable.SaveToDatabase); - Assert.AreEqual("NumberOfIntegersToUseInAnonymousRepresentation cannot be negative", ex.Message); + Assert.That(ex.Message, Is.EqualTo("NumberOfIntegersToUseInAnonymousRepresentation cannot be negative")); } finally { @@ -133,7 +136,7 @@ public void CreateAnANOTable_TotalCountZero() anoTable.NumberOfIntegersToUseInAnonymousRepresentation = 0; anoTable.NumberOfCharactersToUseInAnonymousRepresentation = 0; var ex = Assert.Throws(anoTable.SaveToDatabase); - Assert.AreEqual("Anonymous representations must have at least 1 integer or character", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Anonymous representations must have at least 1 integer or character")); } finally { @@ -163,9 +166,12 @@ public void SubstituteANOIdentifiers_2CHINumbers() var transformer = new ANOTransformer(anoTable, ThrowImmediatelyDataLoadEventListener.Quiet); transformer.Transform(dt, dt.Columns["CHI"], dt.Columns["ANOCHI"]); - Assert.IsTrue((string)dt.Rows[0][0] == "0101010101"); - Assert.IsTrue(_anochiPattern.IsMatch((string)dt.Rows[0][1])); //should be 10 digits and then _A - Assert.AreEqual(dt.Rows[0][1], dt.Rows[2][1]); //because of duplication these should both be the same + Assert.Multiple(() => + { + Assert.That((string)dt.Rows[0][0], Is.EqualTo("0101010101")); + Assert.That(_anochiPattern.IsMatch((string)dt.Rows[0][1])); //should be 10 digits and then _A + Assert.That(dt.Rows[2][1], Is.EqualTo(dt.Rows[0][1])); //because of duplication these should both be the same + }); Console.WriteLine($"ANO identifiers created were:{dt.Rows[0][1]},{dt.Rows[1][1]}"); @@ -181,9 +187,12 @@ public void SubstituteANOIdentifiers_2CHINumbers() transformer.Transform(dt, dt.Columns["CHI"], dt.Columns["ANOCHI"], true); var val3 = dt.Rows[0][1]; - //should always be different - Assert.AreNotEqual(val1, val2); - Assert.AreNotEqual(val1, val3); + Assert.Multiple(() => + { + //should always be different + Assert.That(val2, Is.Not.EqualTo(val1)); + Assert.That(val3, Is.Not.EqualTo(val1)); + }); //now test repeatability transformer.Transform(dt, dt.Columns["CHI"], dt.Columns["ANOCHI"], false); @@ -194,8 +203,11 @@ public void SubstituteANOIdentifiers_2CHINumbers() transformer.Transform(dt, dt.Columns["CHI"], dt.Columns["ANOCHI"], false); var val6 = dt.Rows[0][1]; - Assert.AreEqual(val4, val5); - Assert.AreEqual(val4, val6); + Assert.Multiple(() => + { + Assert.That(val5, Is.EqualTo(val4)); + Assert.That(val6, Is.EqualTo(val4)); + }); TruncateANOTable(anoTable); @@ -212,7 +224,7 @@ public void SubstituteANOIdentifiers_PreviewWithoutPush() var ANOtable = ANOStore_Database.ExpectTable(anoTable.TableName); //should not exist yet - Assert.False(ANOtable.Exists()); + Assert.That(ANOtable.Exists(), Is.False); using var dt = new DataTable(); dt.Columns.Add("CHI"); @@ -221,10 +233,13 @@ public void SubstituteANOIdentifiers_PreviewWithoutPush() var transformer = new ANOTransformer(anoTable, ThrowImmediatelyDataLoadEventListener.Quiet); transformer.Transform(dt, dt.Columns["CHI"], dt.Columns["ANOCHI"], true); - Assert.IsTrue(_anochiPattern.IsMatch((string)dt.Rows[0][1])); //should be 10 digits and then _A + Assert.Multiple(() => + { + Assert.That(_anochiPattern.IsMatch((string)dt.Rows[0][1])); //should be 10 digits and then _A - //still not exist yet - Assert.False(ANOtable.Exists()); + //still not exist yet + Assert.That(ANOtable.Exists(), Is.False); + }); anoTable.DeleteInDatabase(); } @@ -287,7 +302,7 @@ public void SubstituteANOIdentifiers_BulkTest() var ANOid = row["ANOCHI"].ToString(); uniqueSet.Add(ANOid); - Assert.IsTrue(_anochiPattern.IsMatch(ANOid)); + Assert.That(_anochiPattern.IsMatch(ANOid)); } Console.WriteLine($"Allocated {uniqueSet.Count} anonymous identifiers"); @@ -302,12 +317,12 @@ public void SubstituteANOIdentifiers_BulkTest() var numberOfRows = Convert.ToInt32(cmd.ExecuteScalar()); //should be the same number of unique identifiers in memory as in the database - Assert.AreEqual(uniqueSet.Count, numberOfRows); + Assert.That(numberOfRows, Is.EqualTo(uniqueSet.Count)); Console.WriteLine($"Found {numberOfRows} unique ones"); var cmdNulls = server.GetCommand("select count(*) from ANOMyTable where ANOMyTable is null", con); var nulls = Convert.ToInt32(cmdNulls.ExecuteScalar()); - Assert.AreEqual(0, nulls); + Assert.That(nulls, Is.EqualTo(0)); Console.WriteLine($"Found {nulls} null ANO identifiers"); con.Close(); diff --git a/Rdmp.Core.Tests/Curation/Anonymisation/ForwardEngineerANOCatalogueTwoTableTests.cs b/Rdmp.Core.Tests/Curation/Anonymisation/ForwardEngineerANOCatalogueTwoTableTests.cs index 131e06b861..07fc9d45d5 100644 --- a/Rdmp.Core.Tests/Curation/Anonymisation/ForwardEngineerANOCatalogueTwoTableTests.cs +++ b/Rdmp.Core.Tests/Curation/Anonymisation/ForwardEngineerANOCatalogueTwoTableTests.cs @@ -155,7 +155,7 @@ public void TestAnonymisingJoinKey() engine1.NewCatalogue.GetAllExtractionInformation(ExtractionCategory.Any); var ei1 = plan1ExtractionInformationsAtDestination.Single(e => e.GetRuntimeName().Equals("ANOTestId")); - Assert.IsTrue(ei1.Exists()); + Assert.That(ei1.Exists()); //Now create a plan for the combo Catalogue which contains references to both tables (Tests and Results). Remember Tests has already been migrated as part of plan1 var plan2 = new ForwardEngineerANOCataloguePlanManager(RepositoryLocator, _comboCata); @@ -174,7 +174,7 @@ public void TestAnonymisingJoinKey() engine2.NewCatalogue.GetAllExtractionInformation(ExtractionCategory.Any); var ei2 = plan2ExtractionInformationsAtDestination.Single(e => e.GetRuntimeName().Equals("ANOTestId")); - Assert.IsTrue(ei2.Exists()); + Assert.That(ei2.Exists()); //and can the query be executed successfully var qb = new QueryBuilder(null, null); @@ -191,8 +191,11 @@ public void TestAnonymisingJoinKey() Console.WriteLine($"Final migrated combo dataset SQL was:{qb.SQL}"); - Assert.IsTrue(_comboCata.CatalogueItems.Any(ci => ci.Name.Equals("Measuree"))); - Assert.IsTrue(engine2.NewCatalogue.CatalogueItems.Any(ci => ci.Name.Equals("Measuree")), - "ANO Catalogue did not respect the original CatalogueItem Name"); + Assert.Multiple(() => + { + Assert.That(_comboCata.CatalogueItems.Any(ci => ci.Name.Equals("Measuree"))); + Assert.That(engine2.NewCatalogue.CatalogueItems.Any(ci => ci.Name.Equals("Measuree")), + "ANO Catalogue did not respect the original CatalogueItem Name"); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Anonymisation/IdentifierDumpFunctionalityTests.cs b/Rdmp.Core.Tests/Curation/Anonymisation/IdentifierDumpFunctionalityTests.cs index 4ea7992673..ed17f7e23b 100644 --- a/Rdmp.Core.Tests/Curation/Anonymisation/IdentifierDumpFunctionalityTests.cs +++ b/Rdmp.Core.Tests/Curation/Anonymisation/IdentifierDumpFunctionalityTests.cs @@ -46,12 +46,12 @@ protected override void OneTimeSetUp() Console.WriteLine( $"Imported ColumnInfos {string.Join(",", columnInfosCreated.Select(c => c.GetRuntimeName()))}"); - Assert.NotNull(tableInfoCreated); + Assert.That(tableInfoCreated, Is.Not.Null); var chi = columnInfosCreated.Single(c => c.GetRuntimeName().Equals("chi")); Console.WriteLine($"CHI is primary key? (expecting true):{chi.IsPrimaryKey}"); - Assert.IsTrue(chi.IsPrimaryKey); + Assert.That(chi.IsPrimaryKey); tableInfoCreated.ColumnInfos.Single(c => c.GetRuntimeName().Equals("surname")).DeleteInDatabase(); @@ -85,8 +85,11 @@ public void DumpAllIdentifiersInTable_Passes() var dt = _bulkData.GetDataTable(1000); - Assert.AreEqual(1000, dt.Rows.Count); - Assert.IsTrue(dt.Columns.Contains("surname")); + Assert.Multiple(() => + { + Assert.That(dt.Rows, Has.Count.EqualTo(1000)); + Assert.That(dt.Columns.Contains("surname")); + }); //for checking the final ID table has the correct values in foreach (DataRow row in dt.Rows) @@ -104,7 +107,7 @@ public void DumpAllIdentifiersInTable_Passes() dumper.DropStaging(); //confirm that the surname column is no longer in the pipeline - Assert.IsFalse(dt.Columns.Contains("surname")); + Assert.That(dt.Columns.Contains("surname"), Is.False); //now look at the ids in the identifier dump and make sure they match what was in the pipeline before we sent it var server = IdentifierDump_Database.Server; @@ -117,9 +120,9 @@ public void DumpAllIdentifiersInTable_Passes() //make sure the values in the ID table match the ones we originally had in the pipeline while (r.Read()) if (!chiToSurnameDictionary[r["chi"].ToString()].Any()) - Assert.IsTrue(r["surname"] == DBNull.Value); + Assert.That(r["surname"], Is.EqualTo(DBNull.Value)); else - Assert.IsTrue(chiToSurnameDictionary[r["chi"].ToString()].Contains(r["surname"] as string), + Assert.That(chiToSurnameDictionary[r["chi"].ToString()], Does.Contain(r["surname"] as string), "Dictionary did not contain expected surname:" + r["surname"]); r.Close(); @@ -172,15 +175,15 @@ public void DumpAllIdentifiersInTable_UnexpectedColumnFoundInIdentifierDumpTable dumper.Check(new AcceptAllCheckNotifier()); var tableInDump = IdentifierDump_Database.ExpectTable($"ID_{BulkTestsData.BulkDataTable}"); - Assert.IsTrue(tableInDump.Exists(), "ID table did not exist"); + Assert.That(tableInDump.Exists(), "ID table did not exist"); var columnsInDump = tableInDump.DiscoverColumns().Select(c => c.GetRuntimeName()).ToArray(); //works and creates table on server - Assert.Contains("hic_validFrom", columnsInDump); - Assert.Contains("forename", columnsInDump); - Assert.Contains("chi", columnsInDump); - Assert.Contains("surname", columnsInDump); + Assert.That(columnsInDump, Does.Contain("hic_validFrom")); + Assert.That(columnsInDump, Does.Contain("forename")); + Assert.That(columnsInDump, Does.Contain("chi")); + Assert.That(columnsInDump, Does.Contain("surname")); //now delete it! preDiscardedColumn2.DeleteInDatabase(); @@ -191,9 +194,8 @@ public void DumpAllIdentifiersInTable_UnexpectedColumnFoundInIdentifierDumpTable try { var ex = Assert.Throws(() => dumper2.Check(ThrowImmediatelyCheckNotifier.QuietPicky)); - Assert.AreEqual( - "Column forename was found in the IdentifierDump table ID_BulkData but was not one of the primary keys or a PreLoadDiscardedColumn", - ex?.Message); + Assert.That( + ex?.Message, Is.EqualTo("Column forename was found in the IdentifierDump table ID_BulkData but was not one of the primary keys or a PreLoadDiscardedColumn")); } finally { @@ -236,9 +238,8 @@ public void IdentifierDumperCheckFails_StagingNotCalled() { dumper.Check(new AcceptAllCheckNotifier()); var ex = Assert.Throws(() => dumper.DumpAllIdentifiersInTable(_bulkData.GetDataTable(10))); - Assert.AreEqual( - "IdentifierDumper STAGING insert (ID_BulkData_STAGING) failed, make sure you have called CreateSTAGINGTable() before trying to Dump identifiers (also you should call DropStaging() when you are done)", - ex?.Message); + Assert.That( + ex?.Message, Is.EqualTo("IdentifierDumper STAGING insert (ID_BulkData_STAGING) failed, make sure you have called CreateSTAGINGTable() before trying to Dump identifiers (also you should call DropStaging() when you are done)")); } finally { @@ -276,7 +277,7 @@ public void IdentifierDumperCheckFails_NoTableExists() var notifier = new ToMemoryCheckNotifier(new AcceptAllCheckNotifier()); dumper.Check(notifier); - Assert.IsTrue(notifier.Messages.Any(m => + Assert.That(notifier.Messages.Any(m => m.Result == CheckResult.Warning && m.Message.Contains("Table ID_BulkData was not found"))); @@ -312,12 +313,14 @@ public void IdentifierDumperCheckFails_ServerIsNotADumpServer() } catch (Exception ex) { - Assert.IsTrue( - ex.Message.StartsWith( - "Exception occurred when trying to find stored procedure sp_createIdentifierDump")); - Assert.IsTrue(ex.InnerException?.Message.StartsWith("Connected successfully to server")); - Assert.IsTrue(ex.InnerException?.Message.EndsWith( - " but did not find the stored procedure sp_createIdentifierDump in the database (Possibly the ExternalDatabaseServer is not an IdentifierDump database?)")); + Assert.Multiple(() => + { + Assert.That( + ex.Message, Does.StartWith("Exception occurred when trying to find stored procedure sp_createIdentifierDump")); + Assert.That(ex.InnerException?.Message.StartsWith("Connected successfully to server", StringComparison.Ordinal), Is.EqualTo(true)); + Assert.That(ex.InnerException?.Message.EndsWith( + " but did not find the stored procedure sp_createIdentifierDump in the database (Possibly the ExternalDatabaseServer is not an IdentifierDump database?)", StringComparison.Ordinal), Is.EqualTo(true)); + }); } finally { @@ -339,7 +342,7 @@ public void IdentifierDumperCheckFails_NoTableOnServerRejectChange() preDiscardedColumn1.SaveToDatabase(); var ex = Assert.Throws(() => new IdentifierDumper(tableInfoCreated)); - StringAssert.Contains("does not have a listed IdentifierDump ExternalDatabaseServer", ex.Message); + Assert.That(ex.Message, Does.Contain("does not have a listed IdentifierDump ExternalDatabaseServer")); } finally { @@ -364,7 +367,7 @@ public void IdentifierDumperCheckFails_LieAboutDatatype() var dumper = new IdentifierDumper(tableInfoCreated); - //table doesnt exist yet it should work + //table doesn't exist yet it should work dumper.Check(new AcceptAllCheckNotifier()); //now it is varbinary @@ -373,11 +376,10 @@ public void IdentifierDumperCheckFails_LieAboutDatatype() //get a new dumper because we have changed the pre load discarded column dumper = new IdentifierDumper(tableInfoCreated); - //table doesnt exist yet it should work + //table doesn't exist yet it should work var ex = Assert.Throws(() => dumper.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.IsTrue(ex?.Message.Contains( - "has data type varbinary(200) in the Catalogue but appears as varchar(50) in the actual IdentifierDump")); + Assert.That(ex?.Message, Does.Contain("has data type varbinary(200) in the Catalogue but appears as varchar(50) in the actual IdentifierDump")); } finally { diff --git a/Rdmp.Core.Tests/Curation/CrossPlatformParameterTests/BasicParameterUseTests.cs b/Rdmp.Core.Tests/Curation/CrossPlatformParameterTests/BasicParameterUseTests.cs index 61c8193197..f95b4612ca 100644 --- a/Rdmp.Core.Tests/Curation/CrossPlatformParameterTests/BasicParameterUseTests.cs +++ b/Rdmp.Core.Tests/Curation/CrossPlatformParameterTests/BasicParameterUseTests.cs @@ -74,7 +74,7 @@ public void Test_DatabaseTypeQueryWithParameter_IntParameter(DatabaseType dbType new ParameterCreator(filter.GetFilterFactory(), null, null).CreateAll(filter, null); var p = filter.GetAllParameters().Single(); - Assert.AreEqual("@n", p.ParameterName); + Assert.That(p.ParameterName, Is.EqualTo("@n")); p.ParameterSQL = p.ParameterSQL.Replace("varchar(50)", "int"); //make it int p.Value = "20"; p.SaveToDatabase(); @@ -91,10 +91,12 @@ public void Test_DatabaseTypeQueryWithParameter_IntParameter(DatabaseType dbType var cmd = db.Server.GetCommand(sql, con); var r = cmd.ExecuteReader(); - Assert.IsTrue(r.Read()); - Assert.AreEqual( - 20, - r[extractionInformation.GetRuntimeName()]); + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That( + r[extractionInformation.GetRuntimeName()], Is.EqualTo(20)); + }); /////////////////////////////////////////////////////////////////////////////////////// } finally diff --git a/Rdmp.Core.Tests/Curation/DublinCoreTests.cs b/Rdmp.Core.Tests/Curation/DublinCoreTests.cs index 1051964909..8a8b31df01 100644 --- a/Rdmp.Core.Tests/Curation/DublinCoreTests.cs +++ b/Rdmp.Core.Tests/Curation/DublinCoreTests.cs @@ -40,30 +40,33 @@ public void TestWritingDocument() } var contents = File.ReadAllText(f.FullName); - StringAssert.Contains(def.Title, contents); - StringAssert.Contains(def.Alternative, contents); - StringAssert.Contains(def.Description, contents); - StringAssert.Contains(def.Format, contents); - StringAssert.Contains(def.Publisher, contents); - StringAssert.Contains(def.Subject, contents); + Assert.That(contents, Does.Contain(def.Title)); + Assert.That(contents, Does.Contain(def.Alternative)); + Assert.That(contents, Does.Contain(def.Description)); + Assert.That(contents, Does.Contain(def.Format)); + Assert.That(contents, Does.Contain(def.Publisher)); + Assert.That(contents, Does.Contain(def.Subject)); - StringAssert.Contains("2001-01-01", contents); - StringAssert.Contains("http://foo.com", contents); - StringAssert.Contains("http://foo2.com", contents); + Assert.That(contents, Does.Contain("2001-01-01")); + Assert.That(contents, Does.Contain("http://foo.com")); + Assert.That(contents, Does.Contain("http://foo2.com")); var def2 = new DublinCoreDefinition(); def2.LoadFrom(XDocument.Load(f.FullName).Root); - Assert.AreEqual(def.Title, def2.Title); - Assert.AreEqual(def.Alternative, def2.Alternative); - Assert.AreEqual(def.Description, def2.Description); - Assert.AreEqual(def.Format, def2.Format); - Assert.AreEqual(def.Publisher, def2.Publisher); - Assert.AreEqual(def.Subject, def2.Subject); - - Assert.AreEqual(def.Modified, def2.Modified); - Assert.AreEqual(def.IsPartOf.ToString(), def2.IsPartOf.ToString()); - Assert.AreEqual(def.Identifier.ToString(), def2.Identifier.ToString()); + Assert.Multiple(() => + { + Assert.That(def2.Title, Is.EqualTo(def.Title)); + Assert.That(def2.Alternative, Is.EqualTo(def.Alternative)); + Assert.That(def2.Description, Is.EqualTo(def.Description)); + Assert.That(def2.Format, Is.EqualTo(def.Format)); + Assert.That(def2.Publisher, Is.EqualTo(def.Publisher)); + Assert.That(def2.Subject, Is.EqualTo(def.Subject)); + + Assert.That(def2.Modified, Is.EqualTo(def.Modified)); + Assert.That(def2.IsPartOf.ToString(), Is.EqualTo(def.IsPartOf.ToString())); + Assert.That(def2.Identifier.ToString(), Is.EqualTo(def.Identifier.ToString())); + }); } [Test] @@ -133,24 +136,27 @@ UKOLN est un centre national d'expertise dans la gestion de l'information def.LoadFrom(doc.Root); - Assert.IsTrue(DatabaseTests.AreBasicallyEquals("UKOLN", def.Title)); - Assert.IsTrue(DatabaseTests.AreBasicallyEquals("UK Office for Library and Information Networking", - def.Alternative)); - Assert.IsTrue(DatabaseTests.AreBasicallyEquals(@"national centre, network information support, library + Assert.Multiple(() => + { + Assert.That(DatabaseTests.AreBasicallyEquals("UKOLN", def.Title)); + Assert.That(DatabaseTests.AreBasicallyEquals("UK Office for Library and Information Networking", + def.Alternative)); + Assert.That(DatabaseTests.AreBasicallyEquals(@"national centre, network information support, library community, awareness, research, information services,public library networking, bibliographic management, distributed library systems, metadata, resource discovery, conferences,lectures, workshops", def.Subject)); - Assert.IsTrue(DatabaseTests.AreBasicallyEquals(@"UKOLN is a national focus of expertise in digital information + Assert.That(DatabaseTests.AreBasicallyEquals(@"UKOLN is a national focus of expertise in digital information management. It provides policy, research and awareness services to the UK library, information and cultural heritage communities. UKOLN is based at the University of Bath.", def.Description)); - Assert.IsTrue(DatabaseTests.AreBasicallyEquals("UKOLN, University of Bath", def.Publisher)); - StringAssert.AreEqualIgnoringCase("http://www.bath.ac.uk/", def.IsPartOf.AbsoluteUri); - StringAssert.AreEqualIgnoringCase("http://www.ukoln.ac.uk/", def.Identifier.AbsoluteUri); - Assert.IsTrue(DatabaseTests.AreBasicallyEquals(new DateTime(2001, 07, 18), def.Modified)); + Assert.That(DatabaseTests.AreBasicallyEquals("UKOLN, University of Bath", def.Publisher)); + Assert.That(def.IsPartOf.AbsoluteUri, Is.EqualTo("http://www.bath.ac.uk/").IgnoreCase); + Assert.That(def.Identifier.AbsoluteUri, Is.EqualTo("http://www.ukoln.ac.uk/").IgnoreCase); + Assert.That(DatabaseTests.AreBasicallyEquals(new DateTime(2001, 07, 18), def.Modified)); + }); } /// diff --git a/Rdmp.Core.Tests/Curation/ExtendedPropertyTests.cs b/Rdmp.Core.Tests/Curation/ExtendedPropertyTests.cs index b710ccbdd6..9b086e4b3b 100644 --- a/Rdmp.Core.Tests/Curation/ExtendedPropertyTests.cs +++ b/Rdmp.Core.Tests/Curation/ExtendedPropertyTests.cs @@ -18,22 +18,34 @@ public void ExtendedProperty_Catalogue() var cata = new Catalogue(CatalogueRepository, "My cata"); var prop = new ExtendedProperty(CatalogueRepository, cata, "Fish", 5); - Assert.AreEqual(5, prop.GetValueAsSystemType()); - Assert.IsTrue(prop.IsReferenceTo(cata)); + Assert.Multiple(() => + { + Assert.That(prop.GetValueAsSystemType(), Is.EqualTo(5)); + Assert.That(prop.IsReferenceTo(cata)); + }); prop.SetValue(10); prop.SaveToDatabase(); - Assert.AreEqual(10, prop.GetValueAsSystemType()); - Assert.IsTrue(prop.IsReferenceTo(cata)); + Assert.Multiple(() => + { + Assert.That(prop.GetValueAsSystemType(), Is.EqualTo(10)); + Assert.That(prop.IsReferenceTo(cata)); + }); prop.RevertToDatabaseState(); - Assert.AreEqual(10, prop.GetValueAsSystemType()); - Assert.IsTrue(prop.IsReferenceTo(cata)); + Assert.Multiple(() => + { + Assert.That(prop.GetValueAsSystemType(), Is.EqualTo(10)); + Assert.That(prop.IsReferenceTo(cata)); + }); var prop2 = CatalogueRepository.GetObjectByID(prop.ID); - Assert.AreEqual(10, prop.GetValueAsSystemType()); - Assert.IsTrue(prop.IsReferenceTo(cata)); + Assert.Multiple(() => + { + Assert.That(prop.GetValueAsSystemType(), Is.EqualTo(10)); + Assert.That(prop.IsReferenceTo(cata)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/ImportTests/GatherAndShareTests.cs b/Rdmp.Core.Tests/Curation/ImportTests/GatherAndShareTests.cs index a8ec16f1cf..13baabc4c2 100644 --- a/Rdmp.Core.Tests/Curation/ImportTests/GatherAndShareTests.cs +++ b/Rdmp.Core.Tests/Curation/ImportTests/GatherAndShareTests.cs @@ -6,10 +6,8 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using NUnit.Framework; -using Rdmp.Core.CommandLine.Runners; using Rdmp.Core.Curation.Data; using Rdmp.Core.Curation.Data.DataLoad; using Rdmp.Core.Curation.Data.ImportExport; @@ -33,7 +31,7 @@ public void Test_SerializeObject_ShareAttribute() var obj = (Dictionary)JsonConvertExtensions.DeserializeObject(json, typeof(Dictionary), RepositoryLocator); - Assert.AreEqual(0, obj.Count); + Assert.That(obj, Is.Empty); //now add a key d.Add(new RelationshipAttribute(typeof(string), RelationshipType.SharedObject, "fff"), Guid.Empty); @@ -42,7 +40,7 @@ public void Test_SerializeObject_ShareAttribute() obj = (Dictionary)JsonConvertExtensions.DeserializeObject(json, typeof(Dictionary), RepositoryLocator); - Assert.AreEqual(1, obj.Count); + Assert.That(obj, Has.Count.EqualTo(1)); } [TestCase(true)] @@ -53,16 +51,19 @@ public void GatherAndShare_ANOTable_Test(bool goViaJson) new ExternalDatabaseServer(CatalogueRepository, "MyGatherAndShareTestANOServer", new ANOStorePatcher()); var anoTable = new ANOTable(CatalogueRepository, anoserver, "ANOMagad", "N"); - Assert.AreEqual(anoTable.Server_ID, anoserver.ID); + Assert.That(anoserver.ID, Is.EqualTo(anoTable.Server_ID)); var g = new Gatherer(RepositoryLocator); - Assert.IsTrue(g.CanGatherDependencies(anoTable)); + Assert.That(g.CanGatherDependencies(anoTable)); var gObj = Gatherer.GatherDependencies(anoTable); - //root should be the server - Assert.AreEqual(gObj.Object, anoserver); - Assert.AreEqual(gObj.Children.Single().Object, anoTable); + Assert.Multiple(() => + { + //root should be the server + Assert.That(anoserver, Is.EqualTo(gObj.Object)); + Assert.That(anoTable, Is.EqualTo(gObj.Children.Single().Object)); + }); //get the sharing definitions var shareManager = new ShareManager(RepositoryLocator); @@ -89,40 +90,48 @@ public void GatherAndShare_ANOTable_Test(bool goViaJson) var anoserverAfter = new ExternalDatabaseServer(shareManager, defParent); - Assert.IsTrue(anoserverAfter.Exists()); + Assert.Multiple(() => + { + Assert.That(anoserverAfter.Exists()); - //new instance - Assert.AreNotEqual(anoserverAfter.ID, anoserver.ID); + //new instance + Assert.That(anoserver.ID, Is.Not.EqualTo(anoserverAfter.ID)); - //same properties - Assert.AreEqual(anoserverAfter.Name, anoserver.Name); - Assert.AreEqual(anoserverAfter.CreatedByAssembly, anoserver.CreatedByAssembly); - Assert.AreEqual(anoserverAfter.Database, anoserver.Database); - Assert.AreEqual(anoserverAfter.DatabaseType, anoserver.DatabaseType); - Assert.AreEqual(anoserverAfter.Username, anoserver.Username); - Assert.AreEqual(anoserverAfter.Password, anoserver.Password); + //same properties + Assert.That(anoserver.Name, Is.EqualTo(anoserverAfter.Name)); + Assert.That(anoserver.CreatedByAssembly, Is.EqualTo(anoserverAfter.CreatedByAssembly)); + Assert.That(anoserver.Database, Is.EqualTo(anoserverAfter.Database)); + Assert.That(anoserver.DatabaseType, Is.EqualTo(anoserverAfter.DatabaseType)); + Assert.That(anoserver.Username, Is.EqualTo(anoserverAfter.Username)); + Assert.That(anoserver.Password, Is.EqualTo(anoserverAfter.Password)); + }); var anoTableAfter = new ANOTable(shareManager, defChild); - //new instance - Assert.AreNotEqual(anoTableAfter.ID, anoTable.ID); - Assert.AreNotEqual(anoTableAfter.Server_ID, anoTable.Server_ID); + Assert.Multiple(() => + { + //new instance + Assert.That(anoTable.ID, Is.Not.EqualTo(anoTableAfter.ID)); + Assert.That(anoTable.Server_ID, Is.Not.EqualTo(anoTableAfter.Server_ID)); - //same properties - Assert.AreEqual(anoTableAfter.NumberOfCharactersToUseInAnonymousRepresentation, - anoTable.NumberOfCharactersToUseInAnonymousRepresentation); - Assert.AreEqual(anoTableAfter.Suffix, anoTable.Suffix); + //same properties + Assert.That(anoTable.NumberOfCharactersToUseInAnonymousRepresentation, Is.EqualTo(anoTableAfter.NumberOfCharactersToUseInAnonymousRepresentation)); + Assert.That(anoTable.Suffix, Is.EqualTo(anoTableAfter.Suffix)); + }); //change a property and save it anoTableAfter.Suffix = "CAMMELS!"; CatalogueRepository.SaveToDatabase(anoTableAfter); - //anoTableAfter.SaveToDatabase(); <- this decides to go check the ANOTable exists on the server refernced which is immaginary btw >< thats why we have the above line instead + //anoTableAfter.SaveToDatabase(); <- this decides to go check the ANOTable exists on the server referenced which is imaginary btw >< that's why we have the above line instead - //reimport (this time it should be an update, we import the share definitions and it overrdies our database copy (sharing is UPSERT) + //reimport (this time it should be an update, we import the share definitions and it overrides our database copy (sharing is UPSERT) var anoTableAfter2 = new ANOTable(shareManager, defChild); - Assert.AreEqual(anoTableAfter.ID, anoTableAfter2.ID); - Assert.AreEqual("N", anoTableAfter2.Suffix); + Assert.Multiple(() => + { + Assert.That(anoTableAfter2.ID, Is.EqualTo(anoTableAfter.ID)); + Assert.That(anoTableAfter2.Suffix, Is.EqualTo("N")); + }); anoTableAfter.DeleteInDatabase(); anoserverAfter.DeleteInDatabase(); @@ -131,29 +140,6 @@ public void GatherAndShare_ANOTable_Test(bool goViaJson) o.DeleteInDatabase(); } - [Test] - public void GatherAndShare_Plugin_Test() - { - var f1 = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, - $"Imaginary1{PackPluginRunner.PluginPackageSuffix}")); - File.WriteAllBytes(f1.FullName, new byte[] { 0x1, 0x2 }); - - var plugin = new Plugin(CatalogueRepository, new FileInfo( - $"Imaginary{PackPluginRunner.PluginPackageSuffix}"), new Version(1, 1, 1), new Version(1, 1, 1)); - var lma1 = new LoadModuleAssembly(CatalogueRepository, f1, plugin); - - Assert.AreEqual(lma1.Plugin_ID, plugin.ID); - - var g = new Gatherer(RepositoryLocator); - Assert.IsTrue(g.CanGatherDependencies(plugin)); - - var gObj = Gatherer.GatherDependencies(plugin); - - //root should be the server - Assert.AreEqual(gObj.Object, plugin); - Assert.IsTrue(gObj.Children.Any(d => d.Object.Equals(lma1))); - } - [TestCase(true)] [TestCase(false)] @@ -178,15 +164,15 @@ public void GatherAndShare_Catalogue_Test(bool goViaJson) var ei = new ExtractionInformation(CatalogueRepository, catalogueItem1, colInfo, "UPPER(C1) as Fish"); //the logging server has a system default so should have been populated - Assert.IsNotNull(cata.LiveLoggingServer_ID); + Assert.That(cata.LiveLoggingServer_ID, Is.Not.Null); //Catalogue sharing should be allowed var g = new Gatherer(RepositoryLocator); - Assert.IsTrue(g.CanGatherDependencies(cata)); + Assert.That(g.CanGatherDependencies(cata)); //gather the objects depending on Catalogue as a tree var gObj = Gatherer.GatherDependencies(cata); - Assert.AreEqual(2, gObj.Children.Count); //both cata items + Assert.That(gObj.Children, Has.Count.EqualTo(2)); //both cata items var lmd = new LoadMetadata(CatalogueRepository); cata.LoadMetadata_ID = lmd.ID; @@ -222,10 +208,10 @@ public void GatherAndShare_Catalogue_Test(bool goViaJson) //revert the memory copy and check it got overwritten with the original saved values cata = CatalogueRepository.GetObjectByID(cata.ID); - Assert.AreEqual("Cata", cata.Name); + Assert.That(cata.Name, Is.EqualTo("Cata")); var exports = CatalogueRepository.GetAllObjects(); - Assert.IsTrue(exports.Any()); + Assert.That(exports.Any()); //now delete and report foreach (var d in exports) @@ -238,25 +224,34 @@ public void GatherAndShare_Catalogue_Test(bool goViaJson) //test importing the Catalogue properties only ShareManager.ImportPropertiesOnly(cata, shareDefinition[0]); - //import the defined properties but not name - Assert.AreEqual("fishfish", cata.Name); - Assert.AreEqual(Catalogue.CataloguePeriodicity.BiMonthly, cata.Periodicity); //reset this though - Assert.IsNull(cata.LoadMetadata_ID); + Assert.Multiple(() => + { + //import the defined properties but not name + Assert.That(cata.Name, Is.EqualTo("fishfish")); + Assert.That(cata.Periodicity, Is.EqualTo(Catalogue.CataloguePeriodicity.BiMonthly)); //reset this though + Assert.That(cata.LoadMetadata_ID, Is.Null); + }); cata.SaveToDatabase(); cata.DeleteInDatabase(); - //none of these should now exist thanks to cascade deletes - Assert.IsFalse(cata.Exists()); - Assert.IsFalse(catalogueItem1.Exists()); - Assert.IsFalse(catalogueItem2.Exists()); + Assert.Multiple(() => + { + //none of these should now exist thanks to cascade deletes + Assert.That(cata.Exists(), Is.False); + Assert.That(catalogueItem1.Exists(), Is.False); + Assert.That(catalogueItem2.Exists(), Is.False); + }); //import the saved copy var newObjects = shareManager.ImportSharedObject(shareDefinition).ToArray(); - Assert.AreEqual("Cata", ((Catalogue)newObjects[0]).Name); - Assert.AreEqual("Ci1", ((CatalogueItem)newObjects[1]).Name); - Assert.AreEqual("Ci2", ((CatalogueItem)newObjects[2]).Name); + Assert.Multiple(() => + { + Assert.That(((Catalogue)newObjects[0]).Name, Is.EqualTo("Cata")); + Assert.That(((CatalogueItem)newObjects[1]).Name, Is.EqualTo("Ci1")); + Assert.That(((CatalogueItem)newObjects[2]).Name, Is.EqualTo("Ci2")); + }); } [Test] @@ -301,12 +296,12 @@ public void GatherAndShare_ExtractionFilter_Test() //Gather the dependencies (this is what we are testing) var gatherer = new Gatherer(RepositoryLocator); - Assert.IsTrue(gatherer.CanGatherDependencies(filter)); + Assert.That(gatherer.CanGatherDependencies(filter)); var gathered = Gatherer.GatherDependencies(filter); //gatherer should have gathered the filter and the parameter (but not the ExtractionFilterParameterSet sets) - Assert.AreEqual(1, gathered.Children.Count); - Assert.AreEqual(param, gathered.Children[0].Object); + Assert.That(gathered.Children, Has.Count.EqualTo(1)); + Assert.That(gathered.Children[0].Object, Is.EqualTo(param)); //Cleanup val.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/Curation/ImportTests/PluginClassTests.cs b/Rdmp.Core.Tests/Curation/ImportTests/PluginClassTests.cs deleted file mode 100644 index 9985d97131..0000000000 --- a/Rdmp.Core.Tests/Curation/ImportTests/PluginClassTests.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) The University of Dundee 2018-2019 -// This file is part of the Research Data Management Platform (RDMP). -// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -// RDMP 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 General Public License for more details. -// You should have received a copy of the GNU General Public License along with RDMP. If not, see . - -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using NUnit.Framework; -using Rdmp.Core.CommandLine.Runners; -using Rdmp.Core.Curation.Data; -using Rdmp.Core.Curation.Data.ImportExport; -using Rdmp.Core.Sharing.Dependency.Gathering; -using Tests.Common; - -namespace Rdmp.Core.Tests.Curation.ImportTests; - -public class PluginClassTests : UnitTests -{ - [SetUp] - protected override void SetUp() - { - base.SetUp(); - - Repository.Clear(); - } - - [Test] - public void Catalogue_returns_latest_compatible_plugin() - { - var fi = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, "Blah.zip")); - File.WriteAllBytes(fi.FullName, new byte[] { 0x1, 0x2 }); - - var version = FileVersionInfo.GetVersionInfo(typeof(PluginClassTests).Assembly.Location).FileVersion ?? - throw new Exception($"No file version in {typeof(PluginClassTests).Assembly.Location}"); - - var lma1 = WhenIHaveA(); - var lma2 = WhenIHaveA(); - - - lma1.Plugin.Name = "MyPlugin"; - lma1.Plugin.RdmpVersion = new Version(version); //the version of Rdmp.Core targetted - lma1.Plugin.PluginVersion = new Version(1, 1, 1, 1); //the version of the plugin - lma1.Plugin.SaveToDatabase(); - - lma2.Plugin.Name = "MyPlugin"; - lma2.Plugin.RdmpVersion = new Version(version); //the version of Rdmp.Core targetted (same as above) - lma2.Plugin.PluginVersion = new Version(1, 1, 1, 2); //the version of the plugin (higher) - lma2.SaveToDatabase(); - - var plugins = Repository.PluginManager.GetCompatiblePlugins(); - Assert.That(plugins, Has.Length.EqualTo(1)); - Assert.That(plugins[0], Is.EqualTo(lma2.Plugin)); - } - - [Test] - public void TestPlugin_OrphanImport_Sharing() - { - //Setup the load module we want to test (with plugin parent) - var fi = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, - $"Blah2.{PackPluginRunner.PluginPackageSuffix}")); - File.WriteAllBytes(fi.FullName, new byte[] { 0x1, 0x2 }); - - var fi2 = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, - $"Blah2.{PackPluginRunner.PluginPackageSuffix}")); - File.WriteAllBytes(fi2.FullName, new byte[] { 0x1, 0x2 }); - - var fi3 = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, - $"Blah3.{PackPluginRunner.PluginPackageSuffix}")); - File.WriteAllBytes(fi3.FullName, new byte[] { 0x3, 0x4 }); - - var p = new Plugin(Repository, fi, new Version(1, 1, 1), new Version(1, 1, 1, 1)); - var lma = new LoadModuleAssembly(Repository, fi2, p); - var lma2 = new LoadModuleAssembly(Repository, fi3, p); - - //gather dependencies of the plugin (plugin[0] + lma[1]) - var g = new Gatherer(RepositoryLocator); - var sm = new ShareManager(RepositoryLocator); - var list = Gatherer.GatherDependencies(p).ToShareDefinitionWithChildren(sm); - - //Delete export definitions - foreach (var e in Repository.GetAllObjects()) - e.DeleteInDatabase(); - - //and delete pluing (CASCADE deletes lma too) - p.DeleteInDatabase(); - - //import them - var created = sm.ImportSharedObject(list).ToArray(); - - //There should be 3 - Assert.AreEqual(3, created.Length); - - Assert.AreEqual(3, Repository.GetAllObjects().Length); - - lma2 = (LoadModuleAssembly)created[2]; - - //now delete lma2 only - lma2.DeleteInDatabase(); - - Assert.AreEqual(2, Repository.GetAllObjects().Length); - - //import them - var created2 = sm.ImportSharedObject(list); - - //There should still be 3 - Assert.AreEqual(3, created2.Count()); - } - - [TestCase("Rdmp.1.2.3.nupkg", "Rdmp")] - [TestCase("Rdmp.Dicom.1.2.3.nupkg", "Rdmp.Dicom")] - [TestCase("Rdmp.Dicom.nupkg", "Rdmp.Dicom")] - [TestCase("Rdmp.Dicom", "Rdmp.Dicom")] - public void Test_Plugin_ShortName(string fullname, string expected) - { - var p = WhenIHaveA(); - p.Name = fullname; - Assert.AreEqual(expected, p.GetShortName()); - } -} \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/ImportTests/ShareLoadMetadataTests.cs b/Rdmp.Core.Tests/Curation/ImportTests/ShareLoadMetadataTests.cs index f7598ce18d..b4fbcea25f 100644 --- a/Rdmp.Core.Tests/Curation/ImportTests/ShareLoadMetadataTests.cs +++ b/Rdmp.Core.Tests/Curation/ImportTests/ShareLoadMetadataTests.cs @@ -32,9 +32,12 @@ public void GatherAndShare_LoadMetadata_EmptyLoadMetadata() var lmd2 = ShareToNewRepository(lmd); - //different repos so not identical - Assert.IsFalse(ReferenceEquals(lmd, lmd2)); - Assert.AreEqual(lmd.Name, lmd2.Name); + Assert.Multiple(() => + { + //different repos so not identical + Assert.That(ReferenceEquals(lmd, lmd2), Is.False); + Assert.That(lmd2.Name, Is.EqualTo(lmd.Name)); + }); } [Test] @@ -47,12 +50,15 @@ public void GatherAndShare_LoadMetadata_WithCatalogue() var cata1 = lmd1.GetAllCatalogues().Single(); var cata2 = lmd2.GetAllCatalogues().Single(); - //different repos so not identical - Assert.IsFalse(ReferenceEquals(lmd1, lmd2)); - Assert.IsFalse(ReferenceEquals(cata1, cata2)); + Assert.Multiple(() => + { + //different repos so not identical + Assert.That(ReferenceEquals(lmd1, lmd2), Is.False); + Assert.That(ReferenceEquals(cata1, cata2), Is.False); - Assert.AreEqual(lmd1.Name, lmd2.Name); - Assert.AreEqual(cata1.Name, cata2.Name); + Assert.That(lmd2.Name, Is.EqualTo(lmd1.Name)); + Assert.That(cata2.Name, Is.EqualTo(cata1.Name)); + }); } /// @@ -69,13 +75,13 @@ public void GatherAndShare_LoadMetadata_WithProcessTask() var pt2 = lmd2.ProcessTasks.Single(); //different repos so not identical - Assert.IsFalse(ReferenceEquals(lmd1, lmd2)); + Assert.That(ReferenceEquals(lmd1, lmd2), Is.False); AssertAreEqual(lmd1, lmd2); - Assert.IsFalse(ReferenceEquals(pt1, pt2)); + Assert.That(ReferenceEquals(pt1, pt2), Is.False); AssertAreEqual(pt1, pt2); - Assert.IsFalse(ReferenceEquals(pt1.ProcessTaskArguments.Single(), pt2.ProcessTaskArguments.Single())); + Assert.That(ReferenceEquals(pt1.ProcessTaskArguments.Single(), pt2.ProcessTaskArguments.Single()), Is.False); AssertAreEqual(pt1.ProcessTaskArguments.Single(), pt2.ProcessTaskArguments.Single()); } @@ -105,12 +111,12 @@ public void GatherAndShare_LoadMetadata_WithRealProcessTask() var lmd2 = ShareToNewRepository(lmd1); //different repos so not identical - Assert.IsFalse(ReferenceEquals(lmd1, lmd2)); + Assert.That(ReferenceEquals(lmd1, lmd2), Is.False); AssertAreEqual(lmd1, lmd2); var pt2 = lmd2.ProcessTasks.Single(); - Assert.IsFalse(ReferenceEquals(pt1, pt2)); + Assert.That(ReferenceEquals(pt1, pt2), Is.False); AssertAreEqual(pt1, pt2); AssertAreEqual(pt1.GetAllArguments(), pt2.GetAllArguments()); @@ -156,7 +162,7 @@ public void GatherAndShare_LoadMetadata_WithReferenceProcessTaskArgument() //check that reflection can assemble the master ProcessTask var t = (MutilateDataTablesRuntimeTask)RuntimeTaskFactory.Create(pt1, stg); - Assert.IsNotNull(((SafePrimaryKeyCollisionResolverMutilation)t.MEFPluginClassInstance).ColumnToResolveOn); + Assert.That(((SafePrimaryKeyCollisionResolverMutilation)t.MEFPluginClassInstance).ColumnToResolveOn, Is.Not.Null); //share to the second repository (which won't have that ColumnInfo) var lmd2 = ShareToNewRepository(lmd1); @@ -166,14 +172,14 @@ public void GatherAndShare_LoadMetadata_WithReferenceProcessTaskArgument() //when we create the shared instance it should not have a valid value for ColumnInfo (since it wasn't - and shouldn't be shared) var t2 = (MutilateDataTablesRuntimeTask)RuntimeTaskFactory.Create(lmd2.ProcessTasks.Single(), stg); - Assert.IsNull(((SafePrimaryKeyCollisionResolverMutilation)t2.MEFPluginClassInstance).ColumnToResolveOn); + Assert.That(((SafePrimaryKeyCollisionResolverMutilation)t2.MEFPluginClassInstance).ColumnToResolveOn, Is.Null); } private LoadMetadata ShareToNewRepository(LoadMetadata lmd) { var gatherer = new Gatherer(RepositoryLocator); - Assert.IsTrue(gatherer.CanGatherDependencies(lmd)); + Assert.That(gatherer.CanGatherDependencies(lmd)); var rootObj = gatherer.GatherDependencies(lmd); var sm = new ShareManager(RepositoryLocator, null); diff --git a/Rdmp.Core.Tests/Curation/Integration/AllKeywordsDescribedTest.cs b/Rdmp.Core.Tests/Curation/Integration/AllKeywordsDescribedTest.cs index dcab4d9ef6..82afafa465 100644 --- a/Rdmp.Core.Tests/Curation/Integration/AllKeywordsDescribedTest.cs +++ b/Rdmp.Core.Tests/Curation/Integration/AllKeywordsDescribedTest.cs @@ -51,7 +51,7 @@ public void AllTablesDescribed() foreach (var problem in problems) Console.WriteLine($"Fatal Problem:{problem}"); - Assert.AreEqual(0, problems.Count); + Assert.That(problems, Is.Empty); } [Test] @@ -73,7 +73,7 @@ public void AllForeignKeysDescribed() foreach (var problem in problems) Console.WriteLine($"Fatal Problem:{problem}"); - Assert.AreEqual(0, problems.Count, @"Add a description for each of these to KeywordHelp.txt"); + Assert.That(problems, Is.Empty, @"Add a description for each of these to KeywordHelp.txt"); } [Test] @@ -96,7 +96,7 @@ public void AllUserIndexesDescribed() foreach (var problem in problems) Console.WriteLine($"Fatal Problem:{problem}"); - Assert.AreEqual(0, problems.Count, @"Add a description for each of these to KeywordHelp.txt"); + Assert.That(problems, Is.Empty, @"Add a description for each of these to KeywordHelp.txt"); } private static IEnumerable GetForeignKeys(DiscoveredServer server) diff --git a/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ArgumentTypeTests.cs b/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ArgumentTypeTests.cs index bd6914a824..6a4258e171 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ArgumentTypeTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ArgumentTypeTests.cs @@ -32,7 +32,7 @@ public void Test_Type_WithStringValue(Type t, string val, int expectedAnswerIdx) arg.SetType(t); arg.Value = val; - Assert.AreEqual(_expectedAnswers[expectedAnswerIdx], arg.GetValueAsSystemType()); + Assert.That(arg.GetValueAsSystemType(), Is.EqualTo(_expectedAnswers[expectedAnswerIdx])); } [Test] @@ -40,8 +40,11 @@ public void TestClassDemandingDouble_CreateArgumentsForClassIfNotExists() { var args = WhenIHaveA().CreateArgumentsForClassIfNotExists(); - Assert.AreEqual(1.0, args.Single().GetValueAsSystemType()); - Assert.AreEqual("1", args.Single().Value); + Assert.Multiple(() => + { + Assert.That(args.Single().GetValueAsSystemType(), Is.EqualTo(1.0)); + Assert.That(args.Single().Value, Is.EqualTo("1")); + }); } private class TestClassDemandingDouble diff --git a/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ProcessTaskArgumentTests.cs b/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ProcessTaskArgumentTests.cs index 9eccce8937..3d67492a3c 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ProcessTaskArgumentTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ProcessTaskArgumentTests.cs @@ -50,12 +50,12 @@ public void TypeOfTableInfo(bool declareAsInterface) var newInstanceOfPTA = CatalogueRepository.GetObjectByID(pta.ID); - Assert.AreEqual(newInstanceOfPTA.Value, pta.Value); + Assert.That(pta.Value, Is.EqualTo(newInstanceOfPTA.Value)); var t1 = (TableInfo)pta.GetValueAsSystemType(); var t2 = (TableInfo)newInstanceOfPTA.GetValueAsSystemType(); - Assert.AreEqual(t1.ID, t2.ID); + Assert.That(t2.ID, Is.EqualTo(t1.ID)); } finally { @@ -104,12 +104,12 @@ public void TypeOfPreLoadDiscardedColumn() pta.SaveToDatabase(); var newInstanceOfPTA = CatalogueRepository.GetObjectByID(pta.ID); - Assert.AreEqual(newInstanceOfPTA.Value, pta.Value); + Assert.That(pta.Value, Is.EqualTo(newInstanceOfPTA.Value)); var p1 = (PreLoadDiscardedColumn)pta.GetValueAsSystemType(); var p2 = (PreLoadDiscardedColumn)newInstanceOfPTA.GetValueAsSystemType(); - Assert.AreEqual(p1.ID, p2.ID); + Assert.That(p2.ID, Is.EqualTo(p1.ID)); } finally { @@ -153,7 +153,7 @@ public void TableInfoType_FetchAfterDelete_ReturnsNull() tableInfo.DeleteInDatabase(); //give the object back now please? - returns null because it's gone (new behaviour) - Assert.IsNull(pta.GetValueAsSystemType()); + Assert.That(pta.GetValueAsSystemType(), Is.Null); //old behaviour /*var ex = Assert.Throws(()=>pta.GetValueAsSystemType()); @@ -188,9 +188,8 @@ public void LieToProcessTaskArgumentAboutWhatTypeIs_Throws() pta.SetType(typeof(PreLoadDiscardedColumn)); //then surprise! heres a TableInfo! var ex = Assert.Throws(() => pta.SetValue(tableInfo)); - StringAssert.Contains( - "has an incompatible Type specified (Rdmp.Core.Curation.Data.DataLoad.PreLoadDiscardedColumn)", - ex.Message); + Assert.That( + ex.Message, Does.Contain("has an incompatible Type specified (Rdmp.Core.Curation.Data.DataLoad.PreLoadDiscardedColumn)")); } finally { @@ -226,8 +225,8 @@ public void TestEncryptedPasswordHostArgumentType() var loadedPta = CatalogueRepository.GetObjectByID(pta.ID); var value = loadedPta.GetValueAsSystemType() as EncryptedString; - Assert.NotNull(value); - Assert.AreEqual("test123", value.GetDecryptedValue()); + Assert.That(value, Is.Not.Null); + Assert.That(value.GetDecryptedValue(), Is.EqualTo("test123")); } finally { @@ -251,11 +250,14 @@ public void TestArgumentCreation() { var arg = pt.ProcessTaskArguments.Single(); - Assert.AreEqual("MyBool", arg.Name); - Assert.AreEqual("System.Boolean", arg.Type); - Assert.AreEqual("Fishes", arg.Description); - Assert.AreEqual("True", arg.Value); - Assert.AreEqual(true, arg.GetValueAsSystemType()); + Assert.Multiple(() => + { + Assert.That(arg.Name, Is.EqualTo("MyBool")); + Assert.That(arg.Type, Is.EqualTo("System.Boolean")); + Assert.That(arg.Description, Is.EqualTo("Fishes")); + Assert.That(arg.Value, Is.EqualTo("True")); + Assert.That(arg.GetValueAsSystemType(), Is.EqualTo(true)); + }); } finally { @@ -275,12 +277,15 @@ public void TestNestedDemandsGetPutIntoDatabaseAndCanBeBroughtBack() //some of the DemandsInitialization on BasicDataReleaseDestination should be nested var f = new ArgumentFactory(); - Assert.True( - ArgumentFactory.GetRequiredProperties(typeof(BasicDataReleaseDestination)) - .Any(r => r.ParentPropertyInfo != null)); + Assert.Multiple(() => + { + Assert.That( + ArgumentFactory.GetRequiredProperties(typeof(BasicDataReleaseDestination)) + .Any(r => r.ParentPropertyInfo != null)); - //new pc should have no arguments - Assert.That(pc.GetAllArguments(), Is.Empty); + //new pc should have no arguments + Assert.That(pc.GetAllArguments(), Is.Empty); + }); //we create them (the root and nested ones!) var args = pc.CreateArgumentsForClassIfNotExists(); @@ -296,7 +301,7 @@ public void TestNestedDemandsGetPutIntoDatabaseAndCanBeBroughtBack() var destInstance = DataFlowPipelineEngineFactory.CreateDestinationIfExists(pipe); - Assert.AreEqual(true, ((BasicDataReleaseDestination)destInstance).ReleaseSettings.DeleteFilesOnSuccess); + Assert.That(((BasicDataReleaseDestination)destInstance).ReleaseSettings.DeleteFilesOnSuccess, Is.EqualTo(true)); } @@ -315,12 +320,12 @@ public void TestArgumentWithTypeThatIsEnum() arg.SetValue(ExitCodeType.OperationNotRequired); //should have set Value string to the ID of the object - Assert.AreEqual(arg.Value, ExitCodeType.OperationNotRequired.ToString()); + Assert.That(arg.Value, Is.EqualTo(ExitCodeType.OperationNotRequired.ToString())); arg.SaveToDatabase(); //but as system Type should return the server - Assert.AreEqual(arg.GetValueAsSystemType(), ExitCodeType.OperationNotRequired); + Assert.That(arg.GetValueAsSystemType(), Is.EqualTo(ExitCodeType.OperationNotRequired)); } finally { @@ -348,12 +353,12 @@ public void TestArgumentWithTypeThatIsInterface(bool useInterfaceDeclaration) arg.SetValue(server); //should have set Value string to the ID of the object - Assert.AreEqual(arg.Value, server.ID.ToString()); + Assert.That(server.ID.ToString(), Is.EqualTo(arg.Value)); arg.SaveToDatabase(); //but as system Type should return the server - Assert.AreEqual(arg.GetValueAsSystemType(), server); + Assert.That(server, Is.EqualTo(arg.GetValueAsSystemType())); } finally { @@ -378,7 +383,7 @@ public void TestArgumentThatIsDictionary() arg.SetType(typeof(Dictionary)); arg.SaveToDatabase(); - Assert.AreEqual(typeof(Dictionary), arg.GetConcreteSystemType()); + Assert.That(arg.GetConcreteSystemType(), Is.EqualTo(typeof(Dictionary))); var ti1 = new TableInfo(CatalogueRepository, "test1"); var ti2 = new TableInfo(CatalogueRepository, "test2"); @@ -394,9 +399,12 @@ public void TestArgumentThatIsDictionary() arg.SaveToDatabase(); var val2 = (Dictionary)arg.GetValueAsSystemType(); - Assert.AreEqual(2, val2.Count); - Assert.AreEqual("Fish", val2[ti1]); - Assert.AreEqual("Fish", val2[ti2]); + Assert.That(val2, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(val2[ti1], Is.EqualTo("Fish")); + Assert.That(val2[ti2], Is.EqualTo("Fish")); + }); } finally { diff --git a/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ProcessTaskTests.cs b/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ProcessTaskTests.cs index 3cad82713f..e1b3179dbf 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ProcessTaskTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ArgumentTests/ProcessTaskTests.cs @@ -28,21 +28,27 @@ public void CloneProcessTask_ToSameLoadMetadataWithoutArguments() processTask1.SaveToDatabase(); var clone = processTask1.CloneToNewLoadMetadataStage(test, LoadStage.GetFiles); - Assert.AreNotSame(clone.ID, processTask1.ID); - Assert.IsFalse(clone.ID == processTask1.ID); + Assert.Multiple(() => + { + Assert.That(processTask1.ID, Is.Not.EqualTo(clone.ID)); + Assert.That(clone.ID, Is.Not.EqualTo(processTask1.ID)); + }); //get fresh copy out of database to ensure it is still there var orig = CatalogueRepository.GetObjectByID(processTask1.ID); clone = CatalogueRepository.GetObjectByID(clone.ID); - Assert.IsFalse(orig.ID == clone.ID); - Assert.AreEqual(LoadStage.AdjustRaw, orig.LoadStage); - Assert.AreEqual(LoadStage.GetFiles, clone.LoadStage); + Assert.Multiple(() => + { + Assert.That(orig.ID, Is.Not.EqualTo(clone.ID)); + Assert.That(orig.LoadStage, Is.EqualTo(LoadStage.AdjustRaw)); + Assert.That(clone.LoadStage, Is.EqualTo(LoadStage.GetFiles)); - Assert.AreEqual(orig.Order, clone.Order); - Assert.AreEqual(orig.Path, clone.Path); - Assert.AreEqual(orig.ProcessTaskType, clone.ProcessTaskType); - Assert.AreEqual(orig.LoadMetadata_ID, clone.LoadMetadata_ID); + Assert.That(clone.Order, Is.EqualTo(orig.Order)); + Assert.That(clone.Path, Is.EqualTo(orig.Path)); + Assert.That(clone.ProcessTaskType, Is.EqualTo(orig.ProcessTaskType)); + Assert.That(clone.LoadMetadata_ID, Is.EqualTo(orig.LoadMetadata_ID)); + }); clone.DeleteInDatabase(); } @@ -61,7 +67,7 @@ public void CloneProcessTask_ToNewLoadMetadataWithArguments() var parent2 = new LoadMetadata(CatalogueRepository); //make sure we didn't magically create the same ID somehow - Assert.AreNotEqual(parent1.ID, parent2.ID); + Assert.That(parent2.ID, Is.Not.EqualTo(parent1.ID)); //setup things to clone in parent1 var processTask1 = new ProcessTask(CatalogueRepository, parent1, LoadStage.AdjustRaw); @@ -81,39 +87,48 @@ public void CloneProcessTask_ToNewLoadMetadataWithArguments() { //clone to parent 2 var clone = processTask1.CloneToNewLoadMetadataStage(parent2, LoadStage.GetFiles); - Assert.AreNotSame(clone.ID, processTask1.ID); - Assert.IsFalse(clone.ID == processTask1.ID); + Assert.Multiple(() => + { + Assert.That(processTask1.ID, Is.Not.EqualTo(clone.ID)); + Assert.That(clone.ID, Is.Not.EqualTo(processTask1.ID)); + }); //////////////////////////////////////////////////////////////////CHECK CLONAGE OF PROCESS TASK //////////////////////////////////////////////////////////// //get fresh copy out of database to ensure it is still there var orig = CatalogueRepository.GetObjectByID(processTask1.ID); clone = CatalogueRepository.GetObjectByID(clone.ID); - //ids must have changed - Assert.IsFalse(orig.ID == clone.ID); + Assert.Multiple(() => + { + //ids must have changed + Assert.That(orig.ID, Is.Not.EqualTo(clone.ID)); - //load stages must be correct per what we requested - Assert.AreEqual(LoadStage.AdjustRaw, orig.LoadStage); - Assert.AreEqual(LoadStage.GetFiles, clone.LoadStage); + //load stages must be correct per what we requested + Assert.That(orig.LoadStage, Is.EqualTo(LoadStage.AdjustRaw)); + Assert.That(clone.LoadStage, Is.EqualTo(LoadStage.GetFiles)); - //all regular values must have been cloned successfully - Assert.AreEqual(orig.Order, clone.Order); - Assert.AreEqual(orig.Path, clone.Path); - Assert.AreEqual(orig.ProcessTaskType, clone.ProcessTaskType); + //all regular values must have been cloned successfully + Assert.That(clone.Order, Is.EqualTo(orig.Order)); + Assert.That(clone.Path, Is.EqualTo(orig.Path)); + Assert.That(clone.ProcessTaskType, Is.EqualTo(orig.ProcessTaskType)); - Assert.AreEqual(parent1.ID, orig.LoadMetadata_ID); - Assert.AreEqual(parent2.ID, clone.LoadMetadata_ID); + Assert.That(orig.LoadMetadata_ID, Is.EqualTo(parent1.ID)); + Assert.That(clone.LoadMetadata_ID, Is.EqualTo(parent2.ID)); + }); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////CHECK CLONAGE OF ARGUMENTS //////////////////////////////////////////////////////////// var clonearg = clone.ProcessTaskArguments.SingleOrDefault(); - Assert.NotNull(clonearg); - - Assert.AreNotEqual(clonearg.ID, arg.ID); - Assert.AreEqual(clonearg.GetType(), arg.GetType()); - Assert.AreEqual(clonearg.Name, arg.Name); - Assert.AreEqual(clonearg.Value, arg.Value); + Assert.Multiple(() => + { + Assert.That(clonearg, Is.Not.Null); + + Assert.That(arg.ID, Is.Not.EqualTo(clonearg.ID)); + Assert.That(arg.GetType(), Is.EqualTo(clonearg.GetType())); + Assert.That(arg.Name, Is.EqualTo(clonearg.Name)); + Assert.That(arg.Value, Is.EqualTo(clonearg.Value)); + }); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// clone.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/Curation/Integration/BundledLookupTableTests.cs b/Rdmp.Core.Tests/Curation/Integration/BundledLookupTableTests.cs index cc1d94d16d..b41cb2706d 100644 --- a/Rdmp.Core.Tests/Curation/Integration/BundledLookupTableTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/BundledLookupTableTests.cs @@ -22,7 +22,7 @@ public void TestLookupGetDataTableFetchSql() var t = l.PrimaryKey.TableInfo; var bundle = new BundledLookupTable(t); - Assert.AreEqual("select * from [MyDb]..[ChildTable]", bundle.GetDataTableFetchSql()); + Assert.That(bundle.GetDataTableFetchSql(), Is.EqualTo("select * from [MyDb]..[ChildTable]")); } [Test] @@ -35,25 +35,25 @@ public void TestLookupGetDataTableFetchSql_WithCatalogue() engineer.ExecuteForwardEngineering(out var cata, out _, out var eis); var bundle = new BundledLookupTable(t); - Assert.AreEqual(@" + Assert.That(bundle.GetDataTableFetchSql(), Is.EqualTo(@" SELECT ChildCol, Desc FROM -ChildTable", bundle.GetDataTableFetchSql()); +ChildTable")); // ei 1 is suplemental now eis[1].ExtractionCategory = ExtractionCategory.Supplemental; eis[1].SaveToDatabase(); - Assert.AreEqual(@" + Assert.That(bundle.GetDataTableFetchSql(), Is.EqualTo(@" SELECT ChildCol FROM -ChildTable", bundle.GetDataTableFetchSql()); +ChildTable")); // ei 0 is marked IsExtractionIdentifier - so is also not a valid @@ -64,8 +64,7 @@ public void TestLookupGetDataTableFetchSql_WithCatalogue() // so now there are no columns at all that are extractable var ex = Assert.Throws(() => bundle.GetDataTableFetchSql()); - Assert.AreEqual( - "Lookup table 'ChildTable' has a Catalogue defined 'ChildTable' but it has no Core extractable columns", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Lookup table 'ChildTable' has a Catalogue defined 'ChildTable' but it has no Core extractable columns")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/CatalogueCheckTests.cs b/Rdmp.Core.Tests/Curation/Integration/CatalogueCheckTests.cs index 5eff4ab016..2f94ac2651 100644 --- a/Rdmp.Core.Tests/Curation/Integration/CatalogueCheckTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/CatalogueCheckTests.cs @@ -26,7 +26,7 @@ public void CatalogueCheck_DodgyName() }; var ex = Assert.Throws(() => cata.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.IsTrue(ex.Message.Contains("The following invalid characters were found:'\\','.','#'")); + Assert.That(ex.Message, Does.Contain("The following invalid characters were found:'\\','.','#'")); cata.DeleteInDatabase(); } @@ -48,14 +48,14 @@ public void CatalogueCheck_FetchData(DatabaseType databaseType) //shouldn't be any errors var tomemory = new ToMemoryCheckNotifier(); cata.Check(tomemory); - Assert.AreEqual(CheckResult.Success, tomemory.GetWorst()); + Assert.That(tomemory.GetWorst(), Is.EqualTo(CheckResult.Success)); //delete all the records in the table tbl.Truncate(); cata.Check(tomemory); //now it should warn us that it is empty - Assert.AreEqual(CheckResult.Warning, tomemory.GetWorst()); + Assert.That(tomemory.GetWorst(), Is.EqualTo(CheckResult.Warning)); tbl.Drop(); @@ -63,6 +63,6 @@ public void CatalogueCheck_FetchData(DatabaseType databaseType) cata.Check(tomemory); //now it should fail checks - Assert.AreEqual(CheckResult.Fail, tomemory.GetWorst()); + Assert.That(tomemory.GetWorst(), Is.EqualTo(CheckResult.Fail)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/CatalogueItemTests.cs b/Rdmp.Core.Tests/Curation/Integration/CatalogueItemTests.cs index c0c3f2d43a..3e78fe7ace 100644 --- a/Rdmp.Core.Tests/Curation/Integration/CatalogueItemTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/CatalogueItemTests.cs @@ -20,10 +20,13 @@ public void constructor_newTestCatalogueItem_pass() var child1 = new CatalogueItem(CatalogueRepository, parent, "GROG_ITEM1"); var child2 = new CatalogueItem(CatalogueRepository, parent, "GROG_ITEM2"); - Assert.IsTrue(child1.Catalogue_ID == parent.ID); - Assert.IsTrue(child2.Catalogue_ID == parent.ID); + Assert.Multiple(() => + { + Assert.That(child1.Catalogue_ID, Is.EqualTo(parent.ID)); + Assert.That(child2.Catalogue_ID, Is.EqualTo(parent.ID)); - Assert.IsTrue(child1.ID != child2.ID); + Assert.That(child1.ID, Is.Not.EqualTo(child2.ID)); + }); child1.DeleteInDatabase(); child2.DeleteInDatabase(); @@ -39,7 +42,7 @@ public void TestSettingColumnInfoToNull() var child1 = new CatalogueItem(CatalogueRepository, parent, "GROG_ITEM1"); child1.SetColumnInfo(null); - Assert.IsNull(child1.ColumnInfo_ID); + Assert.That(child1.ColumnInfo_ID, Is.Null); child1.DeleteInDatabase(); parent.DeleteInDatabase(); } @@ -54,10 +57,13 @@ public void GetAllCatalogueItemsForCatalogueID_NewCatalogue_pass() var children = parent.CatalogueItems; - Assert.AreEqual(children.Length, 2); - Assert.IsTrue(children[0].ID == child1.ID || children[1].ID == child1.ID); - Assert.IsTrue(children[0].ID == child2.ID || children[1].ID == child2.ID); - Assert.IsTrue(children[0].ID != children[1].ID); + Assert.That(children, Has.Length.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(children[0].ID == child1.ID || children[1].ID == child1.ID); + Assert.That(children[0].ID == child2.ID || children[1].ID == child2.ID); + Assert.That(children[0].ID, Is.Not.EqualTo(children[1].ID)); + }); children[0].DeleteInDatabase(); children[1].DeleteInDatabase(); @@ -86,15 +92,18 @@ public void update_changeAllPropertiesOfCatalogueItem_passes() var childAfter = CatalogueRepository.GetObjectByID(child.ID); - Assert.IsTrue(child.Name == childAfter.Name); - Assert.IsTrue(child.Agg_method == childAfter.Agg_method); - Assert.IsTrue(child.Comments == childAfter.Comments); - Assert.IsTrue(child.Limitations == childAfter.Limitations); - Assert.IsTrue(child.Description == childAfter.Description); - Assert.IsTrue(child.Periodicity == childAfter.Periodicity); - Assert.IsTrue(child.Research_relevance == childAfter.Research_relevance); - Assert.IsTrue(child.Statistical_cons == childAfter.Statistical_cons); - Assert.IsTrue(child.Topic == childAfter.Topic); + Assert.Multiple(() => + { + Assert.That(child.Name, Is.EqualTo(childAfter.Name)); + Assert.That(child.Agg_method, Is.EqualTo(childAfter.Agg_method)); + Assert.That(child.Comments, Is.EqualTo(childAfter.Comments)); + Assert.That(child.Limitations, Is.EqualTo(childAfter.Limitations)); + Assert.That(child.Description, Is.EqualTo(childAfter.Description)); + Assert.That(child.Periodicity, Is.EqualTo(childAfter.Periodicity)); + Assert.That(child.Research_relevance, Is.EqualTo(childAfter.Research_relevance)); + Assert.That(child.Statistical_cons, Is.EqualTo(childAfter.Statistical_cons)); + Assert.That(child.Topic, Is.EqualTo(childAfter.Topic)); + }); child.DeleteInDatabase(); parent.DeleteInDatabase(); @@ -126,18 +135,21 @@ public void clone_CloneCatalogueItemWithIDIntoCatalogue_passes() child.SaveToDatabase(); cloneChild = child.CloneCatalogueItemWithIDIntoCatalogue(parent2); - //get the clone that was returned - Assert.AreEqual(cloneChild.Catalogue_ID, parent2.ID); //it is in the second one - Assert.AreNotEqual(cloneChild.Catalogue_ID, parent.ID); //it is not in the first one - Assert.AreNotEqual(cloneChild.ID, child.ID); //it has a new ID - - Assert.AreEqual(cloneChild.Limitations, child.Limitations); - Assert.AreEqual(cloneChild.Description, child.Description); - Assert.AreEqual(cloneChild.Name, child.Name); - Assert.AreEqual(cloneChild.Periodicity, child.Periodicity); - Assert.AreEqual(cloneChild.Research_relevance, child.Research_relevance); - Assert.AreEqual(cloneChild.Statistical_cons, child.Statistical_cons); - Assert.AreEqual(cloneChild.Topic, child.Topic); + Assert.Multiple(() => + { + //get the clone that was returned + Assert.That(parent2.ID, Is.EqualTo(cloneChild.Catalogue_ID)); //it is in the second one + Assert.That(parent.ID, Is.Not.EqualTo(cloneChild.Catalogue_ID)); //it is not in the first one + Assert.That(child.ID, Is.Not.EqualTo(cloneChild.ID)); //it has a new ID + + Assert.That(child.Limitations, Is.EqualTo(cloneChild.Limitations)); + Assert.That(child.Description, Is.EqualTo(cloneChild.Description)); + Assert.That(child.Name, Is.EqualTo(cloneChild.Name)); + Assert.That(child.Periodicity, Is.EqualTo(cloneChild.Periodicity)); + Assert.That(child.Research_relevance, Is.EqualTo(cloneChild.Research_relevance)); + Assert.That(child.Statistical_cons, Is.EqualTo(cloneChild.Statistical_cons)); + Assert.That(child.Topic, Is.EqualTo(cloneChild.Topic)); + }); } finally { @@ -165,11 +177,14 @@ public void TestDeleting_CascadesToExtractionInformations(bool makeOrphanFirst) c.DeleteInDatabase(); - Assert.IsFalse(c.Exists()); - Assert.IsFalse(ci.Exists()); - Assert.IsFalse(ei.Exists()); + Assert.Multiple(() => + { + Assert.That(c.Exists(), Is.False); + Assert.That(ci.Exists(), Is.False); + Assert.That(ei.Exists(), Is.False); - Assert.IsTrue(t.Exists()); - Assert.AreEqual(!makeOrphanFirst, col.Exists()); + Assert.That(t.Exists()); + Assert.That(col.Exists(), Is.EqualTo(!makeOrphanFirst)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/CatalogueTests.cs b/Rdmp.Core.Tests/Curation/Integration/CatalogueTests.cs index 57b197b80d..5674203e00 100644 --- a/Rdmp.Core.Tests/Curation/Integration/CatalogueTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/CatalogueTests.cs @@ -21,7 +21,7 @@ public void Test_GetObjects_Catalogue() var catalogueWithId = new Catalogue(Repository, "bob"); var catas = Repository.GetAllObjects(); - Assert.IsTrue(catas.Length > 0); + Assert.That(catas, Is.Not.Empty); catalogueWithId.DeleteInDatabase(); } @@ -36,12 +36,12 @@ public void SettingPropertyViaRelationshipDoesntSave_NoticeHowYouHaveToCacheTheP var cata = ci.Catalogue; cata.Name = "fish2"; cata.SaveToDatabase(); - Assert.AreEqual("fish2", ci.Catalogue.Name); + Assert.That(ci.Catalogue.Name, Is.EqualTo("fish2")); //now thanks to lazy this works... but it's ambiguous (it works if the property is referenced via IInjectKnown) ci.Catalogue.Name = "fish"; ci.Catalogue.SaveToDatabase(); - Assert.AreEqual("fish", ci.Catalogue.Name); + Assert.That(ci.Catalogue.Name, Is.EqualTo("fish")); c.DeleteInDatabase(); } @@ -70,7 +70,7 @@ public void update_changeNameOfCatalogue_passes() foreach (var catalogue in catasAfter) if (catalogue.ID == expectedID) { - Assert.AreEqual(catalogue.Name, "fish"); + Assert.That(catalogue.Name, Is.EqualTo("fish")); catalogue.DeleteInDatabase(); } } @@ -132,40 +132,43 @@ public void update_changeAllProperties_pass() foreach (var catalogue in catasAfter) if (catalogue.ID == expectedID) { - Assert.AreEqual(catalogue.Access_options, "backwards,frontwards"); - Assert.AreEqual(catalogue.API_access_URL, new Uri("http://API.html")); - Assert.AreEqual(catalogue.Acronym, "abc"); - Assert.AreEqual(catalogue.Attribution_citation, "belongs to dave"); - Assert.AreEqual(catalogue.Browse_URL, new Uri("http://browse.html")); - Assert.AreEqual(catalogue.Bulk_Download_URL, new Uri("http://bulk.html")); - Assert.AreEqual(catalogue.Contact_details, "thomasnind"); - Assert.AreEqual(catalogue.Geographical_coverage, "fullspectrum"); - Assert.AreEqual(catalogue.Resource_owner, "blackhole"); - Assert.AreEqual(catalogue.Description, "exciting stuff of great excitement"); - Assert.AreEqual(catalogue.Detail_Page_URL, new Uri("http://detail.html")); - Assert.AreEqual(catalogue.Last_revision_date, DateTime.Parse("01/01/01")); - Assert.AreEqual(catalogue.Name, "kaptainshield"); - Assert.AreEqual(catalogue.Background_summary, "£50 preferred"); - Assert.AreEqual(catalogue.Periodicity, Catalogue.CataloguePeriodicity.Monthly); - Assert.AreEqual(catalogue.Query_tool_URL, new Uri("http://querier.html")); - Assert.AreEqual(catalogue.Source_URL, new Uri("http://blackholeSun.html")); - Assert.AreEqual(catalogue.Time_coverage, "comprehensive"); - Assert.AreEqual(catalogue.Search_keywords, "excitement,fishmongery"); - Assert.AreEqual(catalogue.Type, Catalogue.CatalogueType.ResearchStudy); - Assert.AreEqual(catalogue.Update_freq, "Every darmn second!"); - Assert.AreEqual(catalogue.Update_sched, "periodically on request"); - - - Assert.AreEqual(catalogue.Country_of_origin, "United Kingdom"); - Assert.AreEqual(catalogue.Data_standards, "Highly Standardised"); - Assert.AreEqual(catalogue.Administrative_contact_address, "Candyland"); - Assert.AreEqual(catalogue.Administrative_contact_email, "big@brother.com"); - Assert.AreEqual(catalogue.Administrative_contact_name, "Uncle Sam"); - Assert.AreEqual(catalogue.Administrative_contact_telephone, "12345 67890"); - Assert.AreEqual(catalogue.Explicit_consent, true); - Assert.AreEqual(catalogue.Ethics_approver, "Tayside Supernatural Department"); - Assert.AreEqual(catalogue.Source_of_data_collection, "Invented by Unit Test"); - Assert.AreEqual(catalogue.SubjectNumbers, "100,000,000"); + Assert.Multiple(() => + { + Assert.That(catalogue.Access_options, Is.EqualTo("backwards,frontwards")); + Assert.That(catalogue.API_access_URL, Is.EqualTo(new Uri("http://API.html"))); + Assert.That(catalogue.Acronym, Is.EqualTo("abc")); + Assert.That(catalogue.Attribution_citation, Is.EqualTo("belongs to dave")); + Assert.That(catalogue.Browse_URL, Is.EqualTo(new Uri("http://browse.html"))); + Assert.That(catalogue.Bulk_Download_URL, Is.EqualTo(new Uri("http://bulk.html"))); + Assert.That(catalogue.Contact_details, Is.EqualTo("thomasnind")); + Assert.That(catalogue.Geographical_coverage, Is.EqualTo("fullspectrum")); + Assert.That(catalogue.Resource_owner, Is.EqualTo("blackhole")); + Assert.That(catalogue.Description, Is.EqualTo("exciting stuff of great excitement")); + Assert.That(catalogue.Detail_Page_URL, Is.EqualTo(new Uri("http://detail.html"))); + Assert.That(catalogue.Last_revision_date, Is.EqualTo(DateTime.Parse("01/01/01"))); + Assert.That(catalogue.Name, Is.EqualTo("kaptainshield")); + Assert.That(catalogue.Background_summary, Is.EqualTo("£50 preferred")); + Assert.That(catalogue.Periodicity, Is.EqualTo(Catalogue.CataloguePeriodicity.Monthly)); + Assert.That(catalogue.Query_tool_URL, Is.EqualTo(new Uri("http://querier.html"))); + Assert.That(catalogue.Source_URL, Is.EqualTo(new Uri("http://blackholeSun.html"))); + Assert.That(catalogue.Time_coverage, Is.EqualTo("comprehensive")); + Assert.That(catalogue.Search_keywords, Is.EqualTo("excitement,fishmongery")); + Assert.That(catalogue.Type, Is.EqualTo(Catalogue.CatalogueType.ResearchStudy)); + Assert.That(catalogue.Update_freq, Is.EqualTo("Every darmn second!")); + Assert.That(catalogue.Update_sched, Is.EqualTo("periodically on request")); + + + Assert.That(catalogue.Country_of_origin, Is.EqualTo("United Kingdom")); + Assert.That(catalogue.Data_standards, Is.EqualTo("Highly Standardised")); + Assert.That(catalogue.Administrative_contact_address, Is.EqualTo("Candyland")); + Assert.That(catalogue.Administrative_contact_email, Is.EqualTo("big@brother.com")); + Assert.That(catalogue.Administrative_contact_name, Is.EqualTo("Uncle Sam")); + Assert.That(catalogue.Administrative_contact_telephone, Is.EqualTo("12345 67890")); + Assert.That(catalogue.Explicit_consent, Is.EqualTo(true)); + Assert.That(catalogue.Ethics_approver, Is.EqualTo("Tayside Supernatural Department")); + Assert.That(catalogue.Source_of_data_collection, Is.EqualTo("Invented by Unit Test")); + Assert.That(catalogue.SubjectNumbers, Is.EqualTo("100,000,000")); + }); catalogue.DeleteInDatabase(); @@ -180,13 +183,13 @@ public void create_blankConstructorCatalogue_createsNewInDatabase() var newCatalogue = new Catalogue(Repository, "fishing"); var expectedID = newCatalogue.ID; - Assert.IsTrue(expectedID > 1); + Assert.That(expectedID, Is.GreaterThan(1)); var catasAfter = Repository.GetAllObjects().ToArray(); var after = catasAfter.Length; - Assert.AreEqual(before, after - 1); + Assert.That(after - 1, Is.EqualTo(before)); var numberDeleted = 0; foreach (var cata in catasAfter) @@ -196,7 +199,7 @@ public void create_blankConstructorCatalogue_createsNewInDatabase() numberDeleted++; } - Assert.AreEqual(numberDeleted, 1); + Assert.That(numberDeleted, Is.EqualTo(1)); } [Test] @@ -210,8 +213,8 @@ public void GetCatalogueWithID_validID_pass() { var c = new Catalogue(Repository, "TEST"); - Assert.NotNull(c); - Assert.True(c.Name == "TEST"); + Assert.That(c, Is.Not.Null); + Assert.That(c.Name, Is.EqualTo("TEST")); c.DeleteInDatabase(); } @@ -259,26 +262,32 @@ public void TestGetTablesAndLookupTables() try { var allTables = cata.GetTableInfoList(true).ToArray(); - Assert.Contains(t1, allTables); - Assert.Contains(t2, allTables); - Assert.Contains(t3, allTables); + Assert.That(allTables, Does.Contain(t1)); + Assert.That(allTables, Does.Contain(t2)); + Assert.That(allTables, Does.Contain(t3)); var normalTablesOnly = cata.GetTableInfoList(false).ToArray(); - Assert.AreEqual(2, normalTablesOnly.Length); - Assert.Contains(t1, normalTablesOnly); - Assert.Contains(t2, normalTablesOnly); + Assert.That(normalTablesOnly, Has.Length.EqualTo(2)); + Assert.That(normalTablesOnly, Does.Contain(t1)); + Assert.That(normalTablesOnly, Does.Contain(t2)); var lookupTablesOnly = cata.GetLookupTableInfoList(); - Assert.AreEqual(1, lookupTablesOnly.Length); - Assert.Contains(t3, lookupTablesOnly); + Assert.That(lookupTablesOnly, Has.Length.EqualTo(1)); + Assert.That(lookupTablesOnly, Does.Contain(t3)); cata.GetTableInfos(out var normalTables, out var lookupTables); - Assert.AreEqual(2, normalTables.Count); - Assert.AreEqual(1, lookupTables.Count); + Assert.Multiple(() => + { + Assert.That(normalTables, Has.Count.EqualTo(2)); + Assert.That(lookupTables, Has.Count.EqualTo(1)); + }); - Assert.Contains(t1, normalTables); - Assert.Contains(t2, normalTables); - Assert.Contains(t3, lookupTables); + Assert.That(normalTables, Does.Contain(t1)); + Assert.Multiple(() => + { + Assert.That(normalTables, Does.Contain(t2)); + Assert.That(lookupTables, Does.Contain(t3)); + }); } finally { @@ -298,7 +307,7 @@ public void CatalogueFolder_DefaultIsRoot() var c = new Catalogue(Repository, "bob"); try { - Assert.AreEqual("\\", c.Folder); + Assert.That(c.Folder, Is.EqualTo("\\")); } finally { @@ -313,11 +322,11 @@ public void CatalogueFolder_ChangeAndSave() try { c.Folder = "\\Research\\Important"; - Assert.AreEqual("\\research\\important", c.Folder); + Assert.That(c.Folder, Is.EqualTo("\\research\\important")); c.SaveToDatabase(); var c2 = Repository.GetObjectByID(c.ID); - Assert.AreEqual("\\research\\important", c2.Folder); + Assert.That(c2.Folder, Is.EqualTo("\\research\\important")); } finally { @@ -333,7 +342,7 @@ public void CatalogueFolder_CannotSetToNonRoot() try { var ex = Assert.Throws(() => c.Folder = "fish"); - Assert.AreEqual(@"All catalogue paths must start with \. Invalid path was:fish", ex.Message); + Assert.That(ex.Message, Is.EqualTo(@"All catalogue paths must start with \. Invalid path was:fish")); } finally { @@ -348,9 +357,8 @@ public void CatalogueFolder_CannotSetToNull() try { var ex = Assert.Throws(() => c.Folder = null); - Assert.AreEqual( - @"An attempt was made to set Catalogue Folder to null, every Catalogue must have a folder, set it to \ if you want the root", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo(@"An attempt was made to set Catalogue Folder to null, every Catalogue must have a folder, set it to \ if you want the root")); } finally { @@ -366,8 +374,7 @@ public void CatalogueFolder_CannotHaveDoubleSlashes() { //notice the @ symbol that makes the double slashes actual double slashes - common error we might make and what this test is designed to prevent var ex = Assert.Throws(() => c.Folder = @"\\bob\\"); - Assert.AreEqual(@"Catalogue paths cannot contain double slashes '\\', Invalid path was:\\bob\\", - ex.Message); + Assert.That(ex.Message, Is.EqualTo(@"Catalogue paths cannot contain double slashes '\\', Invalid path was:\\bob\\")); } finally { @@ -381,7 +388,7 @@ public void RelatedCatalogueTest_NoCatalogues() var t = new TableInfo(Repository, "MyTable"); try { - Assert.AreEqual(0, t.GetAllRelatedCatalogues().Length); + Assert.That(t.GetAllRelatedCatalogues(), Is.Empty); } finally { @@ -408,8 +415,8 @@ public void RelatedCatalogueTest_OneCatalogue(bool createExtractionInformation) ci.SetColumnInfo(c); var catas = t.GetAllRelatedCatalogues(); - Assert.AreEqual(1, catas.Length); - Assert.AreEqual(cata, catas[0]); + Assert.That(catas, Has.Length.EqualTo(1)); + Assert.That(catas[0], Is.EqualTo(cata)); } finally { @@ -454,9 +461,9 @@ public void RelatedCatalogueTest_TwoCatalogues_TwoColumnsEach(bool createExtract var catas = t.GetAllRelatedCatalogues(); - Assert.AreEqual(2, catas.Length); - Assert.IsTrue(catas.Contains(cata1)); - Assert.IsTrue(catas.Contains(cata2)); + Assert.That(catas, Has.Length.EqualTo(2)); + Assert.That(catas, Does.Contain(cata1)); + Assert.That(catas, Does.Contain(cata2)); } finally { @@ -481,15 +488,18 @@ public void TestTreeNode_FullName_CleanPaths(string fullName, string expectedNam while (bottomFolder.ChildFolders.Any()) bottomFolder = bottomFolder.ChildFolders.Single(); - Assert.AreEqual(expectedName, bottomFolder.Name); - Assert.AreEqual(fullName, bottomFolder.FullName); + Assert.Multiple(() => + { + Assert.That(bottomFolder.Name, Is.EqualTo(expectedName)); + Assert.That(bottomFolder.FullName, Is.EqualTo(fullName)); + }); } [TestCase("\\admissions\\", "\\admissions")] [TestCase("\\ADMissions\\", "\\admissions")] public void TestFolderHelperAdjust(string input, string expectedOutput) { - Assert.AreEqual(expectedOutput, FolderHelper.Adjust(input)); + Assert.That(FolderHelper.Adjust(input), Is.EqualTo(expectedOutput)); } [Test] @@ -518,13 +528,16 @@ public void TestBuildFolderTree() var tree = FolderHelper.BuildFolderTree(objects); - Assert.Contains(r1, tree.ChildObjects); - Assert.Contains(r2, tree.ChildObjects); + Assert.That(tree.ChildObjects, Does.Contain(r1)); + Assert.Multiple(() => + { + Assert.That(tree.ChildObjects, Does.Contain(r2)); - Assert.Contains(cat, tree["dog"]["fish"]["cat"].ChildObjects); + Assert.That(tree["dog"]["fish"]["cat"].ChildObjects, Does.Contain(cat)); - Assert.Contains(fun, tree["fun"].ChildObjects); - Assert.Contains(morefun, tree["fun"].ChildObjects); + Assert.That(tree["fun"].ChildObjects, Does.Contain(fun)); + }); + Assert.That(tree["fun"].ChildObjects, Does.Contain(morefun)); } @@ -551,13 +564,16 @@ public void TestBuildFolderTree_MiddleBranches() }; var tree = FolderHelper.BuildFolderTree(objects); - Assert.IsEmpty(tree.ChildObjects, "Should be no Catalogues on the root"); + Assert.Multiple(() => + { + Assert.That(tree.ChildObjects, Is.Empty, "Should be no Catalogues on the root"); - Assert.AreEqual(1, tree.ChildFolders.Count); - Assert.AreEqual(1, tree["somefolder"].ChildFolders.Count); - Assert.IsEmpty(tree["somefolder"]["somesub"].ChildFolders); + Assert.That(tree.ChildFolders, Has.Count.EqualTo(1)); + Assert.That(tree["somefolder"].ChildFolders, Has.Count.EqualTo(1)); + Assert.That(tree["somefolder"]["somesub"].ChildFolders, Is.Empty); - Assert.Contains(cata1, tree["somefolder"].ChildObjects); - Assert.Contains(cata2, tree["somefolder"]["somesub"].ChildObjects); + Assert.That(tree["somefolder"].ChildObjects, Does.Contain(cata1)); + Assert.That(tree["somefolder"]["somesub"].ChildObjects, Does.Contain(cata2)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/ColumnInfoTests.cs b/Rdmp.Core.Tests/Curation/Integration/ColumnInfoTests.cs index bf34a0f17f..a027b42cf0 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ColumnInfoTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ColumnInfoTests.cs @@ -5,7 +5,6 @@ // You should have received a copy of the GNU General Public License along with RDMP. If not, see . using System.Collections.Generic; -using System.Linq; using NUnit.Framework; using Rdmp.Core.Curation.Data; using Rdmp.Core.Curation.Data.DataLoad; @@ -36,11 +35,14 @@ public void CreateNewColumnInfoInDatabase_NewColumns_NewColumnsAreEqualAfterSave var childAfter = CatalogueRepository.GetObjectByID(child.ID); - Assert.AreEqual(child.Name, childAfter.Name); - Assert.AreEqual(child.Description, childAfter.Description); - Assert.AreEqual(child.Status, childAfter.Status); - Assert.AreEqual(child.RegexPattern, childAfter.RegexPattern); - Assert.AreEqual(child.ValidationRules, childAfter.ValidationRules); + Assert.Multiple(() => + { + Assert.That(childAfter.Name, Is.EqualTo(child.Name)); + Assert.That(childAfter.Description, Is.EqualTo(child.Description)); + Assert.That(childAfter.Status, Is.EqualTo(child.Status)); + Assert.That(childAfter.RegexPattern, Is.EqualTo(child.RegexPattern)); + Assert.That(childAfter.ValidationRules, Is.EqualTo(child.ValidationRules)); + }); } finally { @@ -60,7 +62,7 @@ public void GetAllColumnInfos_moreThan1_pass() try { - Assert.IsTrue(CatalogueRepository.GetAllObjectsWithParent(parent).Length == 1); + Assert.That(CatalogueRepository.GetAllObjectsWithParent(parent), Has.Length.EqualTo(1)); } finally { @@ -79,13 +81,13 @@ public void CreateNewColumnInfoInDatabase_valid_pass() var parent = new TableInfo(CatalogueRepository, "Lazors"); var columnInfo = new ColumnInfo(CatalogueRepository, "Lazor Reflection Vol", "varchar(1000)", parent); - Assert.NotNull(columnInfo); + Assert.That(columnInfo, Is.Not.Null); columnInfo.DeleteInDatabase(); var ex = Assert.Throws(() => CatalogueRepository.GetObjectByID(columnInfo.ID)); - Assert.IsTrue(ex.Message.StartsWith($"Could not find ColumnInfo with ID {columnInfo.ID}"), ex.Message); + Assert.That(ex.Message, Does.StartWith($"Could not find ColumnInfo with ID {columnInfo.ID}"), ex.Message); parent.DeleteInDatabase(); } @@ -107,11 +109,14 @@ public void update_changeAllProperties_pass() var columnAfter = CatalogueRepository.GetObjectByID(column.ID); - Assert.IsTrue(columnAfter.Digitisation_specs == "Highly digitizable"); - Assert.IsTrue(columnAfter.Format == "Jpeg"); - Assert.IsTrue(columnAfter.Name == "mycol"); - Assert.IsTrue(columnAfter.Source == "Bazooka"); - Assert.IsTrue(columnAfter.Data_type == "Whatever"); + Assert.Multiple(() => + { + Assert.That(columnAfter.Digitisation_specs, Is.EqualTo("Highly digitizable")); + Assert.That(columnAfter.Format, Is.EqualTo("Jpeg")); + Assert.That(columnAfter.Name, Is.EqualTo("mycol")); + Assert.That(columnAfter.Source, Is.EqualTo("Bazooka")); + Assert.That(columnAfter.Data_type, Is.EqualTo("Whatever")); + }); columnAfter.DeleteInDatabase(); parent.DeleteInDatabase(); @@ -130,9 +135,12 @@ public void Test_GetRAWStageTypeWhenPreLoadDiscardedDilution() }; discard.SaveToDatabase(); - Assert.AreEqual("varchar(4)", column.GetRuntimeDataType(LoadStage.PostLoad)); - Assert.AreEqual("varchar(4)", column.GetRuntimeDataType(LoadStage.AdjustStaging)); - Assert.AreEqual("varchar(10)", column.GetRuntimeDataType(LoadStage.AdjustRaw)); + Assert.Multiple(() => + { + Assert.That(column.GetRuntimeDataType(LoadStage.PostLoad), Is.EqualTo("varchar(4)")); + Assert.That(column.GetRuntimeDataType(LoadStage.AdjustStaging), Is.EqualTo("varchar(4)")); + Assert.That(column.GetRuntimeDataType(LoadStage.AdjustRaw), Is.EqualTo("varchar(10)")); + }); discard.DeleteInDatabase(); parent.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/Curation/Integration/CommitInProgressTests.cs b/Rdmp.Core.Tests/Curation/Integration/CommitInProgressTests.cs index 548c0ce1ce..a62049e88a 100644 --- a/Rdmp.Core.Tests/Curation/Integration/CommitInProgressTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/CommitInProgressTests.cs @@ -28,17 +28,17 @@ public void CommitInProgress_CatalogueModify() var activator = new ThrowImmediatelyActivator(RepositoryLocator); - Assert.IsNull(start.TryFinish(activator), "No changes made to Catalogue so expected no commit"); + Assert.That(start.TryFinish(activator), Is.Null, "No changes made to Catalogue so expected no commit"); c.Name = "abadaba"; c.IsDeprecated = true; c.SaveToDatabase(); var commit = start.TryFinish(activator); - Assert.IsNotNull(commit); + Assert.That(commit, Is.Not.Null); - Assert.AreEqual(1, commit.Mementos.Length); - Assert.AreNotEqual(commit.Mementos[0].BeforeYaml, commit.Mementos[0].AfterYaml); + Assert.That(commit.Mementos, Has.Length.EqualTo(1)); + Assert.That(commit.Mementos[0].AfterYaml, Is.Not.EqualTo(commit.Mementos[0].BeforeYaml)); } /// @@ -51,7 +51,7 @@ public void CommitInProgress_TestCancellation() { var c = new Catalogue(CatalogueRepository, "Hey"); - Assert.AreEqual(ChangeDescription.NoChanges, c.HasLocalChanges().Evaluation, + Assert.That(c.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.NoChanges), "We just created this Catalogue, how can db copy be different?!"); var start = new CommitInProgress(RepositoryLocator, new CommitInProgressSettings(c) @@ -63,22 +63,22 @@ public void CommitInProgress_TestCancellation() c.Name = "abadaba"; c.IsDeprecated = true; - Assert.AreEqual(ChangeDescription.DatabaseCopyDifferent, c.HasLocalChanges().Evaluation, + Assert.That(c.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.DatabaseCopyDifferent), "We have local changes"); c.SaveToDatabase(); - Assert.AreEqual(ChangeDescription.NoChanges, c.HasLocalChanges().Evaluation, + Assert.That(c.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.NoChanges), "Should be saved inside the transaction"); // abandon the commit start.Dispose(); - Assert.AreEqual(ChangeDescription.DatabaseCopyDifferent, c.HasLocalChanges().Evaluation, + Assert.That(c.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.DatabaseCopyDifferent), "With transaction rolled back the Catalogue should now no longer match db state - i.e. be unsaved"); c.RevertToDatabaseState(); - Assert.AreEqual("Hey", c.Name); + Assert.That(c.Name, Is.EqualTo("Hey")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/ComprehensiveQueryPerformanceCounterTests.cs b/Rdmp.Core.Tests/Curation/Integration/ComprehensiveQueryPerformanceCounterTests.cs index ef637d7f68..944f91c130 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ComprehensiveQueryPerformanceCounterTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ComprehensiveQueryPerformanceCounterTests.cs @@ -29,10 +29,10 @@ public void TestPerformance() //send some queries var cata = new Catalogue(CatalogueRepository, "Fish"); - Assert.IsTrue(cata.Name.Equals("Fish")); + Assert.That(cata.Name, Is.EqualTo("Fish")); var commands = pCounter.DictionaryOfQueries.Values.ToArray(); - Assert.IsTrue(commands.Any(c => c.QueryText.Contains("SELECT * FROM [Catalogue] WHERE ID="))); + Assert.That(commands.Any(c => c.QueryText.Contains("SELECT * FROM [Catalogue] WHERE ID="))); cata.DeleteInDatabase(); } diff --git a/Rdmp.Core.Tests/Curation/Integration/CredentialsTests.cs b/Rdmp.Core.Tests/Curation/Integration/CredentialsTests.cs index ed1d188bab..4df4f93163 100644 --- a/Rdmp.Core.Tests/Curation/Integration/CredentialsTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/CredentialsTests.cs @@ -56,8 +56,11 @@ public void CreateNewCredentials() try { - Assert.AreEqual("bob", newCredentials.Name); - Assert.AreNotEqual(0, newCredentials.ID); + Assert.Multiple(() => + { + Assert.That(newCredentials.Name, Is.EqualTo("bob")); + Assert.That(newCredentials.ID, Is.Not.EqualTo(0)); + }); } finally { @@ -79,15 +82,18 @@ public void CreateNewCredentialsThenGetByUsernamePasswordCombo() var newCopy = CatalogueRepository.GetAllObjects() .SingleOrDefault(c => c.Username == "myusername"); - Assert.IsNotNull(newCopy); + Assert.That(newCopy, Is.Not.Null); try { - Assert.NotNull(newCopy); - Assert.AreEqual(newCredentials.ID, newCopy.ID); - Assert.AreEqual(newCredentials.Username, newCopy.Username); - Assert.AreEqual(newCredentials.GetDecryptedPassword(), newCopy.GetDecryptedPassword()); - Assert.AreEqual(newCredentials.Password, newCopy.Password); + Assert.That(newCopy, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(newCopy.ID, Is.EqualTo(newCredentials.ID)); + Assert.That(newCopy.Username, Is.EqualTo(newCredentials.Username)); + Assert.That(newCopy.GetDecryptedPassword(), Is.EqualTo(newCredentials.GetDecryptedPassword())); + Assert.That(newCopy.Password, Is.EqualTo(newCredentials.Password)); + }); } finally { @@ -114,7 +120,7 @@ public void TestThe_Any_EnumValue_CannotRequestAnyCredentials() //attempt to request ANY credentials var ex = Assert.Throws(() => tableInfo.GetCredentialsIfExists(DataAccessContext.Any)); - Assert.AreEqual("You cannot ask for any credentials, you must supply a usage context.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("You cannot ask for any credentials, you must supply a usage context.")); } finally { @@ -143,11 +149,11 @@ public void TestThe_Any_EnumValue() //because the credential is liscenced to be used under ANY context, you can make requests under any of the specific contexts and be served the Any result var creds2 = tableInfo.GetCredentialsIfExists(DataAccessContext.InternalDataProcessing); - Assert.NotNull(creds2); + Assert.That(creds2, Is.Not.Null); creds2 = tableInfo.GetCredentialsIfExists(DataAccessContext.DataExport); - Assert.NotNull(creds2); + Assert.That(creds2, Is.Not.Null); creds2 = tableInfo.GetCredentialsIfExists(DataAccessContext.DataLoad); - Assert.NotNull(creds2); + Assert.That(creds2, Is.Not.Null); } finally { @@ -178,7 +184,7 @@ public void Test_Any_PrioritisingTheMoreAppropriateCredential() tableInfo.SetCredentials(creds2, DataAccessContext.Any); - Assert.AreEqual(creds, tableInfo.GetCredentialsIfExists(DataAccessContext.DataLoad)); + Assert.That(tableInfo.GetCredentialsIfExists(DataAccessContext.DataLoad), Is.EqualTo(creds)); } finally { @@ -201,14 +207,17 @@ public void SaveAndReloadCredentials() originalCredentials.SaveToDatabase(); var newCopy = CatalogueRepository.GetObjectByID(originalCredentials.ID); - Assert.AreEqual(originalCredentials.Name, newCopy.Name); - Assert.AreEqual(originalCredentials.Username, newCopy.Username); - Assert.AreEqual(originalCredentials.Password, newCopy.Password); + Assert.Multiple(() => + { + Assert.That(newCopy.Name, Is.EqualTo(originalCredentials.Name)); + Assert.That(newCopy.Username, Is.EqualTo(originalCredentials.Username)); + Assert.That(newCopy.Password, Is.EqualTo(originalCredentials.Password)); - //test overridden Equals - Assert.AreEqual(originalCredentials, newCopy); + //test overridden Equals + Assert.That(newCopy, Is.EqualTo(originalCredentials)); + }); originalCredentials.Password = "fish"; - Assert.AreEqual(originalCredentials, newCopy); //they are still equal because IDs are the same + Assert.That(newCopy, Is.EqualTo(originalCredentials)); //they are still equal because IDs are the same } finally { @@ -236,7 +245,7 @@ public void GetCredentialsFromATableInfo() //Go via TableInfo and get credentials var creds2 = (DataAccessCredentials)tableInfo.GetCredentialsIfExists(DataAccessContext.InternalDataProcessing); - Assert.AreEqual(creds2.Name, creds.Name); + Assert.That(creds.Name, Is.EqualTo(creds2.Name)); } finally { @@ -262,9 +271,8 @@ public void Create2TableInfosThatShareTheSameCredentialAndTestDeletingIt_ThrowsT var ex = Assert.Throws(creds .DeleteInDatabase); //the bit that fails (because tables are there) - Assert.AreEqual( - "Cannot delete credentials bob because it is in use by one or more TableInfo objects(Dependency1,Dependency2)", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Cannot delete credentials bob because it is in use by one or more TableInfo objects(Dependency1,Dependency2)")); } finally { @@ -293,8 +301,8 @@ public void GetAllUsersOfACredential() var TablesThatUseCredential = creds.GetAllTableInfosThatUseThis()[DataAccessContext.InternalDataProcessing].ToArray(); - Assert.Contains(tableInfo1, TablesThatUseCredential); - Assert.Contains(tableInfo2, TablesThatUseCredential); + Assert.That(TablesThatUseCredential, Does.Contain(tableInfo1)); + Assert.That(TablesThatUseCredential, Does.Contain(tableInfo2)); tableInfo1.DeleteInDatabase(); tableInfo2.DeleteInDatabase(); @@ -325,8 +333,11 @@ public void GetConnectionStringFromCatalogueWhereOneTableInfoUsesACredentialsOve Password = "pass" }; - Assert.AreNotEqual("pass", cred.Password); - Assert.AreEqual("pass", cred.GetDecryptedPassword()); + Assert.Multiple(() => + { + Assert.That(cred.Password, Is.Not.EqualTo("pass")); + Assert.That(cred.GetDecryptedPassword(), Is.EqualTo("pass")); + }); cred.SaveToDatabase(); @@ -336,10 +347,13 @@ public void GetConnectionStringFromCatalogueWhereOneTableInfoUsesACredentialsOve var constr = (SqlConnectionStringBuilder)c .GetDistinctLiveDatabaseServer(DataAccessContext.InternalDataProcessing, false).Builder; - Assert.AreEqual("myserver", constr.DataSource); - Assert.False(constr.IntegratedSecurity); - Assert.AreEqual("bob", constr.UserID); - Assert.AreEqual("pass", constr.Password); + Assert.Multiple(() => + { + Assert.That(constr.DataSource, Is.EqualTo("myserver")); + Assert.That(constr.IntegratedSecurity, Is.False); + Assert.That(constr.UserID, Is.EqualTo("bob")); + Assert.That(constr.Password, Is.EqualTo("pass")); + }); } finally { @@ -362,8 +376,11 @@ public void Test_BlankPasswords() var manager = new TableInfoCredentialsManager(CatalogueTableRepository); - Assert.AreEqual(creds, manager.GetCredentialByUsernameAndPasswordIfExists("Root", null)); - Assert.AreEqual(creds, manager.GetCredentialByUsernameAndPasswordIfExists("Root", "")); + Assert.Multiple(() => + { + Assert.That(manager.GetCredentialByUsernameAndPasswordIfExists("Root", null), Is.EqualTo(creds)); + Assert.That(manager.GetCredentialByUsernameAndPasswordIfExists("Root", ""), Is.EqualTo(creds)); + }); } [Test] @@ -379,9 +396,12 @@ public void Test_NoDuplicatePasswords() var cred = credentialsFactory.Create(t1, "blarg", "flarg", DataAccessContext.Any); var cred2 = credentialsFactory.Create(t2, "blarg", "flarg", DataAccessContext.Any); - Assert.AreEqual(credCount + 1, CatalogueRepository.GetAllObjects().Length); + Assert.Multiple(() => + { + Assert.That(CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(credCount + 1)); - Assert.AreEqual(cred, cred2, - $"Expected {nameof(DataAccessCredentialsFactory)} to reuse existing credentials for both tables as they have the same username/password - e.g. bulk insert"); + Assert.That(cred2, Is.EqualTo(cred), + $"Expected {nameof(DataAccessCredentialsFactory)} to reuse existing credentials for both tables as they have the same username/password - e.g. bulk insert"); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/CrossDatabaseTriggerTests.cs b/Rdmp.Core.Tests/Curation/Integration/CrossDatabaseTriggerTests.cs index 0d0449ea3c..132b0ed281 100644 --- a/Rdmp.Core.Tests/Curation/Integration/CrossDatabaseTriggerTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/CrossDatabaseTriggerTests.cs @@ -35,9 +35,12 @@ public void TriggerImplementationTest(DatabaseType type) var factory = new TriggerImplementerFactory(type); var implementer = factory.Create(tbl); - Assert.AreEqual(TriggerStatus.Missing, implementer.GetTriggerStatus()); + Assert.Multiple(() => + { + Assert.That(implementer.GetTriggerStatus(), Is.EqualTo(TriggerStatus.Missing)); - Assert.AreEqual(2, tbl.DiscoverColumns().Length); + Assert.That(tbl.DiscoverColumns(), Has.Length.EqualTo(2)); + }); implementer = factory.Create(tbl); @@ -50,31 +53,33 @@ public void TriggerImplementationTest(DatabaseType type) implementer.CreateTrigger(ThrowImmediatelyCheckNotifier.Quiet); - Assert.AreEqual(4, tbl.DiscoverColumns().Length); + Assert.That(tbl.DiscoverColumns(), Has.Length.EqualTo(4)); var archiveTable = tbl.Database.ExpectTable($"{tbl.GetRuntimeName()}_Archive"); - Assert.IsTrue(archiveTable.Exists()); - - Assert.AreEqual(7, archiveTable.DiscoverColumns().Length); - - Assert.AreEqual(1, archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("name"))); - Assert.AreEqual(1, archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("bubbles"))); - Assert.AreEqual(1, - archiveTable.DiscoverColumns().Count(c => - c.GetRuntimeName().Equals("hic_dataLoadrunID", StringComparison.CurrentCultureIgnoreCase))); - Assert.AreEqual(1, - archiveTable.DiscoverColumns().Count(c => - c.GetRuntimeName().Equals("hic_validFrom", StringComparison.CurrentCultureIgnoreCase))); - Assert.AreEqual(1, - archiveTable.DiscoverColumns().Count(c => - c.GetRuntimeName().Equals("hic_validTo", StringComparison.CurrentCultureIgnoreCase))); - Assert.AreEqual(1, - archiveTable.DiscoverColumns().Count(c => - c.GetRuntimeName().Equals("hic_userID", StringComparison.CurrentCultureIgnoreCase))); - Assert.AreEqual(1, archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("hic_status"))); - - //is the trigger now existing - Assert.AreEqual(TriggerStatus.Enabled, implementer.GetTriggerStatus()); + Assert.Multiple(() => + { + Assert.That(archiveTable.Exists()); + + Assert.That(archiveTable.DiscoverColumns(), Has.Length.EqualTo(7)); + }); + + Assert.Multiple(() => + { + Assert.That(archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("name")), Is.EqualTo(1)); + Assert.That(archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("bubbles")), Is.EqualTo(1)); + Assert.That(archiveTable.DiscoverColumns().Count(c => + c.GetRuntimeName().Equals("hic_dataLoadrunID", StringComparison.CurrentCultureIgnoreCase)), Is.EqualTo(1)); + Assert.That(archiveTable.DiscoverColumns().Count(c => + c.GetRuntimeName().Equals("hic_validFrom", StringComparison.CurrentCultureIgnoreCase)), Is.EqualTo(1)); + Assert.That(archiveTable.DiscoverColumns().Count(c => + c.GetRuntimeName().Equals("hic_validTo", StringComparison.CurrentCultureIgnoreCase)), Is.EqualTo(1)); + Assert.That(archiveTable.DiscoverColumns().Count(c => + c.GetRuntimeName().Equals("hic_userID", StringComparison.CurrentCultureIgnoreCase)), Is.EqualTo(1)); + Assert.That(archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("hic_status")), Is.EqualTo(1)); + + //is the trigger now existing + Assert.That(implementer.GetTriggerStatus(), Is.EqualTo(TriggerStatus.Enabled)); + }); //does it function as expected using (var con = tbl.Database.Server.GetConnection()) @@ -84,23 +89,29 @@ public void TriggerImplementationTest(DatabaseType type) $"INSERT INTO {tbl.GetRuntimeName()}(name,bubbles) VALUES('bob',1)", con); cmd.ExecuteNonQuery(); - Assert.AreEqual(1, tbl.GetRowCount()); - Assert.AreEqual(0, archiveTable.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(tbl.GetRowCount(), Is.EqualTo(1)); + Assert.That(archiveTable.GetRowCount(), Is.EqualTo(0)); + }); cmd = tbl.Database.Server.GetCommand($"UPDATE {tbl.GetRuntimeName()} set bubbles=2", con); cmd.ExecuteNonQuery(); - Assert.AreEqual(1, tbl.GetRowCount()); - Assert.AreEqual(1, archiveTable.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(tbl.GetRowCount(), Is.EqualTo(1)); + Assert.That(archiveTable.GetRowCount(), Is.EqualTo(1)); + }); var archive = archiveTable.GetDataTable(); var dr = archive.Rows.Cast().Single(); - Assert.AreEqual(((DateTime)dr["hic_validTo"]).Date, DateTime.Now.Date); + Assert.That(DateTime.Now.Date, Is.EqualTo(((DateTime)dr["hic_validTo"]).Date)); } //do the strict check too - Assert.IsTrue(implementer.CheckUpdateTriggerIsEnabledAndHasExpectedBody()); + Assert.That(implementer.CheckUpdateTriggerIsEnabledAndHasExpectedBody()); tbl.AddColumn("amagad", new DatabaseTypeRequest(typeof(float), null, new DecimalSize(2, 2)), true, 30); implementer = factory.Create(tbl); @@ -113,7 +124,7 @@ public void TriggerImplementationTest(DatabaseType type) var checks = new TriggerChecks(tbl); checks.Check(new AcceptAllCheckNotifier()); - Assert.IsTrue(implementer.CheckUpdateTriggerIsEnabledAndHasExpectedBody()); + Assert.That(implementer.CheckUpdateTriggerIsEnabledAndHasExpectedBody()); //does it function as expected @@ -121,8 +132,11 @@ public void TriggerImplementationTest(DatabaseType type) { con.Open(); - Assert.AreEqual(1, tbl.GetRowCount()); - Assert.AreEqual(1, archiveTable.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(tbl.GetRowCount(), Is.EqualTo(1)); + Assert.That(archiveTable.GetRowCount(), Is.EqualTo(1)); + }); var cmd = tbl.Database.Server.GetCommand($"UPDATE {tbl.GetRuntimeName()} set amagad=1.0", con); cmd.ExecuteNonQuery(); @@ -130,18 +144,27 @@ public void TriggerImplementationTest(DatabaseType type) cmd = tbl.Database.Server.GetCommand($"UPDATE {tbl.GetRuntimeName()} set amagad=.09", con); cmd.ExecuteNonQuery(); - Assert.AreEqual(1, tbl.GetRowCount()); - Assert.AreEqual(3, archiveTable.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(tbl.GetRowCount(), Is.EqualTo(1)); + Assert.That(archiveTable.GetRowCount(), Is.EqualTo(3)); + }); var archive = archiveTable.GetDataTable(); - Assert.AreEqual(1, archive.Rows.Cast().Count(r => Equals(r["amagad"], (decimal)1.00))); - Assert.AreEqual(2, archive.Rows.Cast().Count(r => r["amagad"] == DBNull.Value)); + Assert.Multiple(() => + { + Assert.That(archive.Rows.Cast().Count(r => Equals(r["amagad"], (decimal)1.00)), Is.EqualTo(1)); + Assert.That(archive.Rows.Cast().Count(r => r["amagad"] == DBNull.Value), Is.EqualTo(2)); + }); } implementer.DropTrigger(out var problems, out _); - Assert.IsTrue(string.IsNullOrEmpty(problems)); + Assert.Multiple(() => + { + Assert.That(string.IsNullOrEmpty(problems)); - Assert.AreEqual(TriggerStatus.Missing, implementer.GetTriggerStatus()); + Assert.That(implementer.GetTriggerStatus(), Is.EqualTo(TriggerStatus.Missing)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/DataAccess/SuperMultiThreadedVolumeAccess.cs b/Rdmp.Core.Tests/Curation/Integration/DataAccess/SuperMultiThreadedVolumeAccess.cs index a04e7d098e..8f40cd8d21 100644 --- a/Rdmp.Core.Tests/Curation/Integration/DataAccess/SuperMultiThreadedVolumeAccess.cs +++ b/Rdmp.Core.Tests/Curation/Integration/DataAccess/SuperMultiThreadedVolumeAccess.cs @@ -71,10 +71,10 @@ public void SingleThreadedBulkCatalogueCreation(bool useTransactions) var copy = CatalogueRepository.GetObjectByID(cata.ID); copy.Description = "fish"; - Assert.IsTrue(copy.HasLocalChanges().Evaluation == ChangeDescription.DatabaseCopyDifferent); + Assert.That(copy.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.DatabaseCopyDifferent)); copy.SaveToDatabase(); - Assert.IsTrue(copy.HasLocalChanges().Evaluation == ChangeDescription.NoChanges); + Assert.That(copy.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.NoChanges)); } //now fetch them out of database lots of times @@ -102,7 +102,7 @@ public void SimpleCaseSingleThreaded(bool useTransaction) using var con = useTransaction ? CatalogueTableRepository.BeginNewTransactedConnection() : CatalogueTableRepository.GetConnection(); - Assert.AreEqual(ConnectionState.Open, con.Connection.State); + Assert.That(con.Connection.State, Is.EqualTo(ConnectionState.Open)); Thread.Sleep(1000); if (useTransaction) @@ -110,7 +110,7 @@ public void SimpleCaseSingleThreaded(bool useTransaction) else con.Connection.Close(); - Assert.AreEqual(ConnectionState.Closed, con.Connection.State); + Assert.That(con.Connection.State, Is.EqualTo(ConnectionState.Closed)); } [Test] @@ -154,6 +154,6 @@ private void FireMultiThreaded(Action method, int numberToFire, bool useTr while (ts.Any(t => t.IsAlive)) ts.FirstOrDefault(t => t.IsAlive)?.Join(100); - Assert.IsEmpty(exes); + Assert.That(exes, Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/DataAccess/TestDataAccess.cs b/Rdmp.Core.Tests/Curation/Integration/DataAccess/TestDataAccess.cs index 62cebe110f..dd8d080b44 100644 --- a/Rdmp.Core.Tests/Curation/Integration/DataAccess/TestDataAccess.cs +++ b/Rdmp.Core.Tests/Curation/Integration/DataAccess/TestDataAccess.cs @@ -41,7 +41,7 @@ public void TestDistinctCredentials_PasswordMismatch() var ex = Assert.Throws(() => DataAccessPortal.ExpectDistinctServer(testPoints.ToArray(), DataAccessContext.InternalDataProcessing, true)); - StringAssert.Contains("collection could not agree on a single Password", ex.Message); + Assert.That(ex.Message, Does.Contain("collection could not agree on a single Password")); } [Test] @@ -57,7 +57,7 @@ public void TestDistinctCredentials_UsernamePasswordAreNull() var ex = Assert.Throws(() => DataAccessPortal.ExpectDistinctServer(testPoints.ToArray(), DataAccessContext.InternalDataProcessing, true)); - StringAssert.Contains("collection could not agree whether to use Credentials", ex.Message); + Assert.That(ex.Message, Does.Contain("collection could not agree whether to use Credentials")); } [Test] @@ -74,7 +74,7 @@ public void TestDistinctCredentials_UsernameMismatch() var ex = Assert.Throws(() => DataAccessPortal.ExpectDistinctServer(testPoints.ToArray(), DataAccessContext.InternalDataProcessing, true)); - StringAssert.Contains("collection could not agree on a single Username", ex.Message); + Assert.That(ex.Message, Does.Contain("collection could not agree on a single Username")); } @@ -89,7 +89,7 @@ public void TestDistinctCredentials_ServerMixedCapitalization_Allowed() var server = DataAccessPortal.ExpectDistinctServer(testPoints.ToArray(), DataAccessContext.InternalDataProcessing, true); - Assert.AreEqual("frank", server.Name); + Assert.That(server.Name, Is.EqualTo("frank")); } [Test] @@ -104,9 +104,8 @@ public void TestDistinctCredentials_DatabaseMixedCapitalization_NotAllowed() var ex = Assert.Throws(() => DataAccessPortal.ExpectDistinctServer(testPoints.ToArray(), DataAccessContext.InternalDataProcessing, true)); - StringAssert.Contains( - "All data access points must be into the same database, access points 'frankbob' and 'frankBOB' are into different databases", - ex.Message); + Assert.That( + ex.Message, Does.Contain("All data access points must be into the same database, access points 'frankbob' and 'frankBOB' are into different databases")); } #endregion @@ -127,7 +126,7 @@ public void TestDistinctCredentials_WrappedDatabaseName() DataAccessPortal.ExpectDistinctServer(testPoints.ToArray(), DataAccessContext.InternalDataProcessing, true); //test result - Assert.AreEqual("bob's Database", result.Builder["Initial Catalog"]); + Assert.That(result.Builder["Initial Catalog"], Is.EqualTo("bob's Database")); } [Test] @@ -144,7 +143,7 @@ public void TestDistinctCredentials_PasswordMatch() DataAccessPortal.ExpectDistinctServer(testPoints.ToArray(), DataAccessContext.InternalDataProcessing, true); //test result - Assert.AreEqual("mypas", result.Builder["Password"]); + Assert.That(result.Builder["Password"], Is.EqualTo("mypas")); } #endregion @@ -174,7 +173,7 @@ public void AsyncTest() Console.WriteLine(ExceptionHelper.ExceptionToListOfInnerMessages(asyncException, true)); } - Assert.IsEmpty(asyncExceptions); + Assert.That(asyncExceptions, Is.Empty); } private List asyncExceptions = new(); @@ -223,10 +222,13 @@ public void TestGettingConnectionStrings() //t has no credentials var server = DataAccessPortal.ExpectServer(t, DataAccessContext.InternalDataProcessing); - Assert.AreEqual(typeof(SqlConnectionStringBuilder), server.Builder.GetType()); - Assert.AreEqual("fish", ((SqlConnectionStringBuilder)server.Builder).DataSource); - Assert.AreEqual("bobsDatabase", ((SqlConnectionStringBuilder)server.Builder).InitialCatalog); - Assert.AreEqual(true, ((SqlConnectionStringBuilder)server.Builder).IntegratedSecurity); + Assert.Multiple(() => + { + Assert.That(server.Builder.GetType(), Is.EqualTo(typeof(SqlConnectionStringBuilder))); + Assert.That(((SqlConnectionStringBuilder)server.Builder).DataSource, Is.EqualTo("fish")); + Assert.That(((SqlConnectionStringBuilder)server.Builder).InitialCatalog, Is.EqualTo("bobsDatabase")); + Assert.That(((SqlConnectionStringBuilder)server.Builder).IntegratedSecurity, Is.EqualTo(true)); + }); var creds = new DataAccessCredentials(CatalogueRepository, "Bob"); try @@ -242,12 +244,15 @@ public void TestGettingConnectionStrings() ////t has some credentials now server = DataAccessPortal.ExpectServer(t, DataAccessContext.InternalDataProcessing); - Assert.AreEqual(typeof(SqlConnectionStringBuilder), server.Builder.GetType()); - Assert.AreEqual("fish", ((SqlConnectionStringBuilder)server.Builder).DataSource); - Assert.AreEqual("bobsDatabase", ((SqlConnectionStringBuilder)server.Builder).InitialCatalog); - Assert.AreEqual("frank", ((SqlConnectionStringBuilder)server.Builder).UserID); - Assert.AreEqual("bobsPassword", ((SqlConnectionStringBuilder)server.Builder).Password); - Assert.AreEqual(false, ((SqlConnectionStringBuilder)server.Builder).IntegratedSecurity); + Assert.Multiple(() => + { + Assert.That(server.Builder.GetType(), Is.EqualTo(typeof(SqlConnectionStringBuilder))); + Assert.That(((SqlConnectionStringBuilder)server.Builder).DataSource, Is.EqualTo("fish")); + Assert.That(((SqlConnectionStringBuilder)server.Builder).InitialCatalog, Is.EqualTo("bobsDatabase")); + Assert.That(((SqlConnectionStringBuilder)server.Builder).UserID, Is.EqualTo("frank")); + Assert.That(((SqlConnectionStringBuilder)server.Builder).Password, Is.EqualTo("bobsPassword")); + Assert.That(((SqlConnectionStringBuilder)server.Builder).IntegratedSecurity, Is.EqualTo(false)); + }); } finally { diff --git a/Rdmp.Core.Tests/Curation/Integration/Dependencies/DependencyTests.cs b/Rdmp.Core.Tests/Curation/Integration/Dependencies/DependencyTests.cs index eb17a931b2..49b686e0e1 100644 --- a/Rdmp.Core.Tests/Curation/Integration/Dependencies/DependencyTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/Dependencies/DependencyTests.cs @@ -24,20 +24,23 @@ public void ExtractionInformationTriangle() try { - //col depends on tr - Assert.Contains(t, col.GetObjectsThisDependsOn()); - Assert.Contains(col, t.GetObjectsDependingOnThis()); + Assert.Multiple(() => + { + //col depends on tr + Assert.That(col.GetObjectsThisDependsOn(), Does.Contain(t)); + Assert.That(t.GetObjectsDependingOnThis(), Does.Contain(col)); - //catalogue depends on catalogue items existing (slightly counter intuitive but think of it as data flow out of technical low level data through transforms into datasets - and then into researchers and research projects) - Assert.Contains(cat, ci.GetObjectsDependingOnThis()); - Assert.Contains(ci, cat.GetObjectsThisDependsOn()); + //catalogue depends on catalogue items existing (slightly counter intuitive but think of it as data flow out of technical low level data through transforms into datasets - and then into researchers and research projects) + Assert.That(ci.GetObjectsDependingOnThis(), Does.Contain(cat)); + Assert.That(cat.GetObjectsThisDependsOn(), Does.Contain(ci)); - //catalogue item should not be relying on anything currently (no link to underlying technical data) - Assert.IsNull(ci.GetObjectsThisDependsOn()); + //catalogue item should not be relying on anything currently (no link to underlying technical data) + Assert.That(ci.GetObjectsThisDependsOn(), Is.Null); + }); //now they are associated so the ci should be dependent on the col ci.SetColumnInfo(col); - Assert.Contains(col, ci.GetObjectsDependingOnThis()); + Assert.That(ci.GetObjectsDependingOnThis(), Does.Contain(col)); } finally { diff --git a/Rdmp.Core.Tests/Curation/Integration/DitaExtractorTests.cs b/Rdmp.Core.Tests/Curation/Integration/DitaExtractorTests.cs index ec09ec9b09..2997ed4c79 100644 --- a/Rdmp.Core.Tests/Curation/Integration/DitaExtractorTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/DitaExtractorTests.cs @@ -94,17 +94,23 @@ public void DitaExtractorConstructor_ExtractTestCatalogue_FilesExist() extractor.Extract(ThrowImmediatelyDataLoadEventListener.Quiet); - //make sure the root mapping files exist for navigating around - Assert.IsTrue(File.Exists(Path.Combine(testDir.FullName, "hic_data_catalogue.ditamap"))); - Assert.IsTrue(File.Exists(Path.Combine(testDir.FullName, "introduction.dita"))); - Assert.IsTrue(File.Exists(Path.Combine(testDir.FullName, "dataset.dita"))); + Assert.Multiple(() => + { + //make sure the root mapping files exist for navigating around + Assert.That(File.Exists(Path.Combine(testDir.FullName, "hic_data_catalogue.ditamap"))); + Assert.That(File.Exists(Path.Combine(testDir.FullName, "introduction.dita"))); + Assert.That(File.Exists(Path.Combine(testDir.FullName, "dataset.dita"))); + }); //make sure the catalogue we created is there var ditaCatalogueAsDotDitaFile = new FileInfo(Path.Combine(testDir.FullName, "ditaextractorconstructor_extracttestcatalogue_filesexist.dita")); //name of Dita file (for the Catalogue we just created) - Assert.IsTrue(ditaCatalogueAsDotDitaFile.Exists); - Assert.IsTrue(File.ReadAllText(ditaCatalogueAsDotDitaFile.FullName) - .Contains(ditaTestCatalogue.Description)); + Assert.Multiple(() => + { + Assert.That(ditaCatalogueAsDotDitaFile.Exists); + Assert.That(File.ReadAllText(ditaCatalogueAsDotDitaFile.FullName) + , Does.Contain(ditaTestCatalogue.Description)); + }); } finally { @@ -132,9 +138,8 @@ public void CreateCatalogueWithNoAcronym_CrashesDITAExtractor() { var extractor = new DitaCatalogueExtractor(CatalogueRepository, testDir); var ex = Assert.Throws(() => extractor.Extract(ThrowImmediatelyDataLoadEventListener.Quiet)); - Assert.AreEqual( - "Dita Extraction requires that each catalogue have a unique Acronym, the catalogue UnitTestCatalogue is missing an Acronym", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Dita Extraction requires that each catalogue have a unique Acronym, the catalogue UnitTestCatalogue is missing an Acronym")); } finally { diff --git a/Rdmp.Core.Tests/Curation/Integration/EncryptionTests.cs b/Rdmp.Core.Tests/Curation/Integration/EncryptionTests.cs index c25ee7e0e4..9c8b30abfc 100644 --- a/Rdmp.Core.Tests/Curation/Integration/EncryptionTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/EncryptionTests.cs @@ -24,8 +24,11 @@ public void EncryptAndThenDecryptString() const string toEncrypt = "Amagad"; var encryptedBinaryString = encrypter.Encrypt(toEncrypt); - Assert.AreNotEqual(toEncrypt, encryptedBinaryString); - Assert.AreEqual(toEncrypt, encrypter.Decrypt(encryptedBinaryString)); + Assert.Multiple(() => + { + Assert.That(encryptedBinaryString, Is.Not.EqualTo(toEncrypt)); + Assert.That(encrypter.Decrypt(encryptedBinaryString), Is.EqualTo(toEncrypt)); + }); } [Test] @@ -38,8 +41,11 @@ public void CheckIfThingsAreEncryptedOrNot() Console.WriteLine($"Encrypted password was:{encryptedBinaryString}"); - Assert.True(encrypter.IsStringEncrypted(encryptedBinaryString)); - Assert.False(encrypter.IsStringEncrypted(toEncrypt)); + Assert.Multiple(() => + { + Assert.That(encrypter.IsStringEncrypted(encryptedBinaryString)); + Assert.That(encrypter.IsStringEncrypted(toEncrypt), Is.False); + }); } @@ -57,15 +63,21 @@ public void MultiEncryptingShouldntBreakIt() //as soon as you set a password it should be encrypted by the credentials class in memory creds.Password = "fish"; - Assert.AreNotEqual("fish", creds.Password); - Assert.AreEqual("fish", creds.GetDecryptedPassword()); //but we should still be able to decrypt it + Assert.Multiple(() => + { + Assert.That(creds.Password, Is.Not.EqualTo("fish")); + Assert.That(creds.GetDecryptedPassword(), Is.EqualTo("fish")); //but we should still be able to decrypt it + }); //set the password to the encrypted password creds.Password = creds.Password; - //should still work - Assert.AreNotEqual("fish", creds.Password); - Assert.AreEqual("fish", creds.GetDecryptedPassword()); //but we should still be able to decrypt it + Assert.Multiple(() => + { + //should still work + Assert.That(creds.Password, Is.Not.EqualTo("fish")); + Assert.That(creds.GetDecryptedPassword(), Is.EqualTo("fish")); //but we should still be able to decrypt it + }); } finally { @@ -87,8 +99,11 @@ public void DataAccessCredentialsEncryption() { //as soon as you set a password it should be encrypted by the credentials class in memory creds.Password = "fish"; - Assert.AreNotEqual("fish", creds.Password); - Assert.AreEqual("fish", creds.GetDecryptedPassword()); //but we should still be able to decrypt it + Assert.Multiple(() => + { + Assert.That(creds.Password, Is.Not.EqualTo("fish")); + Assert.That(creds.GetDecryptedPassword(), Is.EqualTo("fish")); //but we should still be able to decrypt it + }); //save it creds.SaveToDatabase(); @@ -103,19 +118,25 @@ public void DataAccessCredentialsEncryption() } //ensure password in database is encrypted - Assert.AreNotEqual("fish", value); - Assert.AreEqual(creds.Password, value); //does value in database match value in memory (encrypted) + Assert.That(value, Is.Not.EqualTo("fish")); + Assert.That(value, Is.EqualTo(creds.Password)); //does value in database match value in memory (encrypted) } //get a new copy out of the database var newCopy = CatalogueRepository.GetObjectByID(creds.ID); - Assert.AreEqual(creds.Password, newCopy.Password); //passwords should match - Assert.AreNotEqual("fish", creds.Password); //neither should be fish - Assert.AreNotEqual("fish", newCopy.Password); + Assert.Multiple(() => + { + Assert.That(newCopy.Password, Is.EqualTo(creds.Password)); //passwords should match + Assert.That(creds.Password, Is.Not.EqualTo("fish")); //neither should be fish + }); + Assert.Multiple(() => + { + Assert.That(newCopy.Password, Is.Not.EqualTo("fish")); - //both should decrypt to the same value (fish - Assert.AreEqual("fish", creds.GetDecryptedPassword()); - Assert.AreEqual("fish", newCopy.GetDecryptedPassword()); + //both should decrypt to the same value (fish + Assert.That(creds.GetDecryptedPassword(), Is.EqualTo("fish")); + Assert.That(newCopy.GetDecryptedPassword(), Is.EqualTo("fish")); + }); } finally { @@ -139,8 +160,11 @@ public void TestFreakyPasswordValues(string freakyPassword) { //as soon as you set a password it should be encrypted by the credentials class in memory creds.Password = freakyPassword; - Assert.AreNotEqual(freakyPassword, creds.Password); - Assert.AreEqual(freakyPassword, creds.GetDecryptedPassword()); //but we should still be able to decrypt it + Assert.Multiple(() => + { + Assert.That(creds.Password, Is.Not.EqualTo(freakyPassword)); + Assert.That(creds.GetDecryptedPassword(), Is.EqualTo(freakyPassword)); //but we should still be able to decrypt it + }); //save it creds.SaveToDatabase(); @@ -155,19 +179,25 @@ public void TestFreakyPasswordValues(string freakyPassword) } //ensure password in database is encrypted - Assert.AreNotEqual(freakyPassword, value); - Assert.AreEqual(creds.Password, value); //does value in database match value in memory (encrypted) + Assert.That(value, Is.Not.EqualTo(freakyPassword)); + Assert.That(value, Is.EqualTo(creds.Password)); //does value in database match value in memory (encrypted) } //get a new copy out of the database var newCopy = CatalogueRepository.GetObjectByID(creds.ID); - Assert.AreEqual(creds.Password, newCopy.Password); //passwords should match - Assert.AreNotEqual(freakyPassword, creds.Password); //neither should be fish - Assert.AreNotEqual(freakyPassword, newCopy.Password); + Assert.Multiple(() => + { + Assert.That(newCopy.Password, Is.EqualTo(creds.Password)); //passwords should match + Assert.That(creds.Password, Is.Not.EqualTo(freakyPassword)); //neither should be fish + }); + Assert.Multiple(() => + { + Assert.That(newCopy.Password, Is.Not.EqualTo(freakyPassword)); - //both should decrypt to the same value (fish - Assert.AreEqual(freakyPassword, creds.GetDecryptedPassword()); - Assert.AreEqual(freakyPassword, newCopy.GetDecryptedPassword()); + //both should decrypt to the same value (fish + Assert.That(creds.GetDecryptedPassword(), Is.EqualTo(freakyPassword)); + Assert.That(newCopy.GetDecryptedPassword(), Is.EqualTo(freakyPassword)); + }); } finally { @@ -194,13 +224,16 @@ public void MigrationOfOldPasswordsTest() using var cmd = DatabaseCommandHelper.GetCommand( "UPDATE DataAccessCredentials set Password = 'fish' where Name='frankieFran'", con.Connection, con.Transaction); - Assert.AreEqual(1, cmd.ExecuteNonQuery()); + Assert.That(cmd.ExecuteNonQuery(), Is.EqualTo(1)); } var newCopy = CatalogueRepository.GetObjectByID(creds.ID); - Assert.AreEqual("fish", newCopy.GetDecryptedPassword()); - Assert.AreNotEqual("fish", newCopy.Password); + Assert.Multiple(() => + { + Assert.That(newCopy.GetDecryptedPassword(), Is.EqualTo("fish")); + Assert.That(newCopy.Password, Is.Not.EqualTo("fish")); + }); } finally { @@ -221,8 +254,7 @@ public void PasswordTooLong() password += "a"; var ex = Assert.Throws(() => TestFreakyPasswordValues(password)); - Assert.AreEqual( - "The free text Value supplied to this class was too long to be encrypted (Length of string was 201)", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("The free text Value supplied to this class was too long to be encrypted (Length of string was 201)")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/ExtractionFilterParameterSetTests.cs b/Rdmp.Core.Tests/Curation/Integration/ExtractionFilterParameterSetTests.cs index 7dd68d31d3..bf43d63dfa 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ExtractionFilterParameterSetTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ExtractionFilterParameterSetTests.cs @@ -31,11 +31,14 @@ public void ExtractionFilterParameterSet_Deleting() var paramSet = new ExtractionFilterParameterSet(CatalogueRepository, filter, "Old"); var vals = paramSet.CreateNewValueEntries(); - Assert.AreEqual(1, vals.Length); - Assert.IsTrue(vals[0].Exists()); + Assert.That(vals, Has.Length.EqualTo(1)); + Assert.That(vals[0].Exists()); paramSet.DeleteInDatabase(); - Assert.IsFalse(paramSet.Exists()); - Assert.IsFalse(vals[0].Exists()); + Assert.Multiple(() => + { + Assert.That(paramSet.Exists(), Is.False); + Assert.That(vals[0].Exists(), Is.False); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/ExtractionFilterTests.cs b/Rdmp.Core.Tests/Curation/Integration/ExtractionFilterTests.cs index 97dbf9cf24..4d05eb70a4 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ExtractionFilterTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ExtractionFilterTests.cs @@ -18,8 +18,7 @@ public void TestExtractionFilterDeleting_WhenItHas_ExtractionFilterParameterSet_ { var filter = GetFilterWithParameterSet(); var ex = Assert.Throws(() => filter.DeleteInDatabase()); - Assert.AreEqual("Cannot delete 'Age' because there are one or more ExtractionFilterParameterSet declared on it", - ex.Message); + Assert.That(ex.Message, Is.EqualTo("Cannot delete 'Age' because there are one or more ExtractionFilterParameterSet declared on it")); } private ExtractionFilter GetFilterWithParameterSet() diff --git a/Rdmp.Core.Tests/Curation/Integration/ExtractionInformationTests.cs b/Rdmp.Core.Tests/Curation/Integration/ExtractionInformationTests.cs index 043f06bace..7c728ef112 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ExtractionInformationTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ExtractionInformationTests.cs @@ -29,12 +29,15 @@ protected override void SetUp() ti = new TableInfo(CatalogueRepository, "HighEnergyShizzle"); columnInfo = new ColumnInfo(CatalogueRepository, "VelocityOfMatter", "int", ti); - ////////////Check the creation worked ok - Assert.IsNotNull(cata); //catalogue - Assert.IsNotNull(cataItem); + Assert.Multiple(() => + { + ////////////Check the creation worked ok + Assert.That(cata, Is.Not.Null); //catalogue + Assert.That(cataItem, Is.Not.Null); - Assert.IsNotNull(ti); //underlying table stuff - Assert.IsNotNull(columnInfo); + Assert.That(ti, Is.Not.Null); //underlying table stuff + Assert.That(columnInfo, Is.Not.Null); + }); ////////////// Create links between stuff and check they were created successfully ////////////// @@ -46,8 +49,8 @@ protected override void SetUp() public void BasicIDsAreCorrect() { var firstLinked = cataItem.ColumnInfo; - Assert.IsTrue(firstLinked != null); - Assert.IsTrue(firstLinked.ID == columnInfo.ID); + Assert.That(firstLinked, Is.Not.EqualTo(null)); + Assert.That(firstLinked.ID, Is.EqualTo(columnInfo.ID)); } @@ -71,27 +74,30 @@ public void test_creating_ExtractionFilter() Description = "Query to identify things that travel faster than X miles per hour!" }; filterFastThings.SaveToDatabase(); - Assert.AreEqual(filterFastThings.Name, "FastThings"); + Assert.That(filterFastThings.Name, Is.EqualTo("FastThings")); parameter = new ExtractionFilterParameter(CatalogueRepository, "DECLARE @X INT", filterFastThings); - Assert.IsNotNull(parameter); - Assert.AreEqual(parameter.ParameterName, "@X"); + Assert.That(parameter, Is.Not.Null); + Assert.That(parameter.ParameterName, Is.EqualTo("@X")); parameter.Value = "500"; parameter.SaveToDatabase(); var afterSave = CatalogueRepository.GetObjectByID(parameter.ID); - Assert.AreEqual(afterSave.Value, "500"); + Assert.That(afterSave.Value, Is.EqualTo("500")); var filterFastThings_NewCopyFromDB = CatalogueRepository.GetObjectByID(filterFastThings.ID); - Assert.AreEqual(filterFastThings.ID, filterFastThings_NewCopyFromDB.ID); - Assert.AreEqual(filterFastThings.Description, filterFastThings_NewCopyFromDB.Description); - Assert.AreEqual(filterFastThings.Name, filterFastThings_NewCopyFromDB.Name); - Assert.AreEqual(filterFastThings.WhereSQL, filterFastThings_NewCopyFromDB.WhereSQL); + Assert.Multiple(() => + { + Assert.That(filterFastThings_NewCopyFromDB.ID, Is.EqualTo(filterFastThings.ID)); + Assert.That(filterFastThings_NewCopyFromDB.Description, Is.EqualTo(filterFastThings.Description)); + Assert.That(filterFastThings_NewCopyFromDB.Name, Is.EqualTo(filterFastThings.Name)); + Assert.That(filterFastThings_NewCopyFromDB.WhereSQL, Is.EqualTo(filterFastThings.WhereSQL)); + }); } finally { @@ -121,16 +127,19 @@ public void test_creating_ExtractionInformation() extractInfo.SaveToDatabase(); //confirm the insert worked - Assert.AreEqual(extractInfo.SelectSQL, "dave"); + Assert.That(extractInfo.SelectSQL, Is.EqualTo("dave")); //fetch the extraction information via the linked CatalogueItem - ColumnInfo pair (i.e. we are testing the alternate route to fetch ExtractionInformation - by ID or by colum/item pair) var extractInfo2_CameFromLinker = cataItem.ExtractionInformation; - Assert.AreEqual(extractInfo.ID, extractInfo2_CameFromLinker.ID); - Assert.AreEqual(extractInfo.SelectSQL, extractInfo2_CameFromLinker.SelectSQL); + Assert.Multiple(() => + { + Assert.That(extractInfo2_CameFromLinker.ID, Is.EqualTo(extractInfo.ID)); + Assert.That(extractInfo2_CameFromLinker.SelectSQL, Is.EqualTo(extractInfo.SelectSQL)); - //make sure it saves properly - Assert.AreEqual(extractInfo2_CameFromLinker.Order, 123); - Assert.AreEqual(extractInfo2_CameFromLinker.ExtractionCategory, ExtractionCategory.Supplemental); + //make sure it saves properly + Assert.That(extractInfo2_CameFromLinker.Order, Is.EqualTo(123)); + Assert.That(extractInfo2_CameFromLinker.ExtractionCategory, Is.EqualTo(ExtractionCategory.Supplemental)); + }); } finally { diff --git a/Rdmp.Core.Tests/Curation/Integration/ExtractionInformationUnitTests.cs b/Rdmp.Core.Tests/Curation/Integration/ExtractionInformationUnitTests.cs index 31cdf00bf7..cdb4b3d269 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ExtractionInformationUnitTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ExtractionInformationUnitTests.cs @@ -27,14 +27,14 @@ public void NewExtractionInformation_OrderShouldBeContiguous(int? explicitOrder) ei.SaveToDatabase(); } - Assert.AreEqual(explicitOrder ?? 1, ei.Order); + Assert.That(ei.Order, Is.EqualTo(explicitOrder ?? 1)); // Newly created ones should have the right Order to not collide var cata = ei.CatalogueItem.Catalogue; var cataItem = new CatalogueItem(RepositoryLocator.CatalogueRepository, cata, "ci"); var ei2 = new ExtractionInformation(RepositoryLocator.CatalogueRepository, cataItem, ei.ColumnInfo, "fff"); - Assert.AreEqual((explicitOrder ?? 1) + 1, ei2.Order); + Assert.That(ei2.Order, Is.EqualTo((explicitOrder ?? 1) + 1)); } [Test] @@ -48,16 +48,16 @@ public void NewExtractionInformation_OrderShouldBeContiguous_ManyCalls() var cataItem2 = new CatalogueItem(RepositoryLocator.CatalogueRepository, cata, "ci"); var ei2 = new ExtractionInformation(RepositoryLocator.CatalogueRepository, cataItem2, ei1.ColumnInfo, "fff"); - Assert.AreEqual(2, ei2.Order); + Assert.That(ei2.Order, Is.EqualTo(2)); var cataItem3 = new CatalogueItem(RepositoryLocator.CatalogueRepository, cata, "ci"); var ei3 = new ExtractionInformation(RepositoryLocator.CatalogueRepository, cataItem3, ei1.ColumnInfo, "fff"); - Assert.AreEqual(3, ei3.Order); + Assert.That(ei3.Order, Is.EqualTo(3)); var cataItem4 = new CatalogueItem(RepositoryLocator.CatalogueRepository, cata, "ci"); var ei4 = new ExtractionInformation(RepositoryLocator.CatalogueRepository, cataItem4, ei1.ColumnInfo, "fff"); - Assert.AreEqual(4, ei4.Order); + Assert.That(ei4.Order, Is.EqualTo(4)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/FilterImportingTests/FilterImporterTests.cs b/Rdmp.Core.Tests/Curation/Integration/FilterImportingTests/FilterImporterTests.cs index 38c1abf636..eac1f1998d 100644 --- a/Rdmp.Core.Tests/Curation/Integration/FilterImportingTests/FilterImporterTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/FilterImportingTests/FilterImporterTests.cs @@ -148,13 +148,15 @@ public void FilterCreated_ParametersWithMasterExplicitTyping() //factory should have been asked to create a new filter called "Space Odyssey" and a parameter with a declaration that matches the master filter SQL (i.e. 'AS int') factory.Received(1).CreateNewFilter("Space Odyssey"); - //The master filter parameters should have been copied to the child - Assert.AreEqual(constructedParameter.Comment, masterParameter.Comment); - Assert.AreEqual(constructedParameter.ParameterSQL, - masterParameter - .ParameterSQL); //We actually manually set this above because that's the contract with "CreateNewParameter" - Assert.AreEqual(constructedParameter.Value, masterParameter.Value); - } + Assert.Multiple(() => + { + //The master filter parameters should have been copied to the child + Assert.That(masterParameter.Comment, Is.EqualTo(constructedParameter.Comment)); + Assert.That(masterParameter + .ParameterSQL, Is.EqualTo(constructedParameter.ParameterSQL)); //We actually manually set this above because that's the contract with "CreateNewParameter" + Assert.That(masterParameter.Value, Is.EqualTo(constructedParameter.Value)); + }); + } [Test] public void FilterCreated_ParametersRenamingDueToExistingParameterInScopeWithSameName() @@ -242,7 +244,7 @@ public void var filterCreator = new FilterImporter(factory, null); filterCreator.ImportFilter(WhenIHaveA(), master, new[] { existing }); - Assert.AreEqual("@hall2 = 'active'", constructed.WhereSQL); + Assert.That(constructed.WhereSQL, Is.EqualTo("@hall2 = 'active'")); //Master filter should have been asked what its parameters are master.Received(1).GetAllParameters(); diff --git a/Rdmp.Core.Tests/Curation/Integration/FilterImportingTests/ParameterCreatorTests.cs b/Rdmp.Core.Tests/Curation/Integration/FilterImportingTests/ParameterCreatorTests.cs index fab9d64bd9..6ac1c32b62 100644 --- a/Rdmp.Core.Tests/Curation/Integration/FilterImportingTests/ParameterCreatorTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/FilterImportingTests/ParameterCreatorTests.cs @@ -47,7 +47,7 @@ public void SingleParameterTest_NullReturnFromConstruct_Throws() var ex = Assert.Throws(() => creator.CreateAll(f, null)); - Assert.IsTrue(ex.Message.StartsWith("Parameter construction method returned null")); + Assert.That(ex.Message, Does.StartWith("Parameter construction method returned null")); } [Test] @@ -157,10 +157,13 @@ public void SingleParameterTest_Template_TemplateValuesUsed() var creator = new ParameterCreator(factory, null, new[] { template }); creator.CreateAll(f, null); - Assert.AreEqual("5", pstub.Value); - Assert.AreEqual("fish", pstub.Comment); + Assert.Multiple(() => + { + Assert.That(pstub.Value, Is.EqualTo("5")); + Assert.That(pstub.Comment, Is.EqualTo("fish")); + }); - factory.Received(1).CreateNewParameter(f, "DECLARE @bob AS int"); + factory.Received(1).CreateNewParameter(f, "DECLARE @bob AS int"); } [TestCase("[MyTable].[MyCol] = @name", "@name", "@name2", "[MyTable].[MyCol] = @name2")] @@ -180,7 +183,7 @@ public void SingleParameterTest_Template_TemplateValuesUsed() public void ReplaceParametersSQL(string haystack, string needle, string replacement, string expectedOutput) { var output = ParameterCreator.RenameParameterInSQL(haystack, needle, replacement); - Assert.AreEqual(expectedOutput, output); + Assert.That(output, Is.EqualTo(expectedOutput)); } [Test] @@ -213,6 +216,6 @@ [test]..[prescribing].[approved_name] LIKE @drugName2_2 [test]..[prescribing].[approved_name] LIKE @drugName3_2"; - Assert.AreEqual(expectedoutput, newString); + Assert.That(newString, Is.EqualTo(expectedoutput)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/ForwardEngineerANOCatalogueTests.cs b/Rdmp.Core.Tests/Curation/Integration/ForwardEngineerANOCatalogueTests.cs index 9eb7063222..96fac156b8 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ForwardEngineerANOCatalogueTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ForwardEngineerANOCatalogueTests.cs @@ -119,15 +119,18 @@ public void CreateANOVersionTest() engine.Execute(); var anoCatalogue = CatalogueRepository.GetAllObjects().Single(c => c.Folder.StartsWith("\\ano")); - Assert.IsTrue(anoCatalogue.Exists()); + Assert.That(anoCatalogue.Exists()); db.Drop(); var exports = CatalogueRepository.GetAllObjects().Length; var imports = CatalogueRepository.GetAllObjects().Length; - Assert.AreEqual(exports, imports); - Assert.IsTrue(exports > 0); + Assert.Multiple(() => + { + Assert.That(imports, Is.EqualTo(exports)); + Assert.That(exports, Is.GreaterThan(0)); + }); } [Test] @@ -166,20 +169,26 @@ public void CreateANOVersionTest_IntIdentity() engine.Execute(); var anoCatalogue = CatalogueRepository.GetAllObjects().Single(c => c.Folder.StartsWith("\\ano")); - Assert.IsTrue(anoCatalogue.Exists()); + Assert.Multiple(() => + { + Assert.That(anoCatalogue.Exists()); - //should only be one (the id column - Assert.AreEqual(1, anoCatalogue.CatalogueItems.Length); + //should only be one (the id column + Assert.That(anoCatalogue.CatalogueItems, Has.Length.EqualTo(1)); + }); var idColInAnoDatabase = anoCatalogue.CatalogueItems[0].ColumnInfo; - Assert.AreEqual("int", idColInAnoDatabase.Data_type); + Assert.That(idColInAnoDatabase.Data_type, Is.EqualTo("int")); db.Drop(); var exports = CatalogueRepository.GetAllObjects().Length; var imports = CatalogueRepository.GetAllObjects().Length; - Assert.AreEqual(exports, imports); - Assert.IsTrue(exports > 0); + Assert.Multiple(() => + { + Assert.That(imports, Is.EqualTo(exports)); + Assert.That(exports, Is.GreaterThan(0)); + }); } @@ -228,7 +237,7 @@ public void CreateANOVersion_TestSkippingTables(bool tableInfoAlreadyExistsForSk } //Create a JoinInfo so the query builder knows how to connect the tables - new JoinInfo(CatalogueRepository, + _=new JoinInfo(CatalogueRepository, fromHeadsColumnInfo.Single(c => c.GetRuntimeName().Equals("Vertebrae")), fromNeckColumnInfo.Single(c => c.GetRuntimeName().Equals("Vertebrae")), ExtractionJoinType.Inner, null ); @@ -240,7 +249,7 @@ public void CreateANOVersion_TestSkippingTables(bool tableInfoAlreadyExistsForSk cataEngineer2.ExecuteForwardEngineering(cata); //4 extraction informations in from Catalogue (2 from Heads and 2 from Necks) - Assert.AreEqual(cata.GetAllExtractionInformation(ExtractionCategory.Any).Length, 4); + Assert.That(cata.GetAllExtractionInformation(ExtractionCategory.Any), Has.Length.EqualTo(4)); //setup ANOTable on head var anoTable = new ANOTable(CatalogueRepository, ANOStore_ExternalDatabaseServer, "ANOSkullColor", "C") @@ -271,15 +280,18 @@ public void CreateANOVersion_TestSkippingTables(bool tableInfoAlreadyExistsForSk //not part of serialization planManager.TargetDatabase = dbTo; planManager.SkippedTables - .Add(fromNeckTableInfo); //skip the necks table because it already exists (ColumnInfos may or may not exist but physical table definetly does) + .Add(fromNeckTableInfo); //skip the necks table because it already exists (ColumnInfos may or may not exist but physical table definitely does) var engine = new ForwardEngineerANOCatalogueEngine(RepositoryLocator, planManager); if (!tableInfoAlreadyExistsForSkippedTable) { var ex = Assert.Throws(engine.Execute); - Assert.IsTrue(Regex.IsMatch(ex.InnerException.Message, "Found '0' ColumnInfos called")); - Assert.IsTrue(Regex.IsMatch(ex.InnerException.Message, "[Necks].[SpineColor]")); + Assert.Multiple(() => + { + Assert.That(Regex.IsMatch(ex.InnerException.Message, "Found '0' ColumnInfos called")); + Assert.That(Regex.IsMatch(ex.InnerException.Message, "[Necks].[SpineColor]")); + }); return; } @@ -287,30 +299,33 @@ public void CreateANOVersion_TestSkippingTables(bool tableInfoAlreadyExistsForSk engine.Execute(); var newCata = CatalogueRepository.GetAllObjects().Single(c => c.Name.Equals("ANOHeads")); - Assert.IsTrue(newCata.Exists()); + Assert.That(newCata.Exists()); var newCataItems = newCata.CatalogueItems; - Assert.AreEqual(newCataItems.Length, 4); - - //should be extraction informations - //all extraction informations should point to the new table location - Assert.IsTrue(newCataItems.All(ci => ci.ExtractionInformation.SelectSQL.Contains(dbTo.GetRuntimeName()))); - - //these columns should all exist - Assert.IsTrue(newCataItems.Any(ci => ci.ExtractionInformation.SelectSQL.Contains("SkullColor"))); - Assert.IsTrue(newCataItems.Any(ci => ci.ExtractionInformation.SelectSQL.Contains("SpineColor"))); - Assert.IsTrue(newCataItems.Any(ci => - ci.ExtractionInformation.SelectSQL - .Contains("Vertebrae"))); //actually there will be 2 copies of this one from Necks one from Heads + Assert.That(newCataItems, Has.Length.EqualTo(4)); - //new ColumnInfo should have a reference to the anotable - Assert.IsTrue(newCataItems.Single(ci => ci.Name.Equals("ANOSkullColor")).ColumnInfo.ANOTable_ID == anoTable.ID); + Assert.Multiple(() => + { + //should be extraction informations + //all extraction informations should point to the new table location + Assert.That(newCataItems.All(ci => ci.ExtractionInformation.SelectSQL.Contains(dbTo.GetRuntimeName()))); + + //these columns should all exist + Assert.That(newCataItems.Any(ci => ci.ExtractionInformation.SelectSQL.Contains("SkullColor"))); + Assert.That(newCataItems.Any(ci => ci.ExtractionInformation.SelectSQL.Contains("SpineColor"))); + Assert.That(newCataItems.Any(ci => + ci.ExtractionInformation.SelectSQL + .Contains("Vertebrae"))); //actually there will be 2 copies of this one from Necks one from Heads + + //new ColumnInfo should have a reference to the anotable + Assert.That(newCataItems.Single(ci => ci.Name.Equals("ANOSkullColor")).ColumnInfo.ANOTable_ID, Is.EqualTo(anoTable.ID)); + }); var newSpineColorColumnInfo = newCataItems.Single(ci => ci.Name.Equals("ANOSkullColor")).ColumnInfo; //table info already existed, make sure the new CatalogueItems point to the same columninfos / table infos - Assert.IsTrue(newCataItems.Select(ci => ci.ColumnInfo).Contains(newSpineColorColumnInfo)); + Assert.That(newCataItems.Select(ci => ci.ColumnInfo), Does.Contain(newSpineColorColumnInfo)); } [Test] @@ -410,14 +425,17 @@ public void CreateANOVersionTest_LookupsAndExtractionInformations() var qb = new QueryBuilder(null, null); qb.AddColumnRange(bulk.catalogue.GetAllExtractionInformation(ExtractionCategory.Any)); - //The query builder should be able to succesfully create SQL + //The query builder should be able to successfully create SQL Console.WriteLine(qb.SQL); - //there should be 2 tables involved in the query [z_sexLookup] and [BulkData] - Assert.AreEqual(2, qb.TablesUsedInQuery.Count); + Assert.Multiple(() => + { + //there should be 2 tables involved in the query [z_sexLookup] and [BulkData] + Assert.That(qb.TablesUsedInQuery, Has.Count.EqualTo(2)); - //the query builder should have identified the lookup - Assert.AreEqual(lookup, qb.GetDistinctRequiredLookups().Single()); + //the query builder should have identified the lookup + Assert.That(qb.GetDistinctRequiredLookups().Single(), Is.EqualTo(lookup)); + }); //////////////////////////////////////////////////////////////////////////////////////The Actual Bit Being Tested//////////////////////////////////////////////////// var planManager = new ForwardEngineerANOCataloguePlanManager(RepositoryLocator, bulk.catalogue) @@ -436,7 +454,7 @@ public void CreateANOVersionTest_LookupsAndExtractionInformations() //////////////////////////////////////////////////////////////////////////////////////End The Actual Bit Being Tested//////////////////////////////////////////////////// var anoCatalogue = CatalogueRepository.GetAllObjects().Single(c => c.Folder.StartsWith("\\ano")); - Assert.IsTrue(anoCatalogue.Exists()); + Assert.That(anoCatalogue.Exists()); //The new Catalogue should have the same number of ExtractionInformations var eiSource = bulk.catalogue.GetAllExtractionInformation(ExtractionCategory.Any).OrderBy(ei => ei.Order) @@ -444,78 +462,87 @@ public void CreateANOVersionTest_LookupsAndExtractionInformations() var eiDestination = anoCatalogue.GetAllExtractionInformation(ExtractionCategory.Any).OrderBy(ei => ei.Order) .ToArray(); - Assert.AreEqual(eiSource.Length, eiDestination.Length, + Assert.That(eiDestination, Has.Length.EqualTo(eiSource.Length), "Both the new and the ANO catalogue should have the same number of ExtractionInformations (extractable columns)"); for (var i = 0; i < eiSource.Length; i++) { - Assert.AreEqual(eiSource[i].Order, eiDestination[i].Order, - "ExtractionInformations in the source and destination Catalogue should have the same order"); - - Assert.AreEqual(eiSource[i].GetRuntimeName(), - eiDestination[i].GetRuntimeName().Replace("ANO", ""), - "ExtractionInformations in the source and destination Catalogue should have the same names (excluding ANO prefix)"); - - Assert.AreEqual(eiSource[i].ExtractionCategory, eiDestination[i].ExtractionCategory, - "Old / New ANO ExtractionInformations did not match on ExtractionCategory"); - Assert.AreEqual(eiSource[i].IsExtractionIdentifier, eiDestination[i].IsExtractionIdentifier, - "Old / New ANO ExtractionInformations did not match on IsExtractionIdentifier"); - Assert.AreEqual(eiSource[i].HashOnDataRelease, eiDestination[i].HashOnDataRelease, - "Old / New ANO ExtractionInformations did not match on HashOnDataRelease"); - Assert.AreEqual(eiSource[i].IsPrimaryKey, eiDestination[i].IsPrimaryKey, - "Old / New ANO ExtractionInformations did not match on IsPrimaryKey"); + Assert.Multiple(() => + { + Assert.That(eiDestination[i].Order, Is.EqualTo(eiSource[i].Order), + "ExtractionInformations in the source and destination Catalogue should have the same order"); + + Assert.That(eiDestination[i].GetRuntimeName().Replace("ANO", ""), Is.EqualTo(eiSource[i].GetRuntimeName()), + "ExtractionInformations in the source and destination Catalogue should have the same names (excluding ANO prefix)"); + + Assert.That(eiDestination[i].ExtractionCategory, Is.EqualTo(eiSource[i].ExtractionCategory), + "Old / New ANO ExtractionInformations did not match on ExtractionCategory"); + Assert.That(eiDestination[i].IsExtractionIdentifier, Is.EqualTo(eiSource[i].IsExtractionIdentifier), + "Old / New ANO ExtractionInformations did not match on IsExtractionIdentifier"); + Assert.That(eiDestination[i].HashOnDataRelease, Is.EqualTo(eiSource[i].HashOnDataRelease), + "Old / New ANO ExtractionInformations did not match on HashOnDataRelease"); + Assert.That(eiDestination[i].IsPrimaryKey, Is.EqualTo(eiSource[i].IsPrimaryKey), + "Old / New ANO ExtractionInformations did not match on IsPrimaryKey"); + }); } //check it worked var qbdestination = new QueryBuilder(null, null); qbdestination.AddColumnRange(anoCatalogue.GetAllExtractionInformation(ExtractionCategory.Any)); - //The query builder should be able to succesfully create SQL + //The query builder should be able to successfully create SQL Console.WriteLine(qbdestination.SQL); var anoEiPostcode = anoCatalogue.GetAllExtractionInformation(ExtractionCategory.Any) .Single(ei => ei.GetRuntimeName().Equals("MyMutilatedColumn")); //The transform on postcode should have been refactored to the new table name and preserve the scalar function LEFT... - Assert.AreEqual($"LEFT(10,{anoEiPostcode.ColumnInfo.TableInfo.GetFullyQualifiedName()}.[current_postcode])", - anoEiPostcode.SelectSQL); + Assert.That(anoEiPostcode.SelectSQL, Is.EqualTo($"LEFT(10,{anoEiPostcode.ColumnInfo.TableInfo.GetFullyQualifiedName()}.[current_postcode])")); var anoEiComboCol = anoCatalogue.GetAllExtractionInformation(ExtractionCategory.Any) .Single(ei => ei.GetRuntimeName().Equals("ComboColumn")); - //The transform on postcode should have been refactored to the new table name and preserve the scalar function LEFT... - Assert.AreEqual( - $"{anoEiPostcode.ColumnInfo.TableInfo.GetFullyQualifiedName()}.[forename] + ' ' + {anoEiPostcode.ColumnInfo.TableInfo.GetFullyQualifiedName()}.[surname]", - anoEiComboCol.SelectSQL); - - //there should be 2 tables involved in the query [z_sexLookup] and [BulkData] - Assert.AreEqual(2, qbdestination.TablesUsedInQuery.Count); - - //the query builder should have identified the lookup but it should be the new one not the old one - Assert.AreEqual(1, qbdestination.GetDistinctRequiredLookups().Count(), - "New query builder for ano catalogue did not correctly identify that there was a Lookup"); - Assert.AreNotEqual(lookup, qbdestination.GetDistinctRequiredLookups().Single(), - "New query builder for ano catalogue identified the OLD Lookup!"); + Assert.Multiple(() => + { + //The transform on postcode should have been refactored to the new table name and preserve the scalar function LEFT... + Assert.That( + anoEiComboCol.SelectSQL, Is.EqualTo($"{anoEiPostcode.ColumnInfo.TableInfo.GetFullyQualifiedName()}.[forename] + ' ' + {anoEiPostcode.ColumnInfo.TableInfo.GetFullyQualifiedName()}.[surname]")); + + //there should be 2 tables involved in the query [z_sexLookup] and [BulkData] + Assert.That(qbdestination.TablesUsedInQuery, Has.Count.EqualTo(2)); + + //the query builder should have identified the lookup but it should be the new one not the old one + Assert.That(qbdestination.GetDistinctRequiredLookups().Count(), Is.EqualTo(1), + "New query builder for ano catalogue did not correctly identify that there was a Lookup"); + Assert.That(qbdestination.GetDistinctRequiredLookups().Single(), Is.Not.EqualTo(lookup), + "New query builder for ano catalogue identified the OLD Lookup!"); + }); - Assert.AreEqual(1, qbdestination.GetDistinctRequiredLookups().Single().GetSupplementalJoins().Count(), - "The new Lookup did not have the composite join key (sex/hb_extract)"); - Assert.AreNotEqual(compositeLookup, qbdestination.GetDistinctRequiredLookups().Single().GetSupplementalJoins(), - "New query builder for ano catalogue identified the OLD LookupCompositeJoinInfo!"); + Assert.Multiple(() => + { + Assert.That(qbdestination.GetDistinctRequiredLookups().Single().GetSupplementalJoins().Count(), Is.EqualTo(1), + "The new Lookup did not have the composite join key (sex/hb_extract)"); + Assert.That(qbdestination.GetDistinctRequiredLookups().Single().GetSupplementalJoins(), Is.Not.EqualTo(compositeLookup), + "New query builder for ano catalogue identified the OLD LookupCompositeJoinInfo!"); + }); db.Drop(); var exports = CatalogueRepository.GetAllObjects().Length; var imports = CatalogueRepository.GetAllObjects().Length; - Assert.AreEqual(exports, imports); - Assert.IsTrue(exports > 0); + Assert.Multiple(() => + { + Assert.That(imports, Is.EqualTo(exports)); + Assert.That(exports, Is.GreaterThan(0)); + }); } private void CreateMigrationRules(ForwardEngineerANOCataloguePlanManager planManager, BulkTestsData bulk) { var chi = bulk.GetColumnInfo("chi"); - + var anoChi = new ANOTable(CatalogueRepository, ANOStore_ExternalDatabaseServer, "ANOCHI", "C") { NumberOfIntegersToUseInAnonymousRepresentation = 9, diff --git a/Rdmp.Core.Tests/Curation/Integration/GetDatabaseDiagramBinaryTest.cs b/Rdmp.Core.Tests/Curation/Integration/GetDatabaseDiagramBinaryTest.cs index 9f8062c16c..eaacef1557 100644 --- a/Rdmp.Core.Tests/Curation/Integration/GetDatabaseDiagramBinaryTest.cs +++ b/Rdmp.Core.Tests/Curation/Integration/GetDatabaseDiagramBinaryTest.cs @@ -5,6 +5,7 @@ // You should have received a copy of the GNU General Public License along with RDMP. If not, see . using System; +using System.Diagnostics.CodeAnalysis; using NUnit.Framework; using Rdmp.Core.ReusableLibraryCode; using Tests.Common; @@ -22,16 +23,16 @@ public void GetBinaryText() con.Connection, con.Transaction); using var reader = cmd.ExecuteReader(); //The system diagram exists - Assert.IsTrue(reader.Read()); + Assert.That(reader.Read()); var bytes = (byte[])reader[0]; var bytesAsString = ByteArrayToString(bytes); Console.WriteLine(bytesAsString); - Assert.Greater(bytesAsString.Length, 100000); + Assert.That(bytesAsString, Has.Length.GreaterThan(100000)); } - public static string ByteArrayToString(byte[] ba) + private static string ByteArrayToString([NotNull] byte[] ba) { var hex = BitConverter.ToString(ba); return hex.Replace("-", ""); diff --git a/Rdmp.Core.Tests/Curation/Integration/GovernanceTests.cs b/Rdmp.Core.Tests/Curation/Integration/GovernanceTests.cs index 63e1e565e0..1ea9126c0c 100644 --- a/Rdmp.Core.Tests/Curation/Integration/GovernanceTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/GovernanceTests.cs @@ -40,8 +40,11 @@ public void TestCreatingGovernance_StartsAtToday() { var gov = GetGov(); - Assert.NotNull(gov); - Assert.AreEqual(gov.StartDate, DateTime.Now.Date); + Assert.Multiple(() => + { + Assert.That(gov, Is.Not.Null); + Assert.That(DateTime.Now.Date, Is.EqualTo(gov.StartDate)); + }); } [Test] @@ -55,17 +58,17 @@ public void TestCreatingGovernance_ChangeName() var freshCopy = CatalogueRepository.GetObjectByID(gov.ID); //local change not applied yet - Assert.AreNotEqual(gov.Name, freshCopy.Name); + Assert.That(freshCopy.Name, Is.Not.EqualTo(gov.Name)); //comitted change to database gov.SaveToDatabase(); //notice that this fresh copy is still desynced - Assert.AreNotEqual(gov.Name, freshCopy.Name); + Assert.That(freshCopy.Name, Is.Not.EqualTo(gov.Name)); //sync it freshCopy = CatalogueRepository.GetObjectByID(gov.ID); - Assert.AreEqual(gov.Name, freshCopy.Name); + Assert.That(freshCopy.Name, Is.EqualTo(gov.Name)); } [Test] @@ -82,9 +85,8 @@ public void TestCreatingGovernance_CannotHaveSameNames() if (CatalogueRepository is TableRepository) { var ex = Assert.Throws(gov2.SaveToDatabase); - StringAssert.StartsWith( - "Cannot insert duplicate key row in object 'dbo.GovernancePeriod' with unique index 'idxGovernancePeriodNameMustBeUnique'. The duplicate key value is (HiDuplicate)", - ex?.Message); + Assert.That( + ex?.Message, Does.StartWith("Cannot insert duplicate key row in object 'dbo.GovernancePeriod' with unique index 'idxGovernancePeriodNameMustBeUnique'. The duplicate key value is (HiDuplicate)")); } } @@ -101,7 +103,7 @@ public void Checkability_ExpiresBeforeStarts() var ex = Assert.Throws(() => gov.Check(ThrowImmediatelyCheckNotifier .Quiet)); //no longer valid - notice there is no SaveToDatabase because we can shouldn't be going back to db anyway - Assert.AreEqual("GovernancePeriod TestExpiryBeforeStarting expires before it begins!", ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("GovernancePeriod TestExpiryBeforeStarting expires before it begins!")); } [Test] @@ -112,7 +114,7 @@ public void Checkability_NoExpiryDateWarning() //valid to start with var ex = Assert.Throws(() => gov.Check(ThrowImmediatelyCheckNotifier.QuietPicky)); - Assert.AreEqual("There is no end date for GovernancePeriod NeverExpires", ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("There is no end date for GovernancePeriod NeverExpires")); } [TestCase(true)] @@ -125,19 +127,19 @@ public void GovernsCatalogue(bool memoryRepository) var c = new Catalogue(repo, "GovernedCatalogue"); try { - Assert.AreEqual(gov.GovernedCatalogues.Count(), 0); + Assert.That(gov.GovernedCatalogues.Count(), Is.EqualTo(0)); //should be no governanced catalogues for this governancer yet gov.CreateGovernanceRelationshipTo(c); var allCatalogues = gov.GovernedCatalogues.ToArray(); var governedCatalogue = allCatalogues[0]; - Assert.AreEqual(governedCatalogue, c); //we now govern C + Assert.That(c, Is.EqualTo(governedCatalogue)); //we now govern C } finally { gov.DeleteGovernanceRelationshipTo(c); - Assert.AreEqual(gov.GovernedCatalogues.Count(), 0); //we govern c nevermore! + Assert.That(gov.GovernedCatalogues.Count(), Is.EqualTo(0)); //we govern c nevermore! c.DeleteInDatabase(); } @@ -149,8 +151,7 @@ public void GovernsSameCatalogueTwice() var c = new Catalogue(CatalogueRepository, "GovernedCatalogue"); var gov = GetGov(); - Assert.AreEqual(gov.GovernedCatalogues.Count(), - 0); //should be no governanced catalogues for this governancer yet + Assert.That(gov.GovernedCatalogues.Count(), Is.EqualTo(0)); //should be no governanced catalogues for this governancer yet gov.CreateGovernanceRelationshipTo(c); gov.CreateGovernanceRelationshipTo(c); diff --git a/Rdmp.Core.Tests/Curation/Integration/LinkerTests.cs b/Rdmp.Core.Tests/Curation/Integration/LinkerTests.cs index 967102ec6b..37cb819f37 100644 --- a/Rdmp.Core.Tests/Curation/Integration/LinkerTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/LinkerTests.cs @@ -29,7 +29,7 @@ public void AddSameLinkTwice() //now you can add as many links as you want, it just skips them lazor.SetColumnInfo(velocityColumn); - Assert.AreEqual(lazor.ColumnInfo, velocityColumn); + Assert.That(velocityColumn, Is.EqualTo(lazor.ColumnInfo)); } finally { @@ -50,18 +50,21 @@ public void AddLinkBetween_createNewLink_pass() var highEnergyTable = new TableInfo(CatalogueRepository, "HighEnergyShizzle"); var velocityColumn = new ColumnInfo(CatalogueRepository, "Velocity Of Matter", "int", highEnergyTable); - ////////////Check the creation worked ok - Assert.IsNotNull(predator); //catalogue - Assert.IsNotNull(lazor); + Assert.Multiple(() => + { + ////////////Check the creation worked ok + Assert.That(predator, Is.Not.Null); //catalogue + Assert.That(lazor, Is.Not.Null); - Assert.IsNotNull(highEnergyTable); //underlying table stuff - Assert.IsNotNull(velocityColumn); + Assert.That(highEnergyTable, Is.Not.Null); //underlying table stuff + Assert.That(velocityColumn, Is.Not.Null); + }); ////////////// Create links between stuff and check they were created successfully ////////////// //create a link between catalogue item lazor and velocity column lazor.SetColumnInfo(velocityColumn); - Assert.IsTrue(lazor.ColumnInfo.ID == velocityColumn.ID); + Assert.That(lazor.ColumnInfo.ID, Is.EqualTo(velocityColumn.ID)); ////////////////cleanup ---- Delete everything that we created -------- ////////////// velocityColumn @@ -69,7 +72,7 @@ public void AddLinkBetween_createNewLink_pass() lazor.RevertToDatabaseState(); - Assert.IsNull(lazor.ColumnInfo); //involves a database query so won't actually invalidate the below + Assert.That(lazor.ColumnInfo, Is.Null); //involves a database query so won't actually invalidate the below predator.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/Curation/Integration/LoadMetadataTests.cs b/Rdmp.Core.Tests/Curation/Integration/LoadMetadataTests.cs index 49a9b113ed..db8467999b 100644 --- a/Rdmp.Core.Tests/Curation/Integration/LoadMetadataTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/LoadMetadataTests.cs @@ -28,7 +28,7 @@ public void CreateNewAndGetBackFromDatabase() loadMetadata.SaveToDatabase(); var loadMetadataWithIdAfterwards = CatalogueRepository.GetObjectByID(loadMetadata.ID); - Assert.AreEqual(loadMetadataWithIdAfterwards.LocationOfFlatFiles, TestContext.CurrentContext.TestDirectory); + Assert.That(TestContext.CurrentContext.TestDirectory, Is.EqualTo(loadMetadataWithIdAfterwards.LocationOfFlatFiles)); } finally { @@ -44,22 +44,22 @@ public void Test_IgnoreTrigger_GetSet() try { //default - Assert.IsFalse(loadMetadata.IgnoreTrigger); + Assert.That(loadMetadata.IgnoreTrigger, Is.False); loadMetadata.SaveToDatabase(); - Assert.IsFalse(loadMetadata.IgnoreTrigger); + Assert.That(loadMetadata.IgnoreTrigger, Is.False); loadMetadata.SaveToDatabase(); loadMetadata.IgnoreTrigger = true; - Assert.IsTrue(loadMetadata.IgnoreTrigger); + Assert.That(loadMetadata.IgnoreTrigger); loadMetadata.RevertToDatabaseState(); - Assert.IsFalse(loadMetadata.IgnoreTrigger); + Assert.That(loadMetadata.IgnoreTrigger, Is.False); loadMetadata.IgnoreTrigger = true; - Assert.IsTrue(loadMetadata.IgnoreTrigger); + Assert.That(loadMetadata.IgnoreTrigger); loadMetadata.SaveToDatabase(); var lmd2 = RepositoryLocator.CatalogueRepository.GetObjectByID(loadMetadata.ID); - Assert.IsTrue(lmd2.IgnoreTrigger); + Assert.That(lmd2.IgnoreTrigger); } finally { @@ -73,13 +73,13 @@ public void TestPreExecutionChecker_TablesDontExist() var db = GetCleanedServer(FAnsi.DatabaseType.MicrosoftSQLServer); var tbl = db.ExpectTable("Imaginary"); - Assert.IsFalse(tbl.Exists()); + Assert.That(tbl.Exists(), Is.False); var lmd = RdmpMockFactory.Mock_LoadMetadataLoadingTable(tbl); var checker = new PreExecutionChecker(lmd, new HICDatabaseConfiguration(db.Server)); var ex = Assert.Throws(() => checker.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.IsMatch("Table '.*Imaginary.*' does not exist", ex.Message); + Assert.That(ex.Message, Does.Match("Table '.*Imaginary.*' does not exist")); } [Test] @@ -90,12 +90,12 @@ public void TestPreExecutionChecker_TableIsTableValuedFunction() f.Create(db, CatalogueRepository); var tbl = f.TableInfoCreated.Discover(DataAccessContext.DataLoad); - Assert.IsTrue(tbl.Exists()); + Assert.That(tbl.Exists()); var lmd = RdmpMockFactory.Mock_LoadMetadataLoadingTable(f.TableInfoCreated); var checker = new PreExecutionChecker(lmd, new HICDatabaseConfiguration(db.Server)); var ex = Assert.Throws(() => checker.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.IsMatch("Table '.*MyAwesomeFunction.*' is a TableValuedFunction", ex.Message); + Assert.That(ex.Message, Does.Match("Table '.*MyAwesomeFunction.*' is a TableValuedFunction")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/LoadProgressTest.cs b/Rdmp.Core.Tests/Curation/Integration/LoadProgressTest.cs index 90a810658f..ea415c2bb7 100644 --- a/Rdmp.Core.Tests/Curation/Integration/LoadProgressTest.cs +++ b/Rdmp.Core.Tests/Curation/Integration/LoadProgressTest.cs @@ -21,7 +21,7 @@ public void CreateNewScheduleTest() var loadMetadata = new LoadMetadata(CatalogueRepository); var loadProgress = new LoadProgress(CatalogueRepository, loadMetadata); - Assert.AreEqual(loadProgress.LoadMetadata_ID, loadMetadata.ID); + Assert.That(loadMetadata.ID, Is.EqualTo(loadProgress.LoadMetadata_ID)); loadProgress.DeleteInDatabase(); loadMetadata.DeleteInDatabase(); @@ -48,15 +48,18 @@ public void LoadProgress_Equals() try { - //values are different - Assert.AreNotEqual(progressCopy.OriginDate, progress.OriginDate); - Assert.AreNotEqual(progressCopy.Name, progress.Name); + Assert.Multiple(() => + { + //values are different + Assert.That(progress.OriginDate, Is.Not.EqualTo(progressCopy.OriginDate)); + Assert.That(progress.Name, Is.Not.EqualTo(progressCopy.Name)); - //IDs are the same - Assert.AreEqual(progressCopy.ID, progress.ID); + //IDs are the same + Assert.That(progress.ID, Is.EqualTo(progressCopy.ID)); - //therefore objects are the same - Assert.IsTrue(progressCopy.Equals(progress)); + //therefore objects are the same + Assert.That(progressCopy, Is.EqualTo(progress)); + }); } finally { diff --git a/Rdmp.Core.Tests/Curation/Integration/LoadProgressUnitTests.cs b/Rdmp.Core.Tests/Curation/Integration/LoadProgressUnitTests.cs index 874f723b6c..7d8764548d 100644 --- a/Rdmp.Core.Tests/Curation/Integration/LoadProgressUnitTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/LoadProgressUnitTests.cs @@ -82,7 +82,7 @@ public void LoadProgress_JobFactory_NoDates() var jobFactory = new SingleScheduledJobFactory(lp, strat, 999, lp.LoadMetadata, null); var job = jobFactory.Create(RepositoryLocator, ThrowImmediatelyDataLoadEventListener.Quiet, null); - Assert.IsNull(job); + Assert.That(job, Is.Null); // We have 1 day to load (date is the last fully loaded date) lp.DataLoadProgress = DateTime.Now.AddDays(-2); @@ -92,6 +92,6 @@ public void LoadProgress_JobFactory_NoDates() jobFactory = new SingleScheduledJobFactory(lp, strat, 999, lp.LoadMetadata, null); job = jobFactory.Create(RepositoryLocator, ThrowImmediatelyDataLoadEventListener.Quiet, null); - Assert.AreEqual(1, ((ScheduledDataLoadJob)job).DatesToRetrieve.Count); + Assert.That(((ScheduledDataLoadJob)job).DatesToRetrieve, Has.Count.EqualTo(1)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/LookupTest.cs b/Rdmp.Core.Tests/Curation/Integration/LookupTest.cs index 6a51c11d52..8ab485bd43 100644 --- a/Rdmp.Core.Tests/Curation/Integration/LookupTest.cs +++ b/Rdmp.Core.Tests/Curation/Integration/LookupTest.cs @@ -138,17 +138,20 @@ public void CreateLookup_linkWithOtherTable(bool memoryRepo) child2 = new ColumnInfo(repo, "unit_test_CreateLookup", "int", parent2); //fk in data table child3 = new ColumnInfo(repo, "unit_test_CreateLookup", "int", parent); //pk in lookup - new Lookup(repo, child, child2, child3, ExtractionJoinType.Left, null); + _=new Lookup(repo, child, child2, child3, ExtractionJoinType.Left, null); - Assert.AreEqual(child.GetAllLookupForColumnInfoWhereItIsA(LookupType.Description).Length, 1); - Assert.AreEqual(child2.GetAllLookupForColumnInfoWhereItIsA(LookupType.Description).Length, 0); - Assert.AreEqual(child.GetAllLookupForColumnInfoWhereItIsA(LookupType.AnyKey).Length, 0); - Assert.AreEqual(child2.GetAllLookupForColumnInfoWhereItIsA(LookupType.AnyKey).Length, 1); - Assert.AreEqual(child3.GetAllLookupForColumnInfoWhereItIsA(LookupType.AnyKey).Length, 1); + Assert.Multiple(() => + { + Assert.That(child.GetAllLookupForColumnInfoWhereItIsA(LookupType.Description), Has.Length.EqualTo(1)); + Assert.That(child2.GetAllLookupForColumnInfoWhereItIsA(LookupType.Description), Is.Empty); + Assert.That(child.GetAllLookupForColumnInfoWhereItIsA(LookupType.AnyKey), Is.Empty); + Assert.That(child2.GetAllLookupForColumnInfoWhereItIsA(LookupType.AnyKey), Has.Length.EqualTo(1)); + Assert.That(child3.GetAllLookupForColumnInfoWhereItIsA(LookupType.AnyKey), Has.Length.EqualTo(1)); - Assert.IsTrue(parent.IsLookupTable()); - Assert.IsFalse(parent2.IsLookupTable()); + Assert.That(parent.IsLookupTable()); + Assert.That(parent2.IsLookupTable(), Is.False); + }); } finally { @@ -224,36 +227,48 @@ public void CompositeLookupTest() desc = new ColumnInfo(CatalogueRepository, "UnitTest_TestDescription", "int", pkTable); lookup = new Lookup(CatalogueRepository, desc, fk, pk, ExtractionJoinType.Left, null); - Assert.AreEqual(lookup.PrimaryKey.Name, pk.Name); - Assert.AreEqual(lookup.PrimaryKey.ID, pk.ID); + Assert.Multiple(() => + { + Assert.That(pk.Name, Is.EqualTo(lookup.PrimaryKey.Name)); + Assert.That(pk.ID, Is.EqualTo(lookup.PrimaryKey.ID)); - Assert.AreEqual(lookup.ForeignKey.Name, fk.Name); - Assert.AreEqual(lookup.ForeignKey.ID, fk.ID); + Assert.That(fk.Name, Is.EqualTo(lookup.ForeignKey.Name)); + Assert.That(fk.ID, Is.EqualTo(lookup.ForeignKey.ID)); - Assert.AreEqual(lookup.Description.Name, desc.Name); - Assert.AreEqual(lookup.Description.ID, desc.ID); + Assert.That(desc.Name, Is.EqualTo(lookup.Description.Name)); + Assert.That(desc.ID, Is.EqualTo(lookup.Description.ID)); + }); //Create the composite lookup composite = new LookupCompositeJoinInfo(CatalogueRepository, lookup, fk2, pk2); - Assert.AreEqual(composite.OriginalLookup_ID, lookup.ID); + Assert.Multiple(() => + { + Assert.That(lookup.ID, Is.EqualTo(composite.OriginalLookup_ID)); - Assert.AreEqual(composite.PrimaryKey.ID, pk2.ID); - Assert.AreEqual(composite.PrimaryKey_ID, pk2.ID); - Assert.AreEqual(composite.PrimaryKey.Name, pk2.Name); + Assert.That(pk2.ID, Is.EqualTo(composite.PrimaryKey.ID)); + }); + Assert.Multiple(() => + { + Assert.That(pk2.ID, Is.EqualTo(composite.PrimaryKey_ID)); + Assert.That(pk2.Name, Is.EqualTo(composite.PrimaryKey.Name)); - Assert.AreEqual(composite.ForeignKey.ID, fk2.ID); - Assert.AreEqual(composite.ForeignKey_ID, fk2.ID); - Assert.AreEqual(composite.ForeignKey.Name, fk2.Name); + Assert.That(fk2.ID, Is.EqualTo(composite.ForeignKey.ID)); + }); + Assert.Multiple(() => + { + Assert.That(fk2.ID, Is.EqualTo(composite.ForeignKey_ID)); + Assert.That(fk2.Name, Is.EqualTo(composite.ForeignKey.Name)); - //get a fresh copy out of memory now that we have created the Lookup composite key, confirm the integrity of that relationship - Assert.AreEqual(lookup.GetSupplementalJoins().Count(), 1); - Assert.AreEqual(lookup.GetSupplementalJoins().Cast().First().ID, composite.ID); + //get a fresh copy out of memory now that we have created the Lookup composite key, confirm the integrity of that relationship + Assert.That(lookup.GetSupplementalJoins().Count(), Is.EqualTo(1)); + Assert.That(composite.ID, Is.EqualTo(lookup.GetSupplementalJoins().Cast().First().ID)); + }); composite.DeleteInDatabase(); composite = null; - Assert.AreEqual(lookup.GetSupplementalJoins().Count(), 0); + Assert.That(lookup.GetSupplementalJoins().Count(), Is.EqualTo(0)); } catch (Exception ex) { @@ -313,16 +328,14 @@ public void CompositeLookupTest_SQL() var joinSQL = JoinHelper.GetJoinSQL(lookup); - Assert.AreEqual(joinSQL, - "UnitTest_Biochemistry Left JOIN UnitTest_BiochemistryLookup ON UnitTest_BCTestCode = UnitTest_TestCode"); + Assert.That(joinSQL, Is.EqualTo("UnitTest_Biochemistry Left JOIN UnitTest_BiochemistryLookup ON UnitTest_BCTestCode = UnitTest_TestCode")); //Create the composite lookup composite = new LookupCompositeJoinInfo(CatalogueRepository, lookup, fk2, pk2); var joinSQL_AfterAddingCompositeKey = JoinHelper.GetJoinSQL(lookup); - Assert.AreEqual(joinSQL_AfterAddingCompositeKey, - "UnitTest_Biochemistry Left JOIN UnitTest_BiochemistryLookup ON UnitTest_BCTestCode = UnitTest_TestCode AND UnitTest_BCHealthBoard = UnitTest_Healthboard"); + Assert.That(joinSQL_AfterAddingCompositeKey, Is.EqualTo("UnitTest_Biochemistry Left JOIN UnitTest_BiochemistryLookup ON UnitTest_BCTestCode = UnitTest_TestCode AND UnitTest_BCHealthBoard = UnitTest_Healthboard")); } catch (Exception ex) { @@ -352,7 +365,7 @@ public void LookupTest_CustomSql() { //this only works for MSSQL Servers if (CatalogueTableRepository.DiscoveredServer.DatabaseType != DatabaseType.MicrosoftSQLServer) - Assert.Ignore("This test only targets Microsft SQL Servers"); + Assert.Ignore("This test only targets Microsoft SQL Servers"); TableInfo fkTable = null; TableInfo pkTable = null; @@ -381,23 +394,24 @@ public void LookupTest_CustomSql() var joinSQL = JoinHelper.GetJoinSQL(lookup); - Assert.AreEqual(joinSQL, "UnitTest_Biochemistry Left JOIN UnitTest_BiochemistryLookup ON One = One"); + Assert.That(joinSQL, Is.EqualTo("UnitTest_Biochemistry Left JOIN UnitTest_BiochemistryLookup ON One = One")); //Create the custom lookup var cmd = new ExecuteCommandSetExtendedProperty(new ThrowImmediatelyActivator(RepositoryLocator), new[] { lookup }, ExtendedProperty.CustomJoinSql, - @"{0}.One={1}.One AND -({0}.Two = {0}.Two OR - ({0}.{Two} is null AND {1}.Two is null) -)"); + """ + {0}.One={1}.One AND + ({0}.Two = {0}.Two OR + ({0}.{Two} is null AND {1}.Two is null) + ) + """); cmd.Execute(); var joinSQL_AfterAddingCompositeKey = JoinHelper.GetJoinSQL(lookup); - Assert.AreEqual(joinSQL_AfterAddingCompositeKey, - "UnitTest_Biochemistry Left JOIN UnitTest_BiochemistryLookup ON UnitTest_Biochemistry.One=UnitTest_BiochemistryLookup.One AND (UnitTest_Biochemistry.Two = UnitTest_Biochemistry.Two OR (UnitTest_Biochemistry.{Two} is null AND UnitTest_BiochemistryLookup.Two is null) )"); + Assert.That(joinSQL_AfterAddingCompositeKey, Is.EqualTo("UnitTest_Biochemistry Left JOIN UnitTest_BiochemistryLookup ON UnitTest_Biochemistry.One=UnitTest_BiochemistryLookup.One AND (UnitTest_Biochemistry.Two = UnitTest_Biochemistry.Two OR (UnitTest_Biochemistry.{Two} is null AND UnitTest_BiochemistryLookup.Two is null) )")); } catch (Exception ex) { @@ -468,7 +482,7 @@ public void TestLookupCommand(LookupTestCase testCase) cmd.Execute(); //sql should not have changed because we didn't create an new ExtractionInformation virtual column - Assert.AreEqual(sqlBefore, GetSql(mainCata)); + Assert.That(GetSql(mainCata), Is.EqualTo(sqlBefore)); break; case LookupTestCase.SingleKeySingleDescription: cmd = new ExecuteCommandCreateLookup(CatalogueRepository, fkEi, descLine1, pk, null, true); @@ -476,8 +490,8 @@ public void TestLookupCommand(LookupTestCase testCase) //should have the lookup join and the virtual column _Desc var sqlAfter = GetSql(mainCata); - Assert.IsTrue(sqlAfter.Contains("JOIN")); - Assert.IsTrue(sqlAfter.Contains("SendingLocation_Desc")); + Assert.That(sqlAfter, Does.Contain("JOIN")); + Assert.That(sqlAfter, Does.Contain("SendingLocation_Desc")); break; default: throw new ArgumentOutOfRangeException(nameof(testCase)); diff --git a/Rdmp.Core.Tests/Curation/Integration/MEFCheckerTests.cs b/Rdmp.Core.Tests/Curation/Integration/MEFCheckerTests.cs index 31717b5486..c6924cf153 100644 --- a/Rdmp.Core.Tests/Curation/Integration/MEFCheckerTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/MEFCheckerTests.cs @@ -5,7 +5,6 @@ // You should have received a copy of the GNU General Public License along with RDMP. If not, see . using System; -using System.IO; using NUnit.Framework; using Rdmp.Core.Curation.Checks; using Rdmp.Core.Curation.Data; @@ -19,7 +18,7 @@ public class MEFCheckerTests : UnitTests [Test] public void FindClass_WrongCase_FoundAnyway() { - Assert.AreEqual(typeof(Catalogue), Core.Repositories.MEF.GetType("catalogue")); + Assert.That(Core.Repositories.MEF.GetType("catalogue"), Is.EqualTo(typeof(Catalogue))); } [Test] @@ -27,9 +26,8 @@ public void FindClass_EmptyString() { var m = new MEFChecker("", s => Assert.Fail()); var ex = Assert.Throws(() => m.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual( - "MEFChecker was asked to check for the existence of an Export class but the _classToFind string was empty", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("MEFChecker was asked to check for the existence of an Export class but the _classToFind string was empty")); } [Test] @@ -53,8 +51,7 @@ public void FindClass_NonExistent() { var m = new MEFChecker("CatalogueLibrary.UncleSam", s => Assert.Fail()); var ex = Assert.Throws(() => m.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.Contains( - "Could not find MEF class called CatalogueLibrary.UncleSam in LoadModuleAssembly.GetAllTypes() and couldn't even find any with the same basic name", - ex?.Message); + Assert.That( + ex?.Message, Does.Contain("Could not find MEF class called CatalogueLibrary.UncleSam in LoadModuleAssembly.GetAllTypes() and couldn't even find any with the same basic name")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/MementoTests.cs b/Rdmp.Core.Tests/Curation/Integration/MementoTests.cs index 7998386c7d..7ae2244f92 100644 --- a/Rdmp.Core.Tests/Curation/Integration/MementoTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/MementoTests.cs @@ -25,18 +25,21 @@ public void FakeMemento_Catalogue_Modify() mem.SaveToDatabase(); mem.BeforeYaml = "haha"; - Assert.AreEqual("haha", mem.BeforeYaml); + Assert.That(mem.BeforeYaml, Is.EqualTo("haha")); mem.RevertToDatabaseState(); - Assert.AreEqual("yar", mem.BeforeYaml); + Assert.That(mem.BeforeYaml, Is.EqualTo("yar")); var mem2 = CatalogueRepository.GetObjectByID(mem.ID); - Assert.AreEqual(g, new Guid(mem2.Commit.Transaction)); - Assert.AreEqual("blerg", mem2.AfterYaml); - Assert.AreEqual("yar", mem2.BeforeYaml); - Assert.AreEqual(MementoType.Modify, mem2.Type); - Assert.AreEqual(Environment.UserName, mem2.Commit.Username); - Assert.AreEqual(c, mem2.GetReferencedObject(RepositoryLocator)); + Assert.Multiple(() => + { + Assert.That(new Guid(mem2.Commit.Transaction), Is.EqualTo(g)); + Assert.That(mem2.AfterYaml, Is.EqualTo("blerg")); + Assert.That(mem2.BeforeYaml, Is.EqualTo("yar")); + Assert.That(mem2.Type, Is.EqualTo(MementoType.Modify)); + Assert.That(mem2.Commit.Username, Is.EqualTo(Environment.UserName)); + Assert.That(mem2.GetReferencedObject(RepositoryLocator), Is.EqualTo(c)); + }); } @@ -53,12 +56,15 @@ public void FakeMemento_Catalogue_Add() foreach (var check in new[] { mem, CatalogueRepository.GetObjectByID(mem.ID) }) { - Assert.IsNull(check.BeforeYaml); - Assert.AreEqual(g, new Guid(check.Commit.Transaction)); - Assert.AreEqual("blerg", check.AfterYaml); - Assert.AreEqual(MementoType.Add, check.Type); - Assert.AreEqual(Environment.UserName, check.Commit.Username); - Assert.AreEqual(c, check.GetReferencedObject(RepositoryLocator)); + Assert.Multiple(() => + { + Assert.That(check.BeforeYaml, Is.Null); + Assert.That(new Guid(check.Commit.Transaction), Is.EqualTo(g)); + Assert.That(check.AfterYaml, Is.EqualTo("blerg")); + Assert.That(check.Type, Is.EqualTo(MementoType.Add)); + Assert.That(check.Commit.Username, Is.EqualTo(Environment.UserName)); + Assert.That(check.GetReferencedObject(RepositoryLocator), Is.EqualTo(c)); + }); } } @@ -75,12 +81,15 @@ public void FakeMemento_Catalogue_Delete() foreach (var check in new[] { mem, CatalogueRepository.GetObjectByID(mem.ID) }) { - Assert.IsNull(check.AfterYaml); - Assert.AreEqual(g, new Guid(check.Commit.Transaction)); - Assert.AreEqual("blah", check.BeforeYaml); - Assert.AreEqual(MementoType.Delete, check.Type); - Assert.AreEqual(Environment.UserName, check.Commit.Username); - Assert.AreEqual(c, check.GetReferencedObject(RepositoryLocator)); + Assert.Multiple(() => + { + Assert.That(check.AfterYaml, Is.Null); + Assert.That(new Guid(check.Commit.Transaction), Is.EqualTo(g)); + Assert.That(check.BeforeYaml, Is.EqualTo("blah")); + Assert.That(check.Type, Is.EqualTo(MementoType.Delete)); + Assert.That(check.Commit.Username, Is.EqualTo(Environment.UserName)); + Assert.That(check.GetReferencedObject(RepositoryLocator), Is.EqualTo(c)); + }); } } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/MetadataLoggingConfigurationChecksTests.cs b/Rdmp.Core.Tests/Curation/Integration/MetadataLoggingConfigurationChecksTests.cs index e5ecbfce88..fe41cd5a66 100644 --- a/Rdmp.Core.Tests/Curation/Integration/MetadataLoggingConfigurationChecksTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/MetadataLoggingConfigurationChecksTests.cs @@ -25,7 +25,7 @@ public void Test_NoLoggingTask() var cata2 = WhenIHaveA(); cata2.LoadMetadata_ID = lmd.ID; - Assert.AreEqual(2, lmd.GetAllCatalogues().Count()); + Assert.That(lmd.GetAllCatalogues().Count(), Is.EqualTo(2)); var checks = new MetadataLoggingConfigurationChecks(lmd); var toMem = new ToMemoryCheckNotifier(); @@ -45,7 +45,7 @@ public void Test_MismatchedLoggingTask() cata1.LoggingDataTask = "OMG YEAGH"; - Assert.AreEqual(2, lmd.GetAllCatalogues().Count()); + Assert.That(lmd.GetAllCatalogues().Count(), Is.EqualTo(2)); var checks = new MetadataLoggingConfigurationChecks(lmd); var toMem = new ToMemoryCheckNotifier(); @@ -67,7 +67,7 @@ public void Test_MissingLoggingServer() cata2.LoggingDataTask = "OMG YEAGH"; cata2.LiveLoggingServer_ID = null; - Assert.AreEqual(2, lmd.GetAllCatalogues().Count()); + Assert.That(lmd.GetAllCatalogues().Count(), Is.EqualTo(2)); var checks = new MetadataLoggingConfigurationChecks(lmd); var toMem = new ToMemoryCheckNotifier(); @@ -97,7 +97,7 @@ public void Test_MissingLoggingServer_UseDefault() var defaults = RepositoryLocator.CatalogueRepository; defaults.SetDefault(PermissableDefaults.LiveLoggingServer_ID, eds); - Assert.AreEqual(2, lmd.GetAllCatalogues().Count()); + Assert.That(lmd.GetAllCatalogues().Count(), Is.EqualTo(2)); var checks = new MetadataLoggingConfigurationChecks(lmd); var toMem = new ToMemoryCheckNotifier(); @@ -111,7 +111,10 @@ private static void AssertFailWithFix(string expectedMessage, string expectedFix { var msg = toMem.Messages.First(m => m.Result == CheckResult.Fail); - Assert.AreEqual(expectedMessage, msg.Message, "Expected error message was wrong"); - Assert.AreEqual(expectedFix, msg.ProposedFix, "Expected proposed fix was wrong"); + Assert.Multiple(() => + { + Assert.That(msg.Message, Is.EqualTo(expectedMessage), "Expected error message was wrong"); + Assert.That(msg.ProposedFix, Is.EqualTo(expectedFix), "Expected proposed fix was wrong"); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/MySqlTriggerImplementerTests.cs b/Rdmp.Core.Tests/Curation/Integration/MySqlTriggerImplementerTests.cs index 5163722df7..c6569ac500 100644 --- a/Rdmp.Core.Tests/Curation/Integration/MySqlTriggerImplementerTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/MySqlTriggerImplementerTests.cs @@ -18,6 +18,6 @@ public class MySqlTriggerImplementerTests [TestCase("10.5.64-MariaDB", false)] public void TestOldNew(string versionString, bool expectToUseOldMethod) { - Assert.AreEqual(expectToUseOldMethod, MySqlTriggerImplementer.UseOldDateTimeDefaultMethod(versionString)); + Assert.That(MySqlTriggerImplementer.UseOldDateTimeDefaultMethod(versionString), Is.EqualTo(expectToUseOldMethod)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/BetweenCatalogueAndDataExportObscureDependencyFinderTests.cs b/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/BetweenCatalogueAndDataExportObscureDependencyFinderTests.cs index cb86dda2fc..7ac276e32a 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/BetweenCatalogueAndDataExportObscureDependencyFinderTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/BetweenCatalogueAndDataExportObscureDependencyFinderTests.cs @@ -31,13 +31,11 @@ public void PreventDeletingCatalogueBecauseOfLinkedDatasetTest() //and suddenly we cannot delete the catalogue var ex = Assert.Throws(() => obscura.ThrowIfDeleteDisallowed(cata)); - Assert.IsTrue(ex.Message.Contains( - "Cannot delete Catalogue MyCata because there are ExtractableDataSets which depend on them ")); + Assert.That(ex.Message, Does.Contain("Cannot delete Catalogue MyCata because there are ExtractableDataSets which depend on them ")); //also if we try to force through a delete it should behave in identical manner var ex2 = Assert.Throws(cata.DeleteInDatabase); - Assert.IsTrue(ex2.Message.Contains( - "Cannot delete Catalogue MyCata because there are ExtractableDataSets which depend on them ")); + Assert.That(ex2.Message, Does.Contain("Cannot delete Catalogue MyCata because there are ExtractableDataSets which depend on them ")); //now we delete the linked dataset dataset.DeleteInDatabase(); @@ -48,9 +46,12 @@ public void PreventDeletingCatalogueBecauseOfLinkedDatasetTest() //and the delete works too cata.DeleteInDatabase(); - //both objects still exist in memory of course but we should be able to see they have disapeared - Assert.IsTrue(dataset.HasLocalChanges().Evaluation == ChangeDescription.DatabaseCopyWasDeleted); - Assert.IsTrue(cata.HasLocalChanges().Evaluation == ChangeDescription.DatabaseCopyWasDeleted); + Assert.Multiple(() => + { + //both objects still exist in memory of course but we should be able to see they have disapeared + Assert.That(dataset.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.DatabaseCopyWasDeleted)); + Assert.That(cata.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.DatabaseCopyWasDeleted)); + }); } [Test] @@ -66,8 +67,7 @@ public void AllowDeletingWhenDataExportManagerIsNotSet() //we cannot delete it because there is a dependency var ex = Assert.Throws(() => obscura1.ThrowIfDeleteDisallowed(cata)); - Assert.IsTrue(ex.Message.Contains( - "Cannot delete Catalogue MyCata because there are ExtractableDataSets which depend on them ")); + Assert.That(ex.Message, Does.Contain("Cannot delete Catalogue MyCata because there are ExtractableDataSets which depend on them ")); //the second finder simulates when the repository locator doesn't have a record of the data export repository so it is unable to check it so it will let you delete it just fine Assert.DoesNotThrow(() => obscura2.ThrowIfDeleteDisallowed(cata)); diff --git a/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/ObjectSharingObscureDependencyFinderTests.cs b/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/ObjectSharingObscureDependencyFinderTests.cs index 7d3806b528..90262e4b62 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/ObjectSharingObscureDependencyFinderTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/ObjectSharingObscureDependencyFinderTests.cs @@ -5,7 +5,6 @@ // You should have received a copy of the GNU General Public License along with RDMP. If not, see . using System; -using System.Linq; using NUnit.Framework; using Rdmp.Core.Curation.Data; using Rdmp.Core.Curation.Data.ImportExport; @@ -34,19 +33,21 @@ public void TestPruning() var c2 = new Catalogue(CatalogueRepository, "Catapault (Import)"); var ci2 = new CatalogueItem(CatalogueRepository, c2, "string (Import)"); - Assert.AreEqual(CatalogueRepository.GetAllObjects().Length, 0); + Assert.That(CatalogueRepository.GetAllObjects(), Is.Empty); var ec = _share.GetNewOrExistingExportFor(c); var eci = _share.GetNewOrExistingExportFor(ci); _share.GetImportAs(ec.SharingUID, c2); _share.GetImportAs(eci.SharingUID, ci2); - Assert.AreEqual(2, CatalogueRepository.GetAllObjects().Length); - Assert.AreEqual(2, CatalogueRepository.GetAllObjects().Length); - Assert.AreEqual(2, - CatalogueRepository.GetAllObjects() - .Length); //successive calls shouldhn't generate extra entries since they are same obj - Assert.AreEqual(2, CatalogueRepository.GetAllObjects().Length); + Assert.Multiple(() => + { + Assert.That(CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(2)); + Assert.That(CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(2)); + }); + Assert.That(CatalogueRepository.GetAllObjects() +, Has.Length.EqualTo(2)); //successive calls shouldn't generate extra entries since they are same obj + Assert.That(CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(2)); //cannot delete the shared object Assert.Throws(c.DeleteInDatabase); @@ -55,7 +56,7 @@ public void TestPruning() Assert.DoesNotThrow(c2.DeleteInDatabase); //now that we deleted the import it should have deleted everything else including the CatalogueItem import which magically disapeared when we deleted the Catalogue via database level cascade events - Assert.AreEqual(0, CatalogueRepository.GetAllObjects().Length); + Assert.That(CatalogueRepository.GetAllObjects(), Is.Empty); _share.GetImportAs(eci.SharingUID, ci2); } @@ -66,12 +67,12 @@ public void CannotDeleteSharedObjectTest() //create a test catalogue var c = new Catalogue(CatalogueRepository, "blah"); - Assert.IsFalse(_share.IsExportedObject(c)); + Assert.That(_share.IsExportedObject(c), Is.False); //make it exportable var exportDefinition = _share.GetNewOrExistingExportFor(c); - Assert.IsTrue(_share.IsExportedObject(c)); + Assert.That(_share.IsExportedObject(c)); //cannot delete because object is shared externally Assert.Throws(c.DeleteInDatabase); @@ -80,7 +81,7 @@ public void CannotDeleteSharedObjectTest() exportDefinition.DeleteInDatabase(); //no longer shared - Assert.IsFalse(_share.IsExportedObject(c)); + Assert.That(_share.IsExportedObject(c), Is.False); //now we can delete it c.DeleteInDatabase(); @@ -98,13 +99,13 @@ public void CascadeDeleteImportDefinitions() var importDefinition = _share.GetImportAs(exportDefinition.SharingUID, p2); //import definition exists - Assert.IsTrue(importDefinition.Exists()); + Assert.That(importDefinition.Exists()); //delete local import p2.DeleteInDatabase(); //cascade should have deleted the import definition since the imported object version is gone - Assert.IsFalse(importDefinition.Exists()); + Assert.That(importDefinition.Exists(), Is.False); //clear SetUp the exported version too exportDefinition.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/ValidationXMLObscureDependencyFinderTests.cs b/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/ValidationXMLObscureDependencyFinderTests.cs index 617c66c6aa..a45ddaf0a9 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/ValidationXMLObscureDependencyFinderTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ObscureDependencyTests/ValidationXMLObscureDependencyFinderTests.cs @@ -31,7 +31,7 @@ public void TestGettingTheUsualSuspects() finder.ThrowIfDeleteDisallowed(null); //this guy should be a usual suspect! - Assert.IsTrue(finder.TheUsualSuspects.Any(s => s.Type == typeof(ReferentialIntegrityConstraint))); + Assert.That(finder.TheUsualSuspects.Any(s => s.Type == typeof(ReferentialIntegrityConstraint))); var testXML = @" @@ -50,7 +50,7 @@ public void TestGettingTheUsualSuspects() "; - Assert.IsTrue(finder.TheUsualSuspects.Select(suspect => string.Format(suspect.Pattern, 10029)) + Assert.That(finder.TheUsualSuspects.Select(suspect => string.Format(suspect.Pattern, 10029)) .Any(pattern => Regex.IsMatch(testXML, pattern, RegexOptions.Singleline))); } @@ -66,10 +66,10 @@ public void DeleteAReferencedValidationXML() var worked = Validator.LoadFromXml(testData.catalogue.ValidatorXML); //notice that it is the ID of the referenced column that is maintained not the name of it! that is because we need to use a data access portal to get the contents of the column which might be in a different table (and normally would be) - Assert.IsFalse(testData.catalogue.ValidatorXML.Contains("previous_address_L2")); - Assert.IsTrue(testData.catalogue.ValidatorXML.Contains(l2ColumnInfo.ID.ToString())); + Assert.That(testData.catalogue.ValidatorXML, Does.Not.Contain("previous_address_L2")); + Assert.That(testData.catalogue.ValidatorXML, Does.Contain(l2ColumnInfo.ID.ToString())); - Assert.IsTrue(testData.catalogue.ValidatorXML.Contains("previous_address_L1")); + Assert.That(testData.catalogue.ValidatorXML, Does.Contain("previous_address_L1")); //we expect the validation XML to find the reference var finder = new ValidationXMLObscureDependencyFinder(RepositoryLocator); @@ -77,7 +77,7 @@ public void DeleteAReferencedValidationXML() //and explode Assert.Throws(() => finder.ThrowIfDeleteDisallowed(l2ColumnInfo)); - Assert.AreEqual(0, finder.CataloguesWithBrokenValidationXml.Count); + Assert.That(finder.CataloguesWithBrokenValidationXml, Is.Empty); //now clear the validation XML testData.catalogue.ValidatorXML = @@ -86,7 +86,7 @@ public void DeleteAReferencedValidationXML() //column info should be deleteable but only because we got ourselves onto the forbidlist Assert.DoesNotThrow(() => finder.ThrowIfDeleteDisallowed(l2ColumnInfo)); - Assert.AreEqual(1, finder.CataloguesWithBrokenValidationXml.Count); + Assert.That(finder.CataloguesWithBrokenValidationXml, Has.Count.EqualTo(1)); testData.catalogue.ValidatorXML = ""; testData.catalogue.SaveToDatabase(); @@ -145,9 +145,8 @@ public void TestRunningSetupMultipleTimes() startup.DoStartup(IgnoreAllErrorsCheckNotifier.Instance); //there should not be any replication! and doubling SetUp! - Assert.AreEqual(numberAfterFirstRun, - ((CatalogueObscureDependencyFinder)CatalogueRepository.ObscureDependencyFinder) - .OtherDependencyFinders.Count); + Assert.That(((CatalogueObscureDependencyFinder)CatalogueRepository.ObscureDependencyFinder) + .OtherDependencyFinders, Has.Count.EqualTo(numberAfterFirstRun)); } #region setup test data with some validation rule diff --git a/Rdmp.Core.Tests/Curation/Integration/PasswordEncryptionKeyLocationTests.cs b/Rdmp.Core.Tests/Curation/Integration/PasswordEncryptionKeyLocationTests.cs index d1b1f1559b..ddfa9cec62 100644 --- a/Rdmp.Core.Tests/Curation/Integration/PasswordEncryptionKeyLocationTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/PasswordEncryptionKeyLocationTests.cs @@ -33,10 +33,10 @@ public void NoKeyFileToStartWith() var keyLocation = new PasswordEncryptionKeyLocation(CatalogueRepository); //there shouldn't already be a key - Assert.IsNull(keyLocation.GetKeyFileLocation()); + Assert.That(keyLocation.GetKeyFileLocation(), Is.Null); var e = Assert.Throws(keyLocation.DeleteKey); - Assert.AreEqual("Cannot delete key because there is no key file configured", e.Message); + Assert.That(e.Message, Is.EqualTo("Cannot delete key because there is no key file configured")); } [Test] @@ -48,12 +48,15 @@ public void CreateKeyFile() Console.WriteLine($"Key file location is:{file.FullName}"); Console.WriteLine($"Text put into file is:{Environment.NewLine}{File.ReadAllText(file.FullName)}"); - Assert.IsTrue(file.FullName.EndsWith("my.key")); + Assert.Multiple(() => + { + Assert.That(file.FullName, Does.EndWith("my.key")); - Assert.AreEqual(file.FullName, keyLocation.GetKeyFileLocation()); + Assert.That(keyLocation.GetKeyFileLocation(), Is.EqualTo(file.FullName)); + }); keyLocation.DeleteKey(); - Assert.IsNull(keyLocation.GetKeyFileLocation()); + Assert.That(keyLocation.GetKeyFileLocation(), Is.Null); } [Test] @@ -64,12 +67,15 @@ public void Encrypt() Console.WriteLine($"String is:{value}"); var encrypter = new EncryptedString(CatalogueRepository); - Assert.IsFalse(encrypter.IsStringEncrypted(value)); + Assert.That(encrypter.IsStringEncrypted(value), Is.False); //should do pass through encryption encrypter.Value = value; - Assert.AreNotEqual(value, encrypter.Value); - Assert.AreEqual(value, encrypter.GetDecryptedValue()); + Assert.Multiple(() => + { + Assert.That(encrypter.Value, Is.Not.EqualTo(value)); + Assert.That(encrypter.GetDecryptedValue(), Is.EqualTo(value)); + }); Console.WriteLine($"Encrypted (stock) is:{encrypter.Value}"); Console.WriteLine($"Decrypted (stock) is:{encrypter.GetDecryptedValue()}"); @@ -82,14 +88,13 @@ public void Encrypt() var s = CatalogueRepository.EncryptionManager.GetEncrypter(); var exception = Assert.Throws(() => s.Decrypt(encrypter.Value)); - Assert.IsTrue(exception.Message.StartsWith( - "Could not decrypt an encrypted string, possibly you are trying to decrypt it after having changed the PrivateKey ")); + Assert.That(exception.Message, Does.StartWith("Could not decrypt an encrypted string, possibly you are trying to decrypt it after having changed the PrivateKey ")); var encrypted = s.Encrypt(value); Console.WriteLine($"Encrypted (with key) is:{encrypted}"); Console.WriteLine($"Decrypted (with key) is:{s.Decrypt(encrypted)}"); - Assert.IsTrue(encrypter.IsStringEncrypted(encrypted)); + Assert.That(encrypter.IsStringEncrypted(encrypted)); keyLocation.DeleteKey(); } diff --git a/Rdmp.Core.Tests/Curation/Integration/PipelineTests.cs b/Rdmp.Core.Tests/Curation/Integration/PipelineTests.cs index a2904766d2..af60e4f97c 100644 --- a/Rdmp.Core.Tests/Curation/Integration/PipelineTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/PipelineTests.cs @@ -25,14 +25,14 @@ public void SetupAndSaveAPipeline() try { - Assert.AreEqual(pipeline.Name, "Bob"); + Assert.That(pipeline.Name, Is.EqualTo("Bob")); var pipelineComponent = new PipelineComponent(CatalogueRepository, pipeline, typeof(BasicAnonymisationEngine), 0); try { - Assert.AreEqual(pipelineComponent.Class, typeof(BasicAnonymisationEngine).FullName); + Assert.That(typeof(BasicAnonymisationEngine).FullName, Is.EqualTo(pipelineComponent.Class)); var argument1 = (PipelineComponentArgument)pipelineComponent.CreateNewArgument(); var argument2 = new PipelineComponentArgument(CatalogueRepository, pipelineComponent); @@ -52,7 +52,7 @@ public void SetupAndSaveAPipeline() argument2.SaveToDatabase(); var argument2Copy = CatalogueRepository.GetObjectByID(argument2.ID); - Assert.AreEqual(dt, argument2Copy.GetValueAsSystemType()); + Assert.That(argument2Copy.GetValueAsSystemType(), Is.EqualTo(dt)); } finally { @@ -84,15 +84,21 @@ public void ClonePipelineNaming() var clone2 = p.Clone(); var clone3 = p.Clone(); - Assert.AreEqual("My Pipe (Clone)", clone1.Name); - Assert.AreEqual("My Pipe (Clone2)", clone2.Name); - Assert.AreEqual("My Pipe (Clone3)", clone3.Name); + Assert.Multiple(() => + { + Assert.That(clone1.Name, Is.EqualTo("My Pipe (Clone)")); + Assert.That(clone2.Name, Is.EqualTo("My Pipe (Clone2)")); + Assert.That(clone3.Name, Is.EqualTo("My Pipe (Clone3)")); + }); var cloneOfClone1 = clone3.Clone(); var cloneOfClone2 = clone3.Clone(); - Assert.AreEqual("My Pipe (Clone3) (Clone)", cloneOfClone1.Name); - Assert.AreEqual("My Pipe (Clone3) (Clone2)", cloneOfClone2.Name); + Assert.Multiple(() => + { + Assert.That(cloneOfClone1.Name, Is.EqualTo("My Pipe (Clone3) (Clone)")); + Assert.That(cloneOfClone2.Name, Is.EqualTo("My Pipe (Clone3) (Clone2)")); + }); } @@ -133,37 +139,39 @@ public void CloneAPipeline() //Execute the cloning process var p2 = p.Clone(); - Assert.AreNotEqual(p2, p); - Assert.AreNotEqual(p2.ID, p.ID); + Assert.That(p, Is.Not.EqualTo(p2)); + Assert.Multiple(() => + { + Assert.That(p.ID, Is.Not.EqualTo(p2.ID)); - Assert.AreEqual(p2.Name, $"{p.Name} (Clone)"); + Assert.That($"{p.Name} (Clone)", Is.EqualTo(p2.Name)); - Assert.AreEqual(componentsBefore * 2, - RepositoryLocator.CatalogueRepository.GetAllObjects().Length); - Assert.AreEqual(argumentsBefore * 2, - RepositoryLocator.CatalogueRepository.GetAllObjects().Length); + Assert.That(RepositoryLocator.CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(componentsBefore * 2)); + Assert.That(RepositoryLocator.CatalogueRepository.GetAllObjects(), Has.Length.EqualTo(argumentsBefore * 2)); - //p the original should have a pipeline component that has the value we set earlier - Assert.AreEqual( - p.PipelineComponents.Single(c => c.Class == typeof(ColumnRenamer).ToString()).PipelineComponentArguments - .Single(a => a.Name == "ColumnNameToFind").Value, - "MyMostCoolestColumnEver" - ); + //p the original should have a pipeline component that has the value we set earlier + Assert.That( + p.PipelineComponents.Single(static c => c.Class == typeof(ColumnRenamer).ToString()).PipelineComponentArguments + .Single(static a => a.Name == "ColumnNameToFind").Value, Is.EqualTo("MyMostCoolestColumnEver" + )); - //p2 the clone should have a pipeline component too since it's a clone - Assert.AreEqual( - p2.PipelineComponents.Single(c => c.Class == typeof(ColumnRenamer).ToString()).PipelineComponentArguments - .Single(a => a.Name == "ColumnNameToFind").Value, - "MyMostCoolestColumnEver" - ); + //p2 the clone should have a pipeline component too since it's a clone + Assert.That( + p2.PipelineComponents.Single(static c => c.Class == typeof(ColumnRenamer).ToString()).PipelineComponentArguments + .Single(static a => a.Name == "ColumnNameToFind").Value, Is.EqualTo("MyMostCoolestColumnEver" + )); - //both should have source and destination components - Assert.NotNull(p2.DestinationPipelineComponent_ID); - Assert.NotNull(p2.SourcePipelineComponent_ID); + //both should have source and destination components + Assert.That(p2.DestinationPipelineComponent_ID, Is.Not.Null); + Assert.That(p2.SourcePipelineComponent_ID, Is.Not.Null); + }); - //but with different IDs because they are clones - Assert.AreNotEqual(p.DestinationPipelineComponent_ID, p2.DestinationPipelineComponent_ID); - Assert.AreNotEqual(p.SourcePipelineComponent_ID, p2.SourcePipelineComponent_ID); + Assert.Multiple(() => + { + //but with different IDs because they are clones + Assert.That(p2.DestinationPipelineComponent_ID, Is.Not.EqualTo(p.DestinationPipelineComponent_ID)); + Assert.That(p2.SourcePipelineComponent_ID, Is.Not.EqualTo(p.SourcePipelineComponent_ID)); + }); p.DeleteInDatabase(); p2.DeleteInDatabase(); @@ -190,12 +198,15 @@ public void CloneAPipeline_BrokenPipes() p.SourcePipelineComponent_ID = source.ID; p.SaveToDatabase(); - Assert.AreEqual("fffffzololz", p.Source.GetAllArguments().Single().Type); + Assert.That(p.Source.GetAllArguments().Single().Type, Is.EqualTo("fffffzololz")); var clone = p.Clone(); - Assert.AreEqual(clone.Source.Class, p.Source.Class); - Assert.AreEqual("fffffzololz", clone.Source.GetAllArguments().Single().Type); + Assert.Multiple(() => + { + Assert.That(p.Source.Class, Is.EqualTo(clone.Source.Class)); + Assert.That(clone.Source.GetAllArguments().Single().Type, Is.EqualTo("fffffzololz")); + }); p.DeleteInDatabase(); clone.DeleteInDatabase(); @@ -219,7 +230,7 @@ public void DeletePipelineSource_ClearsReference() p.RevertToDatabaseState(); // should also clear the reference - Assert.IsNull(p.SourcePipelineComponent_ID); + Assert.That(p.SourcePipelineComponent_ID, Is.Null); } [Test] @@ -240,6 +251,6 @@ public void DeletePipelineDestination_ClearsReference() p.RevertToDatabaseState(); // should also clear the reference - Assert.IsNull(p.DestinationPipelineComponent_ID); + Assert.That(p.DestinationPipelineComponent_ID, Is.Null); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/AggregateDataBasedTests.cs b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/AggregateDataBasedTests.cs index 88c2f6051a..285e22ecb4 100644 --- a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/AggregateDataBasedTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/AggregateDataBasedTests.cs @@ -80,7 +80,7 @@ private DiscoveredTable UploadTestDataAsTableToServer(DatabaseType type, out ICa uploader.Dispose(listener, null); var tbl = db.ExpectTable(uploader.TargetTableName); - Assert.IsTrue(tbl.Exists()); + Assert.That(tbl.Exists()); catalogue = Import(tbl, out tableinfo, out _, out _, out extractionInformations); @@ -132,8 +132,7 @@ private static void AddWHEREToBuilder_CategoryIsTOrNumberGreaterThan42(Aggregate builder.RootFilterContainer = ORContainer; } - private AggregateConfiguration SetupAggregateWithAxis(DatabaseType type, - ExtractionInformation[] extractionInformations, + private AggregateConfiguration SetupAggregateWithAxis(ExtractionInformation[] extractionInformations, ICatalogue catalogue, out AggregateDimension axisDimension) { var dateDimension = @@ -151,8 +150,7 @@ private AggregateConfiguration SetupAggregateWithAxis(DatabaseType type, return configuration; } - private AggregateConfiguration SetupAggregateWithPivot(DatabaseType type, - ExtractionInformation[] extractionInformations, + private AggregateConfiguration SetupAggregateWithPivot(ExtractionInformation[] extractionInformations, ICatalogue catalogue, out AggregateDimension axisDimension, out AggregateDimension pivotDimension) { var axisCol = @@ -259,7 +257,7 @@ public void GroupBy_CategoryWithSum_Correct(DatabaseType type) VerifyRowExist(resultTable, "F", 60); VerifyRowExist(resultTable, "E&, %a' mp;E", 137); VerifyRowExist(resultTable, "G", 100); - Assert.AreEqual(4, resultTable.Rows.Count); + Assert.That(resultTable.Rows, Has.Count.EqualTo(4)); } finally { @@ -299,7 +297,7 @@ public void GroupBy_CategoryWithSum_WHEREStatement(DatabaseType type) //VerifyRowExist(resultTable, "F", 60); //F does not have any records over 42 and isn't T so shouldnt be matched VerifyRowExist(resultTable, "E&, %a' mp;E", 59); //E has 1 records over 42 VerifyRowExist(resultTable, "G", 100); //47 + 53 - Assert.AreEqual(3, resultTable.Rows.Count); + Assert.That(resultTable.Rows, Has.Count.EqualTo(3)); } finally { @@ -316,7 +314,7 @@ public void GroupBy_AxisWithSum_Correct(DatabaseType type) out var tableInfo); //setup the aggregate with axis - var configuration = SetupAggregateWithAxis(type, extractionInformations, catalogue, out var dimension); + var configuration = SetupAggregateWithAxis(extractionInformations, catalogue, out var dimension); configuration.CountSQL = "sum(NumberInTrouble)"; configuration.SaveToDatabase(); @@ -330,7 +328,7 @@ public void GroupBy_AxisWithSum_Correct(DatabaseType type) var resultTable = GetResultForBuilder(builder, tbl); //axis is ordered ascending by date starting in 2000 so that row should come first - Assert.IsTrue(AreBasicallyEquals("2000", resultTable.Rows[0][0])); + Assert.That(AreBasicallyEquals("2000", resultTable.Rows[0][0])); VerifyRowExist(resultTable, "2000", null); //because it is a SUM the ANSI return should be null not 0 since it is a sum of no records @@ -357,7 +355,7 @@ public void GroupBy_AxisWithCount_HAVING(DatabaseType type) out var tableInfo); //setup the aggregate with axis - var configuration = SetupAggregateWithAxis(type, extractionInformations, catalogue, out var dimension); + var configuration = SetupAggregateWithAxis(extractionInformations, catalogue, out var dimension); configuration.CountSQL = "count(*)"; configuration.HavingSQL = "count(*)>3"; //matches only years with more than 3 records @@ -372,7 +370,7 @@ public void GroupBy_AxisWithCount_HAVING(DatabaseType type) var resultTable = GetResultForBuilder(builder, tbl); //axis is ordered ascending by date starting in 2000 so that row should come first - Assert.IsTrue(AreBasicallyEquals("2000", resultTable.Rows[0][0])); + Assert.That(AreBasicallyEquals("2000", resultTable.Rows[0][0])); VerifyRowExist(resultTable, "2000", null); //records only showing where there are more than 3 records (HAVING refers to the year since there's no pivot) @@ -400,7 +398,7 @@ public void GroupBy_AxisWithCount_WHERECorrect(DatabaseType type) out var tableInfo); //setup the aggregate with axis - var configuration = SetupAggregateWithAxis(type, extractionInformations, catalogue, out var dimension); + var configuration = SetupAggregateWithAxis(extractionInformations, catalogue, out var dimension); configuration.CountSQL = "count(NumberInTrouble)"; configuration.SaveToDatabase(); @@ -415,7 +413,7 @@ public void GroupBy_AxisWithCount_WHERECorrect(DatabaseType type) var resultTable = GetResultForBuilder(builder, tbl); //axis is ordered ascending by date starting in 2000 so that row should come first - Assert.IsTrue(AreBasicallyEquals("2000", resultTable.Rows[0][0])); + Assert.That(AreBasicallyEquals("2000", resultTable.Rows[0][0])); VerifyRowExist(resultTable, "2000", null); VerifyRowExist(resultTable, "2001", 4); //4 are T or > 42 @@ -437,7 +435,7 @@ public void GroupBy_PivotWithSum_Correct(DatabaseType type) out var tableInfo); //setup the aggregate pivot (and axis) - var configuration = SetupAggregateWithPivot(type, extractionInformations, catalogue, out var axisDimension, + var configuration = SetupAggregateWithPivot(extractionInformations, catalogue, out var axisDimension, out var pivotDimension); configuration.CountSQL = "sum(NumberInTrouble)"; @@ -454,13 +452,16 @@ public void GroupBy_PivotWithSum_Correct(DatabaseType type) var resultTable = GetResultForBuilder(builder, tbl); - //axis is ordered ascending by date starting in 2000 so that row should come first - Assert.IsTrue(AreBasicallyEquals("2000", resultTable.Rows[0][0])); + Assert.Multiple(() => + { + //axis is ordered ascending by date starting in 2000 so that row should come first + Assert.That(AreBasicallyEquals("2000", resultTable.Rows[0][0])); - Assert.AreEqual("T", resultTable.Columns[1].ColumnName); - Assert.AreEqual("E&, %a' mp;E", resultTable.Columns[2].ColumnName); - Assert.AreEqual("F", resultTable.Columns[3].ColumnName); - Assert.AreEqual("G", resultTable.Columns[4].ColumnName); + Assert.That(resultTable.Columns[1].ColumnName, Is.EqualTo("T")); + Assert.That(resultTable.Columns[2].ColumnName, Is.EqualTo("E&, %a' mp;E")); + Assert.That(resultTable.Columns[3].ColumnName, Is.EqualTo("F")); + Assert.That(resultTable.Columns[4].ColumnName, Is.EqualTo("G")); + }); //T,E,F,G VerifyRowExist(resultTable, "2000", null, null, null, @@ -489,7 +490,7 @@ public void GroupBy_PivotWithSum_WHEREStatement(DatabaseType type) out var tableInfo); //setup the aggregate pivot (and axis) - var configuration = SetupAggregateWithPivot(type, extractionInformations, catalogue, out var axisDimension, + var configuration = SetupAggregateWithPivot(extractionInformations, catalogue, out var axisDimension, out var pivotDimension); configuration.CountSQL = "sum(NumberInTrouble)"; @@ -508,12 +509,15 @@ public void GroupBy_PivotWithSum_WHEREStatement(DatabaseType type) var resultTable = GetResultForBuilder(builder, tbl); - //axis is ordered ascending by date starting in 2000 so that row should come first - Assert.IsTrue(AreBasicallyEquals("2000", resultTable.Rows[0][0])); + Assert.Multiple(() => + { + //axis is ordered ascending by date starting in 2000 so that row should come first + Assert.That(AreBasicallyEquals("2000", resultTable.Rows[0][0])); - Assert.AreEqual("T", resultTable.Columns[1].ColumnName); - Assert.AreEqual("E&, %a' mp;E", resultTable.Columns[2].ColumnName); - Assert.AreEqual("G", resultTable.Columns[3].ColumnName); + Assert.That(resultTable.Columns[1].ColumnName, Is.EqualTo("T")); + Assert.That(resultTable.Columns[2].ColumnName, Is.EqualTo("E&, %a' mp;E")); + Assert.That(resultTable.Columns[3].ColumnName, Is.EqualTo("G")); + }); //T,E,G - F does not appear because WHERE throws it out (both counts are below 42) VerifyRowExist(resultTable, "2000", null, null, @@ -547,7 +551,7 @@ public void GroupBy_PivotWithSum_Top2BasedonCountColumnDesc(DatabaseType type) out var tableInfo); //setup the aggregate pivot (and axis) - var configuration = SetupAggregateWithPivot(type, extractionInformations, catalogue, out var axisDimension, + var configuration = SetupAggregateWithPivot(extractionInformations, catalogue, out var axisDimension, out var pivotDimension); configuration.CountSQL = "sum(NumberInTrouble)"; @@ -571,11 +575,14 @@ public void GroupBy_PivotWithSum_Top2BasedonCountColumnDesc(DatabaseType type) var resultTable = GetResultForBuilder(builder, tbl); - //axis is ordered ascending by date starting in 2000 so that row should come first - Assert.IsTrue(AreBasicallyEquals("2000", resultTable.Rows[0][0])); + Assert.Multiple(() => + { + //axis is ordered ascending by date starting in 2000 so that row should come first + Assert.That(AreBasicallyEquals("2000", resultTable.Rows[0][0])); - Assert.AreEqual("T", resultTable.Columns[1].ColumnName); - Assert.AreEqual("E&, %a' mp;E", resultTable.Columns[2].ColumnName); + Assert.That(resultTable.Columns[1].ColumnName, Is.EqualTo("T")); + Assert.That(resultTable.Columns[2].ColumnName, Is.EqualTo("E&, %a' mp;E")); + }); //T,E,G - F does not appear because WHERE throws it out (both counts are below 42) VerifyRowExist(resultTable, "2000", null, @@ -608,7 +615,7 @@ public void GroupBy_PivotWithSum_Top2AlphabeticalAsc_WHEREStatement(DatabaseType out var tableInfo); //setup the aggregate pivot (and axis) - var configuration = SetupAggregateWithPivot(type, extractionInformations, catalogue, out var axisDimension, + var configuration = SetupAggregateWithPivot(extractionInformations, catalogue, out var axisDimension, out var pivotDimension); configuration.CountSQL = "sum(NumberInTrouble)"; @@ -635,12 +642,15 @@ public void GroupBy_PivotWithSum_Top2AlphabeticalAsc_WHEREStatement(DatabaseType var resultTable = GetResultForBuilder(builder, tbl); - //axis is ordered ascending by date starting in 2000 so that row should come first - Assert.IsTrue(AreBasicallyEquals("2000", resultTable.Rows[0][0])); + Assert.Multiple(() => + { + //axis is ordered ascending by date starting in 2000 so that row should come first + Assert.That(AreBasicallyEquals("2000", resultTable.Rows[0][0])); - //sort in AggregateTopX is the pivot dimension asc (i.e. order alphabetically) - Assert.AreEqual("E&, %a' mp;E", resultTable.Columns[1].ColumnName); - Assert.AreEqual("G", resultTable.Columns[2].ColumnName); + //sort in AggregateTopX is the pivot dimension asc (i.e. order alphabetically) + Assert.That(resultTable.Columns[1].ColumnName, Is.EqualTo("E&, %a' mp;E")); + Assert.That(resultTable.Columns[2].ColumnName, Is.EqualTo("G")); + }); //E,G (note that only 1 value appears for E because WHERE throws out rest). Also note the two columns are E and G because that is Top 2 when alphabetically sorted of the pivot values (E,F,G,T) that match the filter (F doesn't) VerifyRowExist(resultTable, "2000", null, @@ -672,7 +682,7 @@ public void GroupBy_PivotWithSum_HAVING_Top1_WHERE(DatabaseType type) out var tableInfo); //setup the aggregate pivot (and axis) - var configuration = SetupAggregateWithPivot(type, extractionInformations, catalogue, out var axisDimension, + var configuration = SetupAggregateWithPivot(extractionInformations, catalogue, out var axisDimension, out var pivotDimension); configuration.CountSQL = "sum(NumberInTrouble)"; @@ -700,11 +710,14 @@ public void GroupBy_PivotWithSum_HAVING_Top1_WHERE(DatabaseType type) var resultTable = GetResultForBuilder(builder, tbl); - //axis is ordered ascending by date starting in 2000 so that row should come first - Assert.IsTrue(AreBasicallyEquals("2000", resultTable.Rows[0][0])); + Assert.Multiple(() => + { + //axis is ordered ascending by date starting in 2000 so that row should come first + Assert.That(AreBasicallyEquals("2000", resultTable.Rows[0][0])); - //where logic matches T in spades but HAVING statement throws it out for having more than 4 records total - Assert.AreEqual("E&, %a' mp;E", resultTable.Columns[1].ColumnName); + //where logic matches T in spades but HAVING statement throws it out for having more than 4 records total + Assert.That(resultTable.Columns[1].ColumnName, Is.EqualTo("E&, %a' mp;E")); + }); //Only E appears because of Top 1 pivot statement VerifyRowExist(resultTable, "2000", diff --git a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/MicrosoftAggregateBuilderTests.cs b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/MicrosoftAggregateBuilderTests.cs index 1933221130..67c406b287 100644 --- a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/MicrosoftAggregateBuilderTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/MicrosoftAggregateBuilderTests.cs @@ -19,7 +19,7 @@ public void TestAggregateBuilding_NoConfigurationOneDimension() var builder = new AggregateBuilder(null, "count(*)", null); builder.AddColumn(_dimension1); - Assert.AreEqual(CollapseWhitespace(@"/**/ + Assert.That(CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace(@"/**/ SELECT Col1, count(*) AS MyCount @@ -28,7 +28,7 @@ public void TestAggregateBuilding_NoConfigurationOneDimension() group by Col1 order by -Col1"), CollapseWhitespace(builder.SQL)); +Col1"))); } /// @@ -40,7 +40,7 @@ public void TestAggregateBuilding_AS_InCount() var builder = new AggregateBuilder(null, "count(cast(1 AS int))", null); builder.AddColumn(_dimension1); - Assert.AreEqual(CollapseWhitespace(@"/**/ + Assert.That(CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace(@"/**/ SELECT Col1, count(cast(1 AS int)) AS MyCount @@ -49,7 +49,7 @@ public void TestAggregateBuilding_AS_InCount() group by Col1 order by -Col1"), CollapseWhitespace(builder.SQL)); +Col1"))); } [Test] @@ -59,7 +59,7 @@ public void TestAggregateBuilding_NoConfigurationTwoDimension() builder.AddColumn(_dimension1); builder.AddColumn(_dimension2); - Assert.AreEqual(CollapseWhitespace(CollapseWhitespace(@"/**/ + Assert.That(CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace(CollapseWhitespace(@"/**/ SELECT Col1, Col2, @@ -71,7 +71,7 @@ group by Col2 order by Col1, -Col2")), CollapseWhitespace(builder.SQL)); +Col2")))); } [Test] @@ -81,7 +81,7 @@ public void TestAggregateBuilding_ConfigurationTwoDimension() builder.AddColumn(_dimension1); builder.AddColumn(_dimension2); - Assert.AreEqual(CollapseWhitespace(@"/*MyConfig*/ + Assert.That(CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace(@"/*MyConfig*/ SELECT Col1, Col2, @@ -93,7 +93,7 @@ group by Col2 order by Col1, -Col2"), CollapseWhitespace(builder.SQL)); +Col2"))); } [Test] @@ -102,7 +102,7 @@ public void TwoTopXObjects() var topX1 = new AggregateTopX(CatalogueRepository, _configuration, 10); var ex = Assert.Throws(() => new AggregateTopX(CatalogueRepository, _configuration, 10)); - Assert.AreEqual("AggregateConfiguration MyConfig already has a TopX", ex.Message); + Assert.That(ex.Message, Is.EqualTo("AggregateConfiguration MyConfig already has a TopX")); topX1.DeleteInDatabase(); } @@ -125,7 +125,7 @@ public void TestAggregateBuilding_NoConfigurationTwoDimension_Top10(string count var builder = _configuration.GetQueryBuilder(); - Assert.AreEqual(CollapseWhitespace($@"/*MyConfig*/ + Assert.That(CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace($@"/*MyConfig*/ SELECT TOP 10 Col1, @@ -137,7 +137,7 @@ group by Col1, Col2 order by -{countColField} {(asc ? "asc" : "desc")}"), CollapseWhitespace(builder.SQL)); +{countColField} {(asc ? "asc" : "desc")}"))); _configuration.CountSQL = beforeCountSQL; topX.DeleteInDatabase(); @@ -159,7 +159,7 @@ public void TestAggregateBuilding_NoConfigurationTwoDimension_Top10DimensionOrde var builder = _configuration.GetQueryBuilder(); - Assert.AreEqual(CollapseWhitespace($@"/*MyConfig*/ + Assert.That(CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace($@"/*MyConfig*/ SELECT TOP 10 Col1, @@ -171,7 +171,7 @@ group by Col1, Col2 order by -Col1 {(asc ? "asc" : "desc")}"), CollapseWhitespace(builder.SQL)); +Col1 {(asc ? "asc" : "desc")}"))); topX.DeleteInDatabase(); } @@ -181,10 +181,10 @@ public void TestAggregateBuilding_NoConfigurationNoDimensions() { var builder = new AggregateBuilder(null, "count(*)", null, new[] { _ti }); - Assert.AreEqual(CollapseWhitespace(@"/**/ + Assert.That(CollapseWhitespace(builder.SQL), Is.EqualTo(CollapseWhitespace(@"/**/ SELECT count(*) AS MyCount FROM -T1"), CollapseWhitespace(builder.SQL)); +T1"))); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/MySqlAggregateBuilderTests.cs b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/MySqlAggregateBuilderTests.cs index ff628881a7..4ea8b7ba59 100644 --- a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/MySqlAggregateBuilderTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/AggregateBuilderTests/MySqlAggregateBuilderTests.cs @@ -32,7 +32,7 @@ public void Test_AggregateBuilder_MySql_Top32() builder.AggregateTopX = topx; - Assert.AreEqual(CollapseWhitespace(@"/**/ + Assert.That(CollapseWhitespace(builder.SQL.Trim()), Is.EqualTo(CollapseWhitespace(@"/**/ SELECT Col1, count(*) AS MyCount @@ -42,7 +42,7 @@ group by Col1 order by Col1 desc -LIMIT 32"), CollapseWhitespace(builder.SQL.Trim())); +LIMIT 32"))); topx.DeleteInDatabase(); @@ -66,7 +66,7 @@ public void Test_AggregateBuilder_MySql_Top31OrderByCountAsc(bool useAliasForGro }; builder.AggregateTopX = topx; - Assert.AreEqual(useAliasForGroupBy + Assert.That(CollapseWhitespace(builder.SQL), Is.EqualTo(useAliasForGroupBy ? CollapseWhitespace(@"/**/ SELECT Col1, @@ -88,7 +88,7 @@ group by Col1 order by count(*) asc -LIMIT 31"), CollapseWhitespace(builder.SQL)); +LIMIT 31"))); topx.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/MicrosoftQueryBuilderTests.cs b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/MicrosoftQueryBuilderTests.cs index 04be62e17b..c602435369 100644 --- a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/MicrosoftQueryBuilderTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/MicrosoftQueryBuilderTests.cs @@ -24,7 +24,7 @@ public void TestQueryBuilder_MicrosoftSQLServer_Top35() t.SaveToDatabase(); var col = new ColumnInfo(CatalogueRepository, "[db]..[tbl].[col]", "varchar(10)", t); - Assert.AreEqual("col", col.GetRuntimeName()); + Assert.That(col.GetRuntimeName(), Is.EqualTo("col")); var cata = new Catalogue(CatalogueRepository, "cata"); var catalogueItem = new CatalogueItem(CatalogueRepository, cata, "col"); @@ -35,25 +35,25 @@ public void TestQueryBuilder_MicrosoftSQLServer_Top35() TopX = 35 }; qb.AddColumn(extractionInfo); - Assert.AreEqual( - CollapseWhitespace( + Assert.That( +CollapseWhitespace(qb.SQL), Is.EqualTo(CollapseWhitespace( @"SELECT TOP 35 [db]..[tbl].[col] FROM [db]..[tbl]") - , CollapseWhitespace(qb.SQL)); +)); //editting the topX should invalidate the SQL automatically qb.TopX = 50; - Assert.AreEqual( - CollapseWhitespace( + Assert.That( +CollapseWhitespace(qb.SQL), Is.EqualTo(CollapseWhitespace( @"SELECT TOP 50 [db]..[tbl].[col] FROM [db]..[tbl]") - , CollapseWhitespace(qb.SQL)); +)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/MySqlQueryBuilderTests.cs b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/MySqlQueryBuilderTests.cs index 98c2dcaa2c..04eca0d63f 100644 --- a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/MySqlQueryBuilderTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/MySqlQueryBuilderTests.cs @@ -24,20 +24,20 @@ public void TestQueryBuilder_MySql_Normal() t.SaveToDatabase(); var col = new ColumnInfo(CatalogueRepository, "`db`.`tbl`.`col`", "varchar(10)", t); - Assert.AreEqual("col", col.GetRuntimeName()); + Assert.That(col.GetRuntimeName(), Is.EqualTo("col")); var cata = new Catalogue(CatalogueRepository, "cata"); var catalogueItem = new CatalogueItem(CatalogueRepository, cata, "col"); var extractionInfo = new ExtractionInformation(CatalogueRepository, catalogueItem, col, col.Name); - + var qb = new QueryBuilder(null, null); qb.AddColumn(extractionInfo); - Assert.AreEqual(CollapseWhitespace( + Assert.That(CollapseWhitespace(qb.SQL), Is.EqualTo(CollapseWhitespace( @"SELECT `db`.`tbl`.`col` FROM `db`.`tbl`" - ), CollapseWhitespace(qb.SQL)); + ))); } [Test] @@ -50,7 +50,7 @@ public void TestQueryBuilder_MySql_Top35() t.SaveToDatabase(); var col = new ColumnInfo(CatalogueRepository, "`db`.`tbl`.`col`", "varchar(10)", t); - Assert.AreEqual("col", col.GetRuntimeName()); + Assert.That(col.GetRuntimeName(), Is.EqualTo("col")); var cata = new Catalogue(CatalogueRepository, "cata"); var catalogueItem = new CatalogueItem(CatalogueRepository, cata, "col"); @@ -61,25 +61,29 @@ public void TestQueryBuilder_MySql_Top35() TopX = 35 }; qb.AddColumn(extractionInfo); - Assert.AreEqual( - CollapseWhitespace( - @"SELECT -`db`.`tbl`.`col` -FROM -`db`.`tbl` -LIMIT 35") - , CollapseWhitespace(qb.SQL)); + Assert.That( +CollapseWhitespace(qb.SQL), Is.EqualTo(CollapseWhitespace( + """ + SELECT + `db`.`tbl`.`col` + FROM + `db`.`tbl` + LIMIT 35 + """) +)); - //editting the topX should invalidate the SQL automatically + //editing the topX should invalidate the SQL automatically qb.TopX = 50; - Assert.AreEqual( - CollapseWhitespace( - @"SELECT -`db`.`tbl`.`col` -FROM -`db`.`tbl` -LIMIT 50") - , CollapseWhitespace(qb.SQL)); + Assert.That( +CollapseWhitespace(qb.SQL), Is.EqualTo(CollapseWhitespace( + """ + SELECT + `db`.`tbl`.`col` + FROM + `db`.`tbl` + LIMIT 50 + """) +)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/QueryBuilderUnitTests.cs b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/QueryBuilderUnitTests.cs index 4db76ed05f..74cd270330 100644 --- a/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/QueryBuilderUnitTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/QueryBuildingTests/QueryBuilderTests/QueryBuilderUnitTests.cs @@ -35,7 +35,7 @@ public void Test_IsPrimaryExtractionTable_TwoTables() var s = builder.SQL; }); - StringAssert.Contains("There are multiple tables marked as IsPrimaryExtractionTable", ex.Message); + Assert.That(ex.Message, Does.Contain("There are multiple tables marked as IsPrimaryExtractionTable")); } [Test] @@ -55,11 +55,14 @@ public void Test_TwoTables_JoinFound() builder.AddColumn(new ColumnInfoToIColumn(Repository, c1)); builder.AddColumn(new ColumnInfoToIColumn(Repository, c2)); - StringAssert.Contains("JOIN", builder.SQL); + Assert.Multiple(() => + { + Assert.That(builder.SQL, Does.Contain("JOIN")); - //we have 1 legit join go go team! - Assert.AreEqual(1, builder.JoinsUsedInQuery.Count); - Assert.AreEqual(j1, builder.JoinsUsedInQuery[0]); + //we have 1 legit join go go team! + Assert.That(builder.JoinsUsedInQuery, Has.Count.EqualTo(1)); + }); + Assert.That(builder.JoinsUsedInQuery[0], Is.EqualTo(j1)); } [Test] @@ -115,9 +118,9 @@ public void Test_FourTables_MultipleRoutes() Console.WriteLine(builder.SQL); //should be using only 3 of the 4 joins because we already have a route to c4 without a fourth join - Assert.AreEqual(3, builder.JoinsUsedInQuery.Count); - Assert.Contains(j1, builder.JoinsUsedInQuery); - Assert.Contains(j2, builder.JoinsUsedInQuery); - Assert.Contains(j3, builder.JoinsUsedInQuery); + Assert.That(builder.JoinsUsedInQuery, Has.Count.EqualTo(3)); + Assert.That(builder.JoinsUsedInQuery, Does.Contain(j1)); + Assert.That(builder.JoinsUsedInQuery, Does.Contain(j2)); + Assert.That(builder.JoinsUsedInQuery, Does.Contain(j3)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/ServerDefaultsTests.cs b/Rdmp.Core.Tests/Curation/Integration/ServerDefaultsTests.cs index 68ac9c50b6..79fdf8e4dc 100644 --- a/Rdmp.Core.Tests/Curation/Integration/ServerDefaultsTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/ServerDefaultsTests.cs @@ -17,11 +17,11 @@ public class ServerDefaultsTests : DatabaseTests [Test] public void TestClearSameDefaultTwice() { - Assert.IsNotNull(CatalogueRepository.GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID)); + Assert.That(CatalogueRepository.GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID), Is.Not.Null); CatalogueRepository.ClearDefault(PermissableDefaults.LiveLoggingServer_ID); CatalogueRepository.ClearDefault(PermissableDefaults.LiveLoggingServer_ID); CatalogueRepository.ClearDefault(PermissableDefaults.LiveLoggingServer_ID); - Assert.IsNull(CatalogueRepository.GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID)); + Assert.That(CatalogueRepository.GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID), Is.Null); } [Test] @@ -31,13 +31,15 @@ public void CreateNewExternalServerAndConfigureItAsDefault() try { - Assert.AreEqual("Deleteme", databaseServer.Name); + Assert.That(databaseServer.Name, Is.EqualTo("Deleteme")); databaseServer.Password = "nothing"; //automatically encrypts password - Assert.AreNotEqual("nothing", databaseServer.Password); //should not match what we just set it to - Assert.AreEqual("nothing", - databaseServer - .GetDecryptedPassword()); //should match what we set it to because of explicit call to decrypt + Assert.Multiple(() => + { + Assert.That(databaseServer.Password, Is.Not.EqualTo("nothing")); //should not match what we just set it to + Assert.That(databaseServer + .GetDecryptedPassword(), Is.EqualTo("nothing")); //should match what we set it to because of explicit call to decrypt + }); databaseServer.Server = "Bob"; databaseServer.Database = "TEST"; @@ -67,7 +69,7 @@ public void TestDeletingClearsDefault() //now we deleted it! eds.DeleteInDatabase(); - Assert.IsNull(CatalogueRepository.GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID)); + Assert.That(CatalogueRepository.GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID), Is.Null); } finally { diff --git a/Rdmp.Core.Tests/Curation/Integration/SupportingDocumentTests.cs b/Rdmp.Core.Tests/Curation/Integration/SupportingDocumentTests.cs index 1d9cc9cf09..9dc070df85 100644 --- a/Rdmp.Core.Tests/Curation/Integration/SupportingDocumentTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/SupportingDocumentTests.cs @@ -18,7 +18,7 @@ public void test_SupportingDocument_CreateAndDestroy() var cata = new Catalogue(CatalogueRepository, "deleteme"); var doc = new SupportingDocument(CatalogueRepository, cata, "davesFile"); - Assert.AreEqual(doc.Name, "davesFile"); + Assert.That(doc.Name, Is.EqualTo("davesFile")); doc.DeleteInDatabase(); cata.DeleteInDatabase(); @@ -34,12 +34,15 @@ public void test_SupportingDocument_CreateChangeSaveDestroy() }; doc.SaveToDatabase(); - Assert.AreEqual(doc.Name, "davesFile"); - Assert.AreEqual(doc.Description, "some exciting file that dave loves"); + Assert.Multiple(() => + { + Assert.That(doc.Name, Is.EqualTo("davesFile")); + Assert.That(doc.Description, Is.EqualTo("some exciting file that dave loves")); + }); var docAfterCommit = CatalogueRepository.GetObjectByID(doc.ID); - Assert.AreEqual(docAfterCommit.Description, doc.Description); + Assert.That(doc.Description, Is.EqualTo(docAfterCommit.Description)); doc.DeleteInDatabase(); cata.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/Curation/Integration/TableInfoSynchronizerTests.cs b/Rdmp.Core.Tests/Curation/Integration/TableInfoSynchronizerTests.cs index cfb970809e..42366a4b82 100644 --- a/Rdmp.Core.Tests/Curation/Integration/TableInfoSynchronizerTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/TableInfoSynchronizerTests.cs @@ -49,10 +49,10 @@ protected override void SetUp() [Test] public void SynchronizationTests_NoChanges() { - Assert.AreEqual(TABLE_NAME, tableInfoCreated.GetRuntimeName()); + Assert.That(tableInfoCreated.GetRuntimeName(), Is.EqualTo(TABLE_NAME)); var synchronizer = new TableInfoSynchronizer(tableInfoCreated); - Assert.AreEqual(true, synchronizer.Synchronize(ThrowImmediatelyCheckNotifier.Quiet)); + Assert.That(synchronizer.Synchronize(ThrowImmediatelyCheckNotifier.Quiet), Is.EqualTo(true)); } [Test] @@ -60,7 +60,7 @@ public void SynchronizationTests_NoChanges() [TestCase(false)] public void SynchronizationTests_ColumnDropped(bool acceptChanges) { - Assert.AreEqual(TABLE_NAME, tableInfoCreated.GetRuntimeName()); + Assert.That(tableInfoCreated.GetRuntimeName(), Is.EqualTo(TABLE_NAME)); var table = _database.ExpectTable(TABLE_NAME); var colToDrop = table.DiscoverColumn("Address"); @@ -70,14 +70,17 @@ public void SynchronizationTests_ColumnDropped(bool acceptChanges) if (acceptChanges) { - //accept changes should result in a synchronized table - Assert.AreEqual(true, synchronizer.Synchronize(new AcceptAllCheckNotifier())); - Assert.AreEqual(1, tableInfoCreated.ColumnInfos.Length); //should only be 1 remaining + Assert.Multiple(() => + { + //accept changes should result in a synchronized table + Assert.That(synchronizer.Synchronize(new AcceptAllCheckNotifier()), Is.EqualTo(true)); + Assert.That(tableInfoCreated.ColumnInfos, Has.Length.EqualTo(1)); //should only be 1 remaining + }); } else { var ex = Assert.Throws(() => synchronizer.Synchronize(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("The ColumnInfo Address no longer appears in the live table.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The ColumnInfo Address no longer appears in the live table.")); } } @@ -97,14 +100,17 @@ public void SynchronizationTests_ColumnAdded(bool acceptChanges) if (acceptChanges) { - //accept changes should result in a synchronized table - Assert.AreEqual(true, synchronizer.Synchronize(new AcceptAllCheckNotifier())); - Assert.AreEqual(3, tableInfoCreated.ColumnInfos.Length); //should 3 now + Assert.Multiple(() => + { + //accept changes should result in a synchronized table + Assert.That(synchronizer.Synchronize(new AcceptAllCheckNotifier()), Is.EqualTo(true)); + Assert.That(tableInfoCreated.ColumnInfos, Has.Length.EqualTo(3)); //should 3 now + }); } else { var ex = Assert.Throws(() => synchronizer.Synchronize(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("The following columns are missing from the TableInfo:Birthday", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The following columns are missing from the TableInfo:Birthday")); } } @@ -118,9 +124,12 @@ public void SynchronizationTests_ColumnAddedWithCatalogue(bool acceptChanges) try { - Assert.AreEqual(TABLE_NAME, cata.Name); - Assert.AreEqual(2, cataItems.Length); - Assert.AreEqual(2, extractionInformations.Length); + Assert.Multiple(() => + { + Assert.That(cata.Name, Is.EqualTo(TABLE_NAME)); + Assert.That(cataItems, Has.Length.EqualTo(2)); + Assert.That(extractionInformations, Has.Length.EqualTo(2)); + }); using (var con = _server.GetConnection()) { @@ -132,21 +141,26 @@ public void SynchronizationTests_ColumnAddedWithCatalogue(bool acceptChanges) if (acceptChanges) { - //accept changes should result in a synchronized table - Assert.AreEqual(true, synchronizer.Synchronize(new AcceptAllCheckNotifier())); - Assert.AreEqual(3, tableInfoCreated.ColumnInfos.Length); //should 3 now - Assert.AreEqual(3, cata.CatalogueItems.Length); //should 3 now - Assert.AreEqual(3, cata.GetAllExtractionInformation(ExtractionCategory.Any).Length); //should 3 now - - Assert.AreEqual(1, - cata.GetAllExtractionInformation(ExtractionCategory.Any) - .Count(e => e.SelectSQL.Contains("Birthday"))); - Assert.AreEqual(1, cata.CatalogueItems.Count(ci => ci.Name.Contains("Birthday"))); + Assert.Multiple(() => + { + //accept changes should result in a synchronized table + Assert.That(synchronizer.Synchronize(new AcceptAllCheckNotifier()), Is.EqualTo(true)); + Assert.That(tableInfoCreated.ColumnInfos, Has.Length.EqualTo(3)); //should 3 now + Assert.That(cata.CatalogueItems, Has.Length.EqualTo(3)); //should 3 now + Assert.That(cata.GetAllExtractionInformation(ExtractionCategory.Any), Has.Length.EqualTo(3)); //should 3 now + }); + + Assert.Multiple(() => + { + Assert.That(cata.GetAllExtractionInformation(ExtractionCategory.Any) + .Count(e => e.SelectSQL.Contains("Birthday")), Is.EqualTo(1)); + Assert.That(cata.CatalogueItems.Count(ci => ci.Name.Contains("Birthday")), Is.EqualTo(1)); + }); } else { var ex = Assert.Throws(() => synchronizer.Synchronize(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("The following columns are missing from the TableInfo:Birthday", ex.Message); + Assert.That(ex.Message, Is.EqualTo("The following columns are missing from the TableInfo:Birthday")); } } finally diff --git a/Rdmp.Core.Tests/Curation/Integration/TableInfoTests.cs b/Rdmp.Core.Tests/Curation/Integration/TableInfoTests.cs index 258e80eb3b..96229f3a00 100644 --- a/Rdmp.Core.Tests/Curation/Integration/TableInfoTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/TableInfoTests.cs @@ -28,7 +28,7 @@ internal class TableInfoTests : DatabaseTests public void GetAllTableInfos_moreThan1_pass() { var tableInfo = new TableInfo(CatalogueRepository, "AMAGAD!!!"); - Assert.IsTrue(CatalogueRepository.GetAllObjects().Any()); + Assert.That(CatalogueRepository.GetAllObjects().Any()); tableInfo.DeleteInDatabase(); } @@ -37,12 +37,12 @@ public void CreateNewTableInfoInDatabase_valid_pass() { var table = new TableInfo(CatalogueRepository, "TestDB..TestTableName"); - Assert.NotNull(table); + Assert.That(table, Is.Not.Null); table.DeleteInDatabase(); var ex = Assert.Throws(() => CatalogueRepository.GetObjectByID(table.ID)); - Assert.AreEqual(ex.Message, $"Could not find TableInfo with ID {table.ID}"); + Assert.That($"Could not find TableInfo with ID {table.ID}", Is.EqualTo(ex.Message)); } [Test] @@ -60,10 +60,13 @@ public void update_changeAllProperties_pass() var tableAfter = CatalogueRepository.GetObjectByID(table.ID); - Assert.IsTrue(tableAfter.Database == "CHI_AMALG"); - Assert.IsTrue(tableAfter.Server == "Highly restricted"); - Assert.IsTrue(tableAfter.Name == "Fishmongery!"); - Assert.IsTrue(tableAfter.DatabaseType == DatabaseType.Oracle); + Assert.Multiple(() => + { + Assert.That(tableAfter.Database, Is.EqualTo("CHI_AMALG")); + Assert.That(tableAfter.Server, Is.EqualTo("Highly restricted")); + Assert.That(tableAfter.Name, Is.EqualTo("Fishmongery!")); + Assert.That(tableAfter.DatabaseType, Is.EqualTo(DatabaseType.Oracle)); + }); tableAfter.DeleteInDatabase(); } @@ -87,19 +90,21 @@ public void CreateNewTableInfoInDatabase_Naming(string tableName, string columnN try { - Assert.AreEqual("ANOMyCol", c.GetRuntimeName()); - Assert.AreEqual("MyCol", c.GetRuntimeName(LoadStage.AdjustRaw)); - Assert.AreEqual("ANOMyCol", c.GetRuntimeName(LoadStage.PostLoad)); + Assert.Multiple(() => + { + Assert.That(c.GetRuntimeName(), Is.EqualTo("ANOMyCol")); + Assert.That(c.GetRuntimeName(LoadStage.AdjustRaw), Is.EqualTo("MyCol")); + Assert.That(c.GetRuntimeName(LoadStage.PostLoad), Is.EqualTo("ANOMyCol")); - Assert.AreEqual("TestTableName", table.GetRuntimeName()); - Assert.AreEqual("TestTableName", table.GetRuntimeName(LoadBubble.Raw)); - Assert.AreEqual("TestDB_TestTableName_STAGING", table.GetRuntimeName(LoadBubble.Staging)); + Assert.That(table.GetRuntimeName(), Is.EqualTo("TestTableName")); + Assert.That(table.GetRuntimeName(LoadBubble.Raw), Is.EqualTo("TestTableName")); + Assert.That(table.GetRuntimeName(LoadBubble.Staging), Is.EqualTo("TestDB_TestTableName_STAGING")); - Assert.AreEqual("TestTableName_STAGING", table.GetRuntimeName(LoadBubble.Staging, new SuffixBasedNamer())); - Assert.AreEqual("TestDB_TestTableName_STAGING", - table.GetRuntimeName(LoadBubble.Staging, new FixedStagingDatabaseNamer("TestDB"))); + Assert.That(table.GetRuntimeName(LoadBubble.Staging, new SuffixBasedNamer()), Is.EqualTo("TestTableName_STAGING")); + Assert.That(table.GetRuntimeName(LoadBubble.Staging, new FixedStagingDatabaseNamer("TestDB")), Is.EqualTo("TestDB_TestTableName_STAGING")); - Assert.AreEqual("TestTableName", table.GetRuntimeName(LoadBubble.Live)); + Assert.That(table.GetRuntimeName(LoadBubble.Live), Is.EqualTo("TestTableName")); + }); } finally { @@ -121,41 +126,53 @@ public void TestCreateTableInSchemaAndImportAsTableInfo() var tbl = db.CreateTable("Fish", new[] { new DatabaseColumnRequest("MyCol", "int") { IsPrimaryKey = true } }, "Omg"); - Assert.AreEqual("Fish", tbl.GetRuntimeName()); - Assert.AreEqual("Omg", tbl.Schema); - Assert.IsTrue(tbl.GetFullyQualifiedName().EndsWith("[Omg].[Fish]")); + Assert.Multiple(() => + { + Assert.That(tbl.GetRuntimeName(), Is.EqualTo("Fish")); + Assert.That(tbl.Schema, Is.EqualTo("Omg")); + Assert.That(tbl.GetFullyQualifiedName(), Does.EndWith("[Omg].[Fish]")); - Assert.IsTrue(tbl.Exists()); + Assert.That(tbl.Exists()); + }); Import(tbl, out var ti, out var cols); - Assert.AreEqual("Omg", ti.Schema); + Assert.That(ti.Schema, Is.EqualTo("Omg")); var tbl2 = ti.Discover(DataAccessContext.InternalDataProcessing); - Assert.AreEqual("Omg", tbl2.Schema); - Assert.IsTrue(tbl2.Exists()); + Assert.Multiple(() => + { + Assert.That(tbl2.Schema, Is.EqualTo("Omg")); + Assert.That(tbl2.Exists()); - Assert.IsTrue(ti.Name.EndsWith("[Omg].[Fish]")); + Assert.That(ti.Name, Does.EndWith("[Omg].[Fish]")); - Assert.IsTrue(ti.GetFullyQualifiedName().EndsWith("[Omg].[Fish]")); + Assert.That(ti.GetFullyQualifiedName(), Does.EndWith("[Omg].[Fish]")); + }); var c = cols.Single(); - Assert.AreEqual("MyCol", c.GetRuntimeName()); - StringAssert.Contains("[Omg].[Fish]", c.GetFullyQualifiedName()); + Assert.Multiple(() => + { + Assert.That(c.GetRuntimeName(), Is.EqualTo("MyCol")); + Assert.That(c.GetFullyQualifiedName(), Does.Contain("[Omg].[Fish]")); - //should be primary key - Assert.IsTrue(c.IsPrimaryKey); + //should be primary key + Assert.That(c.IsPrimaryKey); + }); var triggerFactory = new TriggerImplementerFactory(DatabaseType.MicrosoftSQLServer); var impl = triggerFactory.Create(tbl); - Assert.AreEqual(TriggerStatus.Missing, impl.GetTriggerStatus()); + Assert.That(impl.GetTriggerStatus(), Is.EqualTo(TriggerStatus.Missing)); impl.CreateTrigger(ThrowImmediatelyCheckNotifier.Quiet); - Assert.AreEqual(TriggerStatus.Enabled, impl.GetTriggerStatus()); + Assert.Multiple(() => + { + Assert.That(impl.GetTriggerStatus(), Is.EqualTo(TriggerStatus.Enabled)); - Assert.IsTrue(impl.CheckUpdateTriggerIsEnabledAndHasExpectedBody()); + Assert.That(impl.CheckUpdateTriggerIsEnabledAndHasExpectedBody()); + }); //should be synced var sync = new TableInfoSynchronizer(ti); @@ -164,17 +181,17 @@ public void TestCreateTableInSchemaAndImportAsTableInfo() //Test importing the _Legacy table valued function that should be created in the Omg schema and test synching that too. var tvf = ti.Discover(DataAccessContext.InternalDataProcessing).Database .ExpectTableValuedFunction("Fish_Legacy", "Omg"); - Assert.IsTrue(tvf.Exists()); + Assert.That(tvf.Exists()); var importerTvf = new TableValuedFunctionImporter(CatalogueRepository, tvf); importerTvf.DoImport(out var tvfTi, out var tvfCols); - Assert.AreEqual("Omg", tvfTi.Schema); + Assert.That(tvfTi.Schema, Is.EqualTo("Omg")); var syncTvf = new TableInfoSynchronizer(tvfTi); syncTvf.Synchronize(ThrowImmediatelyCheckNotifier.Quiet); - StringAssert.EndsWith("[Omg].Fish_Legacy(@index) AS Fish_Legacy", tvfTi.Name); + Assert.That(tvfTi.Name, Does.EndWith("[Omg].Fish_Legacy(@index) AS Fish_Legacy")); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -189,8 +206,11 @@ public void TestView(DatabaseType dbType) var tbl = db.CreateTable("MyTable", dt); Import(tbl, out var tblInfo, out _); - Assert.IsTrue(tblInfo.Discover(DataAccessContext.InternalDataProcessing).Exists()); - Assert.AreEqual(TableType.Table, tblInfo.Discover(DataAccessContext.InternalDataProcessing).TableType); + Assert.Multiple(() => + { + Assert.That(tblInfo.Discover(DataAccessContext.InternalDataProcessing).Exists()); + Assert.That(tblInfo.Discover(DataAccessContext.InternalDataProcessing).TableType, Is.EqualTo(TableType.Table)); + }); var viewName = "MyView"; @@ -223,10 +243,13 @@ public void TestView(DatabaseType dbType) var sync = new TableInfoSynchronizer(viewInfo); sync.Synchronize(ThrowImmediatelyCheckNotifier.Quiet); - Assert.IsTrue(viewInfo.Discover(DataAccessContext.InternalDataProcessing).Exists()); - Assert.AreEqual(TableType.View, viewInfo.Discover(DataAccessContext.InternalDataProcessing).TableType); + Assert.Multiple(() => + { + Assert.That(viewInfo.Discover(DataAccessContext.InternalDataProcessing).Exists()); + Assert.That(viewInfo.Discover(DataAccessContext.InternalDataProcessing).TableType, Is.EqualTo(TableType.View)); + }); view.Drop(); - Assert.IsFalse(view.Exists()); + Assert.That(view.Exists(), Is.False); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/TableNamingConventionTests.cs b/Rdmp.Core.Tests/Curation/Integration/TableNamingConventionTests.cs index 7f1cf105f4..1cbabd8443 100644 --- a/Rdmp.Core.Tests/Curation/Integration/TableNamingConventionTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/TableNamingConventionTests.cs @@ -19,7 +19,7 @@ internal class TableNamingConventionTests : DatabaseTests public void GetAllTableInfos_moreThan1_pass() { var ti = new TableInfo(CatalogueRepository, "AMAGAD!!!"); - Assert.IsTrue(CatalogueRepository.GetAllObjects().Any()); + Assert.That(CatalogueRepository.GetAllObjects().Any()); ti.DeleteInDatabase(); } @@ -39,10 +39,13 @@ public void update_changeAllProperties_pass() var tableInfoAfter = CatalogueRepository.GetObjectByID(tableInfo.ID); - Assert.IsTrue(tableInfoAfter.Database == "CHI_AMALG"); - Assert.IsTrue(tableInfoAfter.Server == "Highly restricted"); - Assert.IsTrue(tableInfoAfter.Name == "Fishmongery!"); - Assert.IsTrue(tableInfoAfter.DatabaseType == DatabaseType.Oracle); + Assert.Multiple(() => + { + Assert.That(tableInfoAfter.Database, Is.EqualTo("CHI_AMALG")); + Assert.That(tableInfoAfter.Server, Is.EqualTo("Highly restricted")); + Assert.That(tableInfoAfter.Name, Is.EqualTo("Fishmongery!")); + Assert.That(tableInfoAfter.DatabaseType, Is.EqualTo(DatabaseType.Oracle)); + }); tableInfoAfter.DeleteInDatabase(); } @@ -54,9 +57,9 @@ public void SuffixBasedTableNamingConventionHelper() var namingScheme = new SuffixBasedNamer(); var stagingTable = namingScheme.GetName(baseTableName, LoadBubble.Staging); - Assert.AreEqual("MyTable_STAGING", stagingTable); + Assert.That(stagingTable, Is.EqualTo("MyTable_STAGING")); var newLookupTable = namingScheme.GetName(baseTableName, LoadBubble.Live); - Assert.AreEqual("MyTable", newLookupTable); + Assert.That(newLookupTable, Is.EqualTo("MyTable")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Integration/TableValuedFunctionTests/AggregationTests.cs b/Rdmp.Core.Tests/Curation/Integration/TableValuedFunctionTests/AggregationTests.cs index 2ffb6f0238..a135f21176 100644 --- a/Rdmp.Core.Tests/Curation/Integration/TableValuedFunctionTests/AggregationTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/TableValuedFunctionTests/AggregationTests.cs @@ -32,14 +32,14 @@ public void GenerateAggregateManuallyTest() //do a count * on the query builder var queryBuilder = new AggregateBuilder("", "count(*)", null, new[] { _function.TableInfoCreated }); - Assert.IsTrue(queryBuilder.SQL.Contains(@"SELECT")); - Assert.IsTrue(queryBuilder.SQL.Contains(@"count(*)")); + Assert.That(queryBuilder.SQL, Does.Contain(@"SELECT")); + Assert.That(queryBuilder.SQL, Does.Contain(@"count(*)")); - Assert.IsTrue(queryBuilder.SQL.Contains(@"DECLARE @name AS varchar(50);")); - Assert.IsTrue(queryBuilder.SQL.Contains(@"SET @name='fish';")); + Assert.That(queryBuilder.SQL, Does.Contain(@"DECLARE @name AS varchar(50);")); + Assert.That(queryBuilder.SQL, Does.Contain(@"SET @name='fish';")); - Assert.IsTrue( - queryBuilder.SQL.Contains("..MyAwesomeFunction(@startNumber,@stopNumber,@name) AS MyAwesomeFunction")); + Assert.That( + queryBuilder.SQL, Does.Contain("..MyAwesomeFunction(@startNumber,@stopNumber,@name) AS MyAwesomeFunction")); Console.WriteLine(queryBuilder.SQL); } @@ -63,8 +63,8 @@ public void GenerateAggregateViaAggregateConfigurationTest(bool memoryRepo) var queryBuilder = agg.GetQueryBuilder(); - Assert.AreEqual( - $@"DECLARE @startNumber AS int; + Assert.That( +queryBuilder.SQL, Is.EqualTo($@"DECLARE @startNumber AS int; SET @startNumber=5; DECLARE @stopNumber AS int; SET @stopNumber=10; @@ -76,7 +76,7 @@ public void GenerateAggregateViaAggregateConfigurationTest(bool memoryRepo) FROM [{TestDatabaseNames.Prefix}ScratchArea]..MyAwesomeFunction(@startNumber,@stopNumber,@name) AS MyAwesomeFunction HAVING -count(*)>1", queryBuilder.SQL); +count(*)>1")); } finally { @@ -105,18 +105,18 @@ public void GenerateAggregateUsingOverridenParametersTest() //do a count * on the query builder var queryBuilder = agg.GetQueryBuilder(); - Assert.IsTrue(queryBuilder.SQL.Contains(@"SELECT")); - Assert.IsTrue(queryBuilder.SQL.Contains(@"count(*)")); + Assert.That(queryBuilder.SQL, Does.Contain(@"SELECT")); + Assert.That(queryBuilder.SQL, Does.Contain(@"count(*)")); //should have this version of things - Assert.IsTrue(queryBuilder.SQL.Contains(@"DECLARE @name AS varchar(50);")); - Assert.IsTrue(queryBuilder.SQL.Contains(@"SET @name='lobster';")); + Assert.That(queryBuilder.SQL, Does.Contain(@"DECLARE @name AS varchar(50);")); + Assert.That(queryBuilder.SQL, Does.Contain(@"SET @name='lobster';")); //isntead of this verison of things - Assert.IsFalse(queryBuilder.SQL.Contains(@"SET @name='fish';")); + Assert.That(queryBuilder.SQL, Does.Not.Contain(@"SET @name='fish';")); - Assert.IsTrue( - queryBuilder.SQL.Contains("..MyAwesomeFunction(@startNumber,@stopNumber,@name) AS MyAwesomeFunction")); + Assert.That( + queryBuilder.SQL, Does.Contain("..MyAwesomeFunction(@startNumber,@stopNumber,@name) AS MyAwesomeFunction")); Console.WriteLine(queryBuilder.SQL); } diff --git a/Rdmp.Core.Tests/Curation/Integration/TableValuedFunctionTests/ImportAndTestTests.cs b/Rdmp.Core.Tests/Curation/Integration/TableValuedFunctionTests/ImportAndTestTests.cs index 2c902d3fcd..9680c6529d 100644 --- a/Rdmp.Core.Tests/Curation/Integration/TableValuedFunctionTests/ImportAndTestTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/TableValuedFunctionTests/ImportAndTestTests.cs @@ -40,39 +40,57 @@ public void FunctionWorks() var r = server.GetCommand("Select * from dbo.MyAwesomeFunction(5,10,'Fish')", con).ExecuteReader(); r.Read(); - Assert.AreEqual(5, r["Number"]); - Assert.AreEqual("Fish", r["Name"]); + Assert.Multiple(() => + { + Assert.That(r["Number"], Is.EqualTo(5)); + Assert.That(r["Name"], Is.EqualTo("Fish")); + }); r.Read(); - Assert.AreEqual(6, r["Number"]); - Assert.AreEqual("Fish", r["Name"]); + Assert.Multiple(() => + { + Assert.That(r["Number"], Is.EqualTo(6)); + Assert.That(r["Name"], Is.EqualTo("Fish")); + }); r.Read(); - Assert.AreEqual(7, r["Number"]); - Assert.AreEqual("Fish", r["Name"]); + Assert.Multiple(() => + { + Assert.That(r["Number"], Is.EqualTo(7)); + Assert.That(r["Name"], Is.EqualTo("Fish")); + }); r.Read(); - Assert.AreEqual(8, r["Number"]); - Assert.AreEqual("Fish", r["Name"]); + Assert.Multiple(() => + { + Assert.That(r["Number"], Is.EqualTo(8)); + Assert.That(r["Name"], Is.EqualTo("Fish")); + }); r.Read(); - Assert.AreEqual(9, r["Number"]); - Assert.AreEqual("Fish", r["Name"]); + Assert.Multiple(() => + { + Assert.That(r["Number"], Is.EqualTo(9)); + Assert.That(r["Name"], Is.EqualTo("Fish")); - Assert.IsFalse(r.Read()); + Assert.That(r.Read(), Is.False); + }); } [Test] public void ImportFunctionIntoCatalogue() { - Assert.AreEqual(2, _function.ColumnInfosCreated.Length); - Assert.IsTrue(_function.TableInfoCreated.Name.Contains("MyAwesomeFunction(@startNumber,@stopNumber,@name)")); + Assert.Multiple(() => + { + Assert.That(_function.ColumnInfosCreated, Has.Length.EqualTo(2)); + Assert.That(_function.TableInfoCreated.Name, Does.Contain("MyAwesomeFunction(@startNumber,@stopNumber,@name)")); + }); } [Test] @@ -90,18 +108,24 @@ public void TestDiscovery() con); cmd.ExecuteNonQuery(); - Assert.IsTrue(db.DiscoverTableValuedFunctions(con.ManagedTransaction) - .Any(tbv => tbv.GetRuntimeName().Equals("MyAwesomeFunction"))); - Assert.IsTrue(db.ExpectTableValuedFunction("MyAwesomeFunction").Exists(con.ManagedTransaction)); + Assert.Multiple(() => + { + Assert.That(db.DiscoverTableValuedFunctions(con.ManagedTransaction) + .Any(tbv => tbv.GetRuntimeName().Equals("MyAwesomeFunction"))); + Assert.That(db.ExpectTableValuedFunction("MyAwesomeFunction").Exists(con.ManagedTransaction)); + }); var cols = db.ExpectTableValuedFunction("MyAwesomeFunction").DiscoverColumns(con.ManagedTransaction); - Assert.AreEqual(2, cols.Length); - Assert.IsTrue(cols[0].GetFullyQualifiedName().Contains("MyAwesomeFunction.[Number]")); - Assert.IsTrue(cols[1].GetFullyQualifiedName().Contains("MyAwesomeFunction.[Name]")); + Assert.That(cols, Has.Length.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(cols[0].GetFullyQualifiedName(), Does.Contain("MyAwesomeFunction.[Number]")); + Assert.That(cols[1].GetFullyQualifiedName(), Does.Contain("MyAwesomeFunction.[Name]")); - Assert.AreEqual("int", cols[0].DataType.SQLType); - Assert.AreEqual("varchar(50)", cols[1].DataType.SQLType); + Assert.That(cols[0].DataType.SQLType, Is.EqualTo("int")); + Assert.That(cols[1].DataType.SQLType, Is.EqualTo("varchar(50)")); + }); con.ManagedTransaction.CommitAndCloseConnection(); } @@ -117,23 +141,26 @@ public void Synchronization_ExtraParameter() var checker = new ToMemoryCheckNotifier(); _function.TableInfoCreated.Check(checker); - Assert.IsTrue(checker.Messages.Any(m => m.Result == CheckResult.Fail + Assert.That(checker.Messages.Any(m => m.Result == CheckResult.Fail && m.Message.Contains(expectedMessage))); var syncer = new TableInfoSynchronizer(_function.TableInfoCreated); var ex = Assert.Throws(() => syncer.Synchronize(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.IsTrue(ex.Message.Contains(expectedMessage)); + Assert.Multiple(() => + { + Assert.That(ex.Message, Does.Contain(expectedMessage)); - //no changes yet - Assert.IsTrue(excessParameter.HasLocalChanges().Evaluation == ChangeDescription.NoChanges); + //no changes yet + Assert.That(excessParameter.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.NoChanges)); - //sync should have proposed to drop the excess parameter (see above), accept the change - Assert.IsTrue(syncer.Synchronize(new AcceptAllCheckNotifier())); + //sync should have proposed to drop the excess parameter (see above), accept the change + Assert.That(syncer.Synchronize(new AcceptAllCheckNotifier())); + }); //now parameter shouldnt be there - Assert.IsTrue(excessParameter.HasLocalChanges().Evaluation == ChangeDescription.DatabaseCopyWasDeleted); + Assert.That(excessParameter.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.DatabaseCopyWasDeleted)); } [Test] @@ -149,16 +176,19 @@ public void Synchronization_MissingParameter() var syncer = new TableInfoSynchronizer(_function.TableInfoCreated); var ex = Assert.Throws(() => syncer.Synchronize(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.IsTrue(ex.Message.Contains(expectedMessage)); + Assert.Multiple(() => + { + Assert.That(ex.Message, Does.Contain(expectedMessage)); - //no parameter called @startNumber (because we deleted it right!) - Assert.IsFalse(_function.TableInfoCreated.GetAllParameters().Any(p => p.ParameterName.Equals("@startNumber"))); + //no parameter called @startNumber (because we deleted it right!) + Assert.That(_function.TableInfoCreated.GetAllParameters().Any(p => p.ParameterName.Equals("@startNumber")), Is.False); - //sync should have proposed to create the missing parameter (see above), accept the change - Assert.IsTrue(syncer.Synchronize(new AcceptAllCheckNotifier())); + //sync should have proposed to create the missing parameter (see above), accept the change + Assert.That(syncer.Synchronize(new AcceptAllCheckNotifier())); + }); //now parameter should have reappeared due to accepthing change - Assert.IsTrue(_function.TableInfoCreated.GetAllParameters().Any(p => p.ParameterName.Equals("@startNumber"))); + Assert.That(_function.TableInfoCreated.GetAllParameters().Any(p => p.ParameterName.Equals("@startNumber"))); } [Test] @@ -175,13 +205,16 @@ public void Synchronization_ParameterDefinitionChanged() var syncer = new TableInfoSynchronizer(_function.TableInfoCreated); var ex = Assert.Throws(() => syncer.Synchronize(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.Contains(expectedMessage, ex?.Message); + Assert.Multiple(() => + { + Assert.That(ex?.Message, Does.Contain(expectedMessage)); - //no changes should yet have taken place since we didn't accept it yet - Assert.IsTrue(parameter.HasLocalChanges().Evaluation == ChangeDescription.NoChanges); + //no changes should yet have taken place since we didn't accept it yet + Assert.That(parameter.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.NoChanges)); - //sync should have proposed to adjusting the datatype - Assert.IsTrue(syncer.Synchronize(new AcceptAllCheckNotifier())); + //sync should have proposed to adjusting the datatype + Assert.That(syncer.Synchronize(new AcceptAllCheckNotifier())); + }); if (CatalogueRepository is not TableRepository) // with a Yaml repository there is only one copy of the object so no need @@ -189,11 +222,14 @@ public void Synchronization_ParameterDefinitionChanged() return; //now parameter should have the correct datatype - Assert.IsTrue(parameter.HasLocalChanges().Evaluation == ChangeDescription.DatabaseCopyDifferent); + Assert.That(parameter.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.DatabaseCopyDifferent)); var diff = parameter.HasLocalChanges().Differences.Single(); - Assert.AreEqual("DECLARE @startNumber AS datetime;", diff.LocalValue); - Assert.AreEqual("DECLARE @startNumber AS int;", diff.DatabaseValue); + Assert.Multiple(() => + { + Assert.That(diff.LocalValue, Is.EqualTo("DECLARE @startNumber AS datetime;")); + Assert.That(diff.DatabaseValue, Is.EqualTo("DECLARE @startNumber AS int;")); + }); } [Test] @@ -207,15 +243,18 @@ public void Synchronization_ParameterRenamed() var syncer = new TableInfoSynchronizer(_function.TableInfoCreated); //shouldn't be any - Assert.IsFalse(_function.TableInfoCreated.GetAllParameters().Any(p => p.ParameterName.Equals("@startNumber"))); + Assert.That(_function.TableInfoCreated.GetAllParameters().Any(p => p.ParameterName.Equals("@startNumber")), Is.False); syncer.Synchronize(new AcceptAllCheckNotifier()); var after = _function.TableInfoCreated.GetAllParameters(); - //now there should be recreated (actually it will suggest deleting the excess one and creating the underlying one as 2 separate suggestions one after the other) - Assert.IsTrue(after.Any(p => p.ParameterName.Equals("@startNumber"))); - - //still there should only be 3 parameters - Assert.AreEqual(3, after.Length); + Assert.Multiple(() => + { + //now there should be recreated (actually it will suggest deleting the excess one and creating the underlying one as 2 separate suggestions one after the other) + Assert.That(after.Any(p => p.ParameterName.Equals("@startNumber"))); + + //still there should only be 3 parameters + Assert.That(after, Has.Length.EqualTo(3)); + }); } diff --git a/Rdmp.Core.Tests/Curation/Integration/TriggerTests.cs b/Rdmp.Core.Tests/Curation/Integration/TriggerTests.cs index b5c4686a67..8d2053222c 100644 --- a/Rdmp.Core.Tests/Curation/Integration/TriggerTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/TriggerTests.cs @@ -29,7 +29,7 @@ public class TriggerTests : DatabaseTests private DiscoveredDatabase _database; - public void CreateTable(DatabaseType dbType) + private void CreateTable(DatabaseType dbType) { _database = GetCleanedServer(dbType); @@ -55,7 +55,7 @@ public void NoTriggerExists(DatabaseType dbType) //most likely doesn't exist but may do implementer.DropTrigger(out _, out _); - Assert.AreEqual(TriggerStatus.Missing, implementer.GetTriggerStatus()); + Assert.That(implementer.GetTriggerStatus(), Is.EqualTo(TriggerStatus.Missing)); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -65,7 +65,7 @@ public void CreateWithNoPks_Complain(DatabaseType dbType) var ex = Assert.Throws(() => GetImplementer().CreateTrigger(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("There must be at least 1 primary key", ex.Message); + Assert.That(ex.Message, Is.EqualTo("There must be at least 1 primary key")); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -76,8 +76,11 @@ public void CreateWithPks_Valid(DatabaseType dbType) _table.CreatePrimaryKey(new[] { _table.DiscoverColumn("name") }); GetImplementer().CreateTrigger(ThrowImmediatelyCheckNotifier.Quiet); - Assert.AreEqual(TriggerStatus.Enabled, GetImplementer().GetTriggerStatus()); - Assert.AreEqual(true, GetImplementer().CheckUpdateTriggerIsEnabledAndHasExpectedBody()); + Assert.Multiple(() => + { + Assert.That(GetImplementer().GetTriggerStatus(), Is.EqualTo(TriggerStatus.Enabled)); + Assert.That(GetImplementer().CheckUpdateTriggerIsEnabledAndHasExpectedBody(), Is.EqualTo(true)); + }); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -95,8 +98,11 @@ public void Create_WithDodgyColumnNames(DatabaseType dbType) GetImplementer().CreateTrigger(ThrowImmediatelyCheckNotifier.Quiet); - Assert.AreEqual(TriggerStatus.Enabled, GetImplementer().GetTriggerStatus()); - Assert.AreEqual(true, GetImplementer().CheckUpdateTriggerIsEnabledAndHasExpectedBody()); + Assert.Multiple(() => + { + Assert.That(GetImplementer().GetTriggerStatus(), Is.EqualTo(TriggerStatus.Enabled)); + Assert.That(GetImplementer().CheckUpdateTriggerIsEnabledAndHasExpectedBody(), Is.EqualTo(true)); + }); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -110,15 +116,15 @@ public void AlterTest_InvalidThenRecreateItAndItsValidAgain(DatabaseType dbType) //still not valid because trigger SQL is missing it in the column list var ex = Assert.Throws(() => GetImplementer().CheckUpdateTriggerIsEnabledAndHasExpectedBody()); - Assert.IsNotNull(ex.Message); + Assert.That(ex.Message, Is.Not.Null); var implementer = GetImplementer(); implementer.DropTrigger(out var problemsDroppingTrigger, out _); - Assert.IsEmpty(problemsDroppingTrigger); + Assert.That(problemsDroppingTrigger, Is.Empty); implementer.CreateTrigger(ThrowImmediatelyCheckNotifier.Quiet); - Assert.AreEqual(true, implementer.CheckUpdateTriggerIsEnabledAndHasExpectedBody()); + Assert.That(implementer.CheckUpdateTriggerIsEnabledAndHasExpectedBody(), Is.EqualTo(true)); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -135,41 +141,42 @@ public void NowTestDataInsertion(DatabaseType dbType) }); var liveOldRow = _table.GetDataTable().Rows.Cast().Single(r => r["bubbles"] as int? == 3); - Assert.AreEqual(new DateTime(2001, 1, 2), (DateTime)liveOldRow[SpecialFieldNames.ValidFrom]); + Assert.That((DateTime)liveOldRow[SpecialFieldNames.ValidFrom], Is.EqualTo(new DateTime(2001, 1, 2))); RunSQL("UPDATE {0} set bubbles =99", _table.GetFullyQualifiedName()); - //new value is 99 - Assert.AreEqual(99, - ExecuteScalar("Select bubbles FROM {0} where name = 'Franky'", _table.GetFullyQualifiedName())); - //archived value is 3 - Assert.AreEqual(3, - ExecuteScalar("Select bubbles FROM {0} where name = 'Franky'", _archiveTable.GetFullyQualifiedName())); + Assert.Multiple(() => + { + //new value is 99 + Assert.That(ExecuteScalar("Select bubbles FROM {0} where name = 'Franky'", _table.GetFullyQualifiedName()), Is.EqualTo(99)); + //archived value is 3 + Assert.That(ExecuteScalar("Select bubbles FROM {0} where name = 'Franky'", _archiveTable.GetFullyQualifiedName()), Is.EqualTo(3)); + }); //Legacy table valued function only works for MicrosoftSQLServer if (dbType == DatabaseType.MicrosoftSQLServer) { - //legacy in 2001-01-01 it didn't exist - Assert.IsNull(ExecuteScalar("Select bubbles FROM TriggerTests_Legacy('2001-01-01') where name = 'Franky'")); - //legacy in 2001-01-03 it did exist and was 3 - Assert.AreEqual(3, - ExecuteScalar("Select bubbles FROM TriggerTests_Legacy('2001-01-03') where name = 'Franky'")); - //legacy boundary case? - Assert.AreEqual(3, - ExecuteScalar("Select bubbles FROM TriggerTests_Legacy('2001-01-02') where name = 'Franky'")); - - //legacy today it is 99 - Assert.AreEqual(99, - ExecuteScalar("Select bubbles FROM TriggerTests_Legacy(GETDATE()) where name = 'Franky'")); + Assert.Multiple(() => + { + //legacy in 2001-01-01 it didn't exist + Assert.That(ExecuteScalar("Select bubbles FROM TriggerTests_Legacy('2001-01-01') where name = 'Franky'"), Is.Null); + //legacy in 2001-01-03 it did exist and was 3 + Assert.That(ExecuteScalar("Select bubbles FROM TriggerTests_Legacy('2001-01-03') where name = 'Franky'"), Is.EqualTo(3)); + //legacy boundary case? + Assert.That(ExecuteScalar("Select bubbles FROM TriggerTests_Legacy('2001-01-02') where name = 'Franky'"), Is.EqualTo(3)); + + //legacy today it is 99 + Assert.That(ExecuteScalar("Select bubbles FROM TriggerTests_Legacy(GETDATE()) where name = 'Franky'"), Is.EqualTo(99)); + }); } // Live row should now reflect that it is validFrom today var liveNewRow = _table.GetDataTable().Rows.Cast().Single(r => r["bubbles"] as int? == 99); - Assert.AreEqual(DateTime.Now.Date, ((DateTime)liveNewRow[SpecialFieldNames.ValidFrom]).Date); + Assert.That(((DateTime)liveNewRow[SpecialFieldNames.ValidFrom]).Date, Is.EqualTo(DateTime.Now.Date)); // Archived row should not have had its validFrom field broken var archivedRow = _archiveTable.GetDataTable().Rows.Cast().Single(r => r["bubbles"] as int? == 3); - Assert.AreEqual(new DateTime(2001, 1, 2), (DateTime)archivedRow[SpecialFieldNames.ValidFrom]); + Assert.That((DateTime)archivedRow[SpecialFieldNames.ValidFrom], Is.EqualTo(new DateTime(2001, 1, 2))); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -203,18 +210,24 @@ public void DiffDatabaseDataFetcherTest(DatabaseType dbType) Thread.Sleep(1000); - Assert.AreEqual(1, _table.GetRowCount()); - Assert.AreEqual(4, _archiveTable.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(_table.GetRowCount(), Is.EqualTo(1)); + Assert.That(_archiveTable.GetRowCount(), Is.EqualTo(4)); + }); Import(_table, out var ti, out var cols); var fetcher = new DiffDatabaseDataFetcher(1, ti, 7, 100); fetcher.FetchData(new AcceptAllCheckNotifier()); - Assert.AreEqual(4, fetcher.Updates_New.Rows[0]["bubbles"]); - Assert.AreEqual(3, fetcher.Updates_Replaced.Rows[0]["bubbles"]); + Assert.Multiple(() => + { + Assert.That(fetcher.Updates_New.Rows[0]["bubbles"], Is.EqualTo(4)); + Assert.That(fetcher.Updates_Replaced.Rows[0]["bubbles"], Is.EqualTo(3)); - Assert.AreEqual(1, fetcher.Updates_New.Rows.Count); - Assert.AreEqual(1, fetcher.Updates_Replaced.Rows.Count); + Assert.That(fetcher.Updates_New.Rows, Has.Count.EqualTo(1)); + Assert.That(fetcher.Updates_Replaced.Rows, Has.Count.EqualTo(1)); + }); } diff --git a/Rdmp.Core.Tests/Curation/Integration/Validation/StandardRegexTests.cs b/Rdmp.Core.Tests/Curation/Integration/Validation/StandardRegexTests.cs index 888d0d8a35..d1807ac392 100644 --- a/Rdmp.Core.Tests/Curation/Integration/Validation/StandardRegexTests.cs +++ b/Rdmp.Core.Tests/Curation/Integration/Validation/StandardRegexTests.cs @@ -24,8 +24,11 @@ public void CreateNew_UseConstraint() var regex = new StandardRegex(CatalogueRepository); try { - Assert.IsNotNull(regex.ConceptName); - Assert.IsTrue(string.IsNullOrEmpty(regex.Description)); + Assert.Multiple(() => + { + Assert.That(regex.ConceptName, Is.Not.Null); + Assert.That(string.IsNullOrEmpty(regex.Description)); + }); regex.ConceptName = "Fish"; regex.Regex = "^(Fish)$"; @@ -36,9 +39,9 @@ public void CreateNew_UseConstraint() CatalogueStandardRegex = regex }; - Assert.IsNull(constraint.Validate("Fish", null, null)); + Assert.That(constraint.Validate("Fish", null, null), Is.Null); var failure = constraint.Validate("FishFingers", null, null); - Assert.IsNotNull(failure); + Assert.That(failure, Is.Not.Null); } finally { diff --git a/Rdmp.Core.Tests/Curation/JsonSerializationTests/JsonSerializationTests.cs b/Rdmp.Core.Tests/Curation/JsonSerializationTests/JsonSerializationTests.cs index 7793b3f28c..01e8681284 100644 --- a/Rdmp.Core.Tests/Curation/JsonSerializationTests/JsonSerializationTests.cs +++ b/Rdmp.Core.Tests/Curation/JsonSerializationTests/JsonSerializationTests.cs @@ -39,14 +39,17 @@ public void TestSerialization_Catalogue() var mySerializeableAfter = (MySerializeableTestClass)JsonConvert.DeserializeObject(asString, typeof(MySerializeableTestClass), new JsonConverter[] { dbConverter, lazyConverter }); - Assert.AreNotEqual(mySerializeable, mySerializeableAfter); - Assert.AreEqual(mySerializeable.SelectedCatalogue, mySerializeableAfter.SelectedCatalogue); - Assert.AreEqual(mySerializeable.SelectedCatalogue.Name, mySerializeableAfter.SelectedCatalogue.Name); - Assert.AreEqual("War and Pieces", mySerializeableAfter.Title); + Assert.That(mySerializeableAfter, Is.Not.SameAs(mySerializeable)); + Assert.That(mySerializeableAfter.SelectedCatalogue, Is.EqualTo(mySerializeable.SelectedCatalogue)); + Assert.Multiple(() => + { + Assert.That(mySerializeableAfter.SelectedCatalogue.Name, Is.EqualTo(mySerializeable.SelectedCatalogue.Name)); + Assert.That(mySerializeableAfter.Title, Is.EqualTo("War and Pieces")); + }); mySerializeableAfter.SelectedCatalogue.Name = "Cannon balls"; mySerializeableAfter.SelectedCatalogue.SaveToDatabase(); - Assert.AreNotEqual(mySerializeable.SelectedCatalogue.Name, mySerializeableAfter.SelectedCatalogue.Name); + Assert.That(mySerializeableAfter.SelectedCatalogue.Name, Is.Not.EqualTo(mySerializeable.SelectedCatalogue.Name)); } //todo null Catalogue test case diff --git a/Rdmp.Core.Tests/Curation/MemoryRepositoryTests/MemoryRepositoryTests.cs b/Rdmp.Core.Tests/Curation/MemoryRepositoryTests/MemoryRepositoryTests.cs index 038dd4d822..7a1be03b9b 100644 --- a/Rdmp.Core.Tests/Curation/MemoryRepositoryTests/MemoryRepositoryTests.cs +++ b/Rdmp.Core.Tests/Curation/MemoryRepositoryTests/MemoryRepositoryTests.cs @@ -35,7 +35,7 @@ public void TestMemoryRepository_CatalogueConstructor() { var memCatalogue = new Catalogue(_repo, "My New Catalogue"); - Assert.AreEqual(memCatalogue, _repo.GetObjectByID(memCatalogue.ID)); + Assert.That(_repo.GetObjectByID(memCatalogue.ID), Is.EqualTo(memCatalogue)); } [Test] @@ -50,16 +50,16 @@ public void TestMemoryRepository_QueryBuilder() var ei = new ExtractionInformation(_repo, myCol, col, col.Name); - Assert.AreEqual(memCatalogue, _repo.GetObjectByID(memCatalogue.ID)); + Assert.That(_repo.GetObjectByID(memCatalogue.ID), Is.EqualTo(memCatalogue)); var qb = new QueryBuilder(null, null); qb.AddColumnRange(memCatalogue.GetAllExtractionInformation(ExtractionCategory.Any)); - Assert.AreEqual(@" + Assert.That(qb.SQL, Is.EqualTo(@" SELECT Mycol FROM -My table", qb.SQL); +My table")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/MemoryRepositoryTests/MemoryRepositoryVsDatabaseRepository.cs b/Rdmp.Core.Tests/Curation/MemoryRepositoryTests/MemoryRepositoryVsDatabaseRepository.cs index 623cd20528..c8a2664d18 100644 --- a/Rdmp.Core.Tests/Curation/MemoryRepositoryTests/MemoryRepositoryVsDatabaseRepository.cs +++ b/Rdmp.Core.Tests/Curation/MemoryRepositoryTests/MemoryRepositoryVsDatabaseRepository.cs @@ -72,7 +72,7 @@ public void TestMemoryRepository_LiveLogging() memoryRepository.SetDefault(PermissableDefaults.LiveLoggingServer_ID, loggingServer); var memCatalogue = new Catalogue(memoryRepository, "My New Catalogue"); - Assert.AreEqual(memCatalogue.LiveLoggingServer_ID, loggingServer.ID); + Assert.That(loggingServer.ID, Is.EqualTo(memCatalogue.LiveLoggingServer_ID)); } [TestCase(DatabaseType.MicrosoftSQLServer)] diff --git a/Rdmp.Core.Tests/Curation/RefactoringTests/SelectSQLRefactorerTests.cs b/Rdmp.Core.Tests/Curation/RefactoringTests/SelectSQLRefactorerTests.cs index 07ede43d6a..8928e82052 100644 --- a/Rdmp.Core.Tests/Curation/RefactoringTests/SelectSQLRefactorerTests.cs +++ b/Rdmp.Core.Tests/Curation/RefactoringTests/SelectSQLRefactorerTests.cs @@ -27,7 +27,7 @@ public void RefactorTableName_TestValidReplacement_ColumnInfo() SelectSQLRefactorer.RefactorTableName(columnInfo, tableInfo, "[database]..[table2]"); - Assert.AreEqual("[database]..[table2].[column]", columnInfo.Name); + Assert.That(columnInfo.Name, Is.EqualTo("[database]..[table2].[column]")); } [Test] @@ -49,7 +49,7 @@ public void RefactorTableName_TestValidReplacement_ExtractionInformation() SelectSQLRefactorer.RefactorTableName(ei, tableInfo, "[database]..[table2]"); - Assert.AreEqual("UPPER([database]..[table2].[column])", ei.SelectSQL); + Assert.That(ei.SelectSQL, Is.EqualTo("UPPER([database]..[table2].[column])")); } [Test] @@ -81,7 +81,7 @@ public void RefactorTableName_IsRefactorable_ExtractionInformation(string transf var refactorer = new SelectSQLRefactorer(); - Assert.AreEqual(expectedToBeRefactorable, SelectSQLRefactorer.IsRefactorable(ei)); + Assert.That(SelectSQLRefactorer.IsRefactorable(ei), Is.EqualTo(expectedToBeRefactorable)); if (expectedToBeRefactorable) SelectSQLRefactorer.RefactorTableName(ei, tableInfo, "[database]..[table2]"); @@ -101,10 +101,13 @@ public void RefactorTableName_IsRefactorable_TableInfoWithNoColumnInfos(string o foreach (IDeleteable d in ti.ColumnInfos) d.DeleteInDatabase(); - Assert.IsTrue(SelectSQLRefactorer.IsRefactorable(ti)); + Assert.Multiple(() => + { + Assert.That(SelectSQLRefactorer.IsRefactorable(ti)); - Assert.AreEqual(1, SelectSQLRefactorer.RefactorTableName(ti, newName)); - Assert.AreEqual(newName, ti.Name); + Assert.That(SelectSQLRefactorer.RefactorTableName(ti, newName), Is.EqualTo(1)); + Assert.That(ti.Name, Is.EqualTo(newName)); + }); } [TestCase("[Donkey]..[MyTbl]", "[Fish]..[MyTbl2]", "'[Donkey]..[MyTbl]' has incorrect database property 'Fish'")] @@ -120,10 +123,10 @@ public void RefactorTableName_IsNotRefactorable_TableInfoWithNoColumnInfos(strin d.DeleteInDatabase(); var refactorer = new SelectSQLRefactorer(); - Assert.IsFalse(SelectSQLRefactorer.IsRefactorable(ti)); + Assert.That(SelectSQLRefactorer.IsRefactorable(ti), Is.False); var ex = Assert.Throws(() => SelectSQLRefactorer.RefactorTableName(ti, newName)); - StringAssert.Contains(expectedReason, ex.Message); + Assert.That(ex.Message, Does.Contain(expectedReason)); } @@ -153,8 +156,11 @@ public void RefactorTableName_IsRefactorable_ColumnInfo(string columnName, strin var oldName = findTableName; var newName = oldName.Replace("MyTbl", "MyNewTbl"); - Assert.AreEqual(1, SelectSQLRefactorer.RefactorTableName(col, oldName, newName)); + Assert.Multiple(() => + { + Assert.That(SelectSQLRefactorer.RefactorTableName(col, oldName, newName), Is.EqualTo(1)); - Assert.AreEqual($"{newName}.[A]", col.Name); + Assert.That(col.Name, Is.EqualTo($"{newName}.[A]")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/SimpleExampleTests.cs b/Rdmp.Core.Tests/Curation/SimpleExampleTests.cs index 1149ba3fbe..dd5d0d54e8 100644 --- a/Rdmp.Core.Tests/Curation/SimpleExampleTests.cs +++ b/Rdmp.Core.Tests/Curation/SimpleExampleTests.cs @@ -5,7 +5,6 @@ // You should have received a copy of the GNU General Public License along with RDMP. If not, see . using System.Data; -using System.Linq; using FAnsi; using NUnit.Framework; using Rdmp.Core.Curation.Data; @@ -20,7 +19,7 @@ public class SimpleExampleTests : DatabaseTests public void Test1() { var cata = new Catalogue(CatalogueRepository, "My Test Cata"); - Assert.IsTrue(cata.Exists()); + Assert.That(cata.Exists()); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -28,9 +27,12 @@ public void Test2(DatabaseType type) { var database = GetCleanedServer(type); - Assert.IsTrue(database.Exists()); - Assert.IsEmpty(database.DiscoverTables(true)); - Assert.IsNotNull(database.GetRuntimeName()); + Assert.Multiple(() => + { + Assert.That(database.Exists()); + Assert.That(database.DiscoverTables(true), Is.Empty); + Assert.That(database.GetRuntimeName(), Is.Not.Null); + }); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -46,10 +48,13 @@ public void TestReadDataLowPrivileges(DatabaseType type) var tbl = database.CreateTable("MyTable", dt); - //at this point we are reading it with the credentials setup by GetCleanedServer - Assert.AreEqual(1, tbl.GetRowCount()); - Assert.AreEqual(1, tbl.DiscoverColumns().Length); - Assert.IsTrue(tbl.DiscoverColumn("MyCol").IsPrimaryKey); + Assert.Multiple(() => + { + //at this point we are reading it with the credentials setup by GetCleanedServer + Assert.That(tbl.GetRowCount(), Is.EqualTo(1)); + Assert.That(tbl.DiscoverColumns(), Has.Length.EqualTo(1)); + Assert.That(tbl.DiscoverColumn("MyCol").IsPrimaryKey); + }); //create a reference to the table in RMDP Import(tbl, out var tableInfo, out var columnInfos); @@ -63,16 +68,19 @@ public void TestReadDataLowPrivileges(DatabaseType type) //get new reference to the table var newTbl = newDatabase.ExpectTable(tableInfo.GetRuntimeName()); - //the credentials should be different - Assert.AreNotEqual(tbl.Database.Server.ExplicitUsernameIfAny, newTbl.Database.Server.ExplicitUsernameIfAny); + Assert.Multiple(() => + { + //the credentials should be different + Assert.That(newTbl.Database.Server.ExplicitUsernameIfAny, Is.Not.EqualTo(tbl.Database.Server.ExplicitUsernameIfAny)); - //try re-reading the data - Assert.AreEqual(1, newTbl.GetRowCount()); - Assert.AreEqual(1, newTbl.DiscoverColumns().Length); - Assert.IsTrue(newTbl.DiscoverColumn("MyCol").IsPrimaryKey); + //try re-reading the data + Assert.That(newTbl.GetRowCount(), Is.EqualTo(1)); + Assert.That(newTbl.DiscoverColumns(), Has.Length.EqualTo(1)); + Assert.That(newTbl.DiscoverColumn("MyCol").IsPrimaryKey); - //low priority user shouldn't be able to drop tables - Assert.That(newTbl.Drop, Throws.Exception); + //low priority user shouldn't be able to drop tables + Assert.That(newTbl.Drop, Throws.Exception); + }); //normal testing user should be able to tbl.Drop(); diff --git a/Rdmp.Core.Tests/Curation/Unit/AggregateConfigurationTests.cs b/Rdmp.Core.Tests/Curation/Unit/AggregateConfigurationTests.cs index aae025d9a3..35c785ce87 100644 --- a/Rdmp.Core.Tests/Curation/Unit/AggregateConfigurationTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/AggregateConfigurationTests.cs @@ -25,7 +25,7 @@ public void TestStripZeroSeries_EmptyTable() // empty tables should not get nuked AggregateConfiguration.AdjustGraphDataTable(dt); - Assert.AreEqual(2, dt.Columns.Count); + Assert.That(dt.Columns, Has.Count.EqualTo(2)); dt.Dispose(); } @@ -48,12 +48,12 @@ public void TestStripZeroSeries_Nulls(bool includeZeroSeries) if (includeZeroSeries) { - Assert.AreEqual(3, dt.Columns.Count); + Assert.That(dt.Columns, Has.Count.EqualTo(3)); } else { // col1 should have been gotten rid of - Assert.AreEqual(2, dt.Columns.Count); + Assert.That(dt.Columns, Has.Count.EqualTo(2)); dt.Columns.Contains("date"); dt.Columns.Contains("col2"); } diff --git a/Rdmp.Core.Tests/Curation/Unit/CacheFetchRequestProviderTests.cs b/Rdmp.Core.Tests/Curation/Unit/CacheFetchRequestProviderTests.cs index 7fc7c8bdb3..b6a84a7889 100644 --- a/Rdmp.Core.Tests/Curation/Unit/CacheFetchRequestProviderTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/CacheFetchRequestProviderTests.cs @@ -41,10 +41,13 @@ public void TestFailedFetchRequestProvider_CreationOfFetchRequest() var provider = new FailedCacheFetchRequestProvider(cacheProgress, 2); var fetchRequest = provider.GetNext(ThrowImmediatelyDataLoadEventListener.Quiet); - Assert.IsNotNull(fetchRequest); - Assert.AreEqual(fetchRequest.ChunkPeriod, new TimeSpan(8, 0, 0)); - Assert.AreEqual(fetchRequest.Start, failure.FetchRequestStart); - Assert.IsTrue(fetchRequest.IsRetry); + Assert.Multiple(() => + { + Assert.That(fetchRequest, Is.Not.Null); + Assert.That(new TimeSpan(8, 0, 0), Is.EqualTo(fetchRequest.ChunkPeriod)); + Assert.That(failure.FetchRequestStart, Is.EqualTo(fetchRequest.Start)); + }); + Assert.That(fetchRequest.IsRetry); cacheProgress.Received(1); } @@ -78,10 +81,10 @@ public void TestFailedFetchRequestProvider_MultiplePages() var provider = new FailedCacheFetchRequestProvider(cacheProgress, 2); // We should get three ICacheFetchRequests in total, followed by a null to signify that there are no more ICacheFetchRequests - Assert.IsNotNull(provider.GetNext(ThrowImmediatelyDataLoadEventListener.Quiet)); - Assert.IsNotNull(provider.GetNext(ThrowImmediatelyDataLoadEventListener.Quiet)); - Assert.IsNotNull(provider.GetNext(ThrowImmediatelyDataLoadEventListener.Quiet)); - Assert.IsNull(provider.GetNext(ThrowImmediatelyDataLoadEventListener.Quiet)); + Assert.That(provider.GetNext(ThrowImmediatelyDataLoadEventListener.Quiet), Is.Not.Null); + Assert.That(provider.GetNext(ThrowImmediatelyDataLoadEventListener.Quiet), Is.Not.Null); + Assert.That(provider.GetNext(ThrowImmediatelyDataLoadEventListener.Quiet), Is.Not.Null); + Assert.That(provider.GetNext(ThrowImmediatelyDataLoadEventListener.Quiet), Is.Null); } /// diff --git a/Rdmp.Core.Tests/Curation/Unit/CacheLagPeriodUnitTests.cs b/Rdmp.Core.Tests/Curation/Unit/CacheLagPeriodUnitTests.cs index bf4fe77d9d..7d34eb1ce4 100644 --- a/Rdmp.Core.Tests/Curation/Unit/CacheLagPeriodUnitTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/CacheLagPeriodUnitTests.cs @@ -14,18 +14,22 @@ namespace Rdmp.Core.Tests.Curation.Unit; public class CacheLagPeriodUnitTests { [Test] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Assertion", "NUnit2043:Use ComparisonConstraint for better assertion messages in case of failure", Justification = "")] public void TestOperator() { - Assert.IsTrue(new TimeSpan(32, 0, 0, 0) > new CacheLagPeriod("1m")); - Assert.IsTrue(new TimeSpan(24, 0, 0, 0) < new CacheLagPeriod("1m")); + Assert.Multiple(static () => + { + Assert.That(new TimeSpan(32, 0, 0, 0) > new CacheLagPeriod("1m")); + Assert.That(new TimeSpan(24, 0, 0, 0) < new CacheLagPeriod("1m")); - Assert.IsTrue(new TimeSpan(3, 0, 0, 0) > new CacheLagPeriod("2d")); - Assert.IsFalse(new TimeSpan(3, 0, 0, 0) > new CacheLagPeriod("3d")); - Assert.IsFalse(new TimeSpan(2, 0, 0, 0) < new CacheLagPeriod("2d")); - Assert.IsTrue(new TimeSpan(1, 0, 0, 0) < new CacheLagPeriod("2d")); + Assert.That(new TimeSpan(3, 0, 0, 0) > new CacheLagPeriod("2d")); + Assert.That(new TimeSpan(3, 0, 0, 0) > new CacheLagPeriod("3d"), Is.False); + Assert.That(new TimeSpan(2, 0, 0, 0) < new CacheLagPeriod("2d"), Is.False); + Assert.That(new TimeSpan(1, 0, 0, 0) < new CacheLagPeriod("2d")); - Assert.IsFalse(new TimeSpan(2, 0, 0, 1) < new CacheLagPeriod("2d")); - Assert.IsFalse(new TimeSpan(2, 0, 0, 0) < new CacheLagPeriod("2d")); - Assert.IsTrue(new TimeSpan(2, 0, 0, 1) > new CacheLagPeriod("2d")); + Assert.That(new TimeSpan(2, 0, 0, 1) < new CacheLagPeriod("2d"), Is.False); + Assert.That(new TimeSpan(2, 0, 0, 0) < new CacheLagPeriod("2d"), Is.False); + Assert.That(new TimeSpan(2, 0, 0, 1) > new CacheLagPeriod("2d")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Unit/CatalogueNamingTests.cs b/Rdmp.Core.Tests/Curation/Unit/CatalogueNamingTests.cs index 4771256035..44717db2d9 100644 --- a/Rdmp.Core.Tests/Curation/Unit/CatalogueNamingTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/CatalogueNamingTests.cs @@ -19,7 +19,7 @@ public class CatalogueNamingTests [TestCase("WTF?")] public void StupidCatalogueNames(string name) { - Assert.IsFalse(Catalogue.IsAcceptableName(name)); + Assert.That(Catalogue.IsAcceptableName(name), Is.False); } [Test] @@ -30,6 +30,6 @@ public void StupidCatalogueNames(string name) [TestCase("Bob&Betty")] public void SensibleCatalogueNames(string name) { - Assert.IsTrue(Catalogue.IsAcceptableName(name)); + Assert.That(Catalogue.IsAcceptableName(name)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Unit/CommitAssemblyTest.cs b/Rdmp.Core.Tests/Curation/Unit/CommitAssemblyTest.cs index 27e6c4aa70..fc03ccf1f4 100644 --- a/Rdmp.Core.Tests/Curation/Unit/CommitAssemblyTest.cs +++ b/Rdmp.Core.Tests/Curation/Unit/CommitAssemblyTest.cs @@ -20,7 +20,7 @@ public void TestGetTypeByName() var t = Type.GetType(s.GetType().AssemblyQualifiedName); - Assert.AreEqual(s.GetType(), t); + Assert.That(t, Is.EqualTo(s.GetType())); } public enum ScheduleStrategy diff --git a/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestBiochemistryCreation.cs b/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestBiochemistryCreation.cs index c5e48e64e4..fa7e8fd6b4 100644 --- a/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestBiochemistryCreation.cs +++ b/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestBiochemistryCreation.cs @@ -39,12 +39,14 @@ public void CreateCSV(int numberOfRecords) biochem.GenerateTestDataFile(people, f, numberOfRecords); - //one progress task only, should have reported creating the correct number of rows - Assert.IsTrue(finished); - Assert.AreEqual(numberOfRecords, finishedWithRecords); + Assert.Multiple(() => + { + //one progress task only, should have reported creating the correct number of rows + Assert.That(finished); + Assert.That(finishedWithRecords, Is.EqualTo(numberOfRecords)); - Assert.GreaterOrEqual(File.ReadAllLines(f.FullName).Length, - numberOfRecords); //can be newlines in middle of file + Assert.That(File.ReadAllLines(f.FullName), Has.Length.GreaterThanOrEqualTo(numberOfRecords)); //can be newlines in middle of file + }); Console.WriteLine($"Created file: {f.FullName}"); f.Delete(); diff --git a/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestDemographyCreation.cs b/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestDemographyCreation.cs index e1efc2deea..80990b790a 100644 --- a/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestDemographyCreation.cs +++ b/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestDemographyCreation.cs @@ -41,13 +41,15 @@ public void CreateCSV(int numberOfRecords) demog.GenerateTestDataFile(people, f, numberOfRecords); - //one progress task only, should have reported craeting 10,000 rows - //one progress task only, should have reported creating the correct number of rows - Assert.IsTrue(finished); - Assert.AreEqual(numberOfRecords, finishedWithRecords); + Assert.Multiple(() => + { + //one progress task only, should have reported craeting 10,000 rows + //one progress task only, should have reported creating the correct number of rows + Assert.That(finished); + Assert.That(finishedWithRecords, Is.EqualTo(numberOfRecords)); - Assert.GreaterOrEqual(File.ReadAllLines(f.FullName).Length, - numberOfRecords); //can be newlines in middle of file + Assert.That(File.ReadAllLines(f.FullName), Has.Length.GreaterThanOrEqualTo(numberOfRecords)); //can be newlines in middle of file + }); f.Delete(); } diff --git a/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestPrescribingCreation.cs b/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestPrescribingCreation.cs index 061fc37c31..4b57512035 100644 --- a/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestPrescribingCreation.cs +++ b/Rdmp.Core.Tests/Curation/Unit/ExerciseData/TestPrescribingCreation.cs @@ -41,11 +41,14 @@ public void CreateCSV(int numberOfRecords) prescribing.GenerateTestDataFile(people, f, numberOfRecords); - //one progress task only, should have reported creating the correct number of rows - Assert.IsTrue(finished); - Assert.AreEqual(numberOfRecords, finishedWithRecords); + Assert.Multiple(() => + { + //one progress task only, should have reported creating the correct number of rows + Assert.That(finished); + Assert.That(finishedWithRecords, Is.EqualTo(numberOfRecords)); - Assert.GreaterOrEqual(File.ReadLines(f.FullName).Count(), numberOfRecords); //can be newlines in middle of file + Assert.That(File.ReadLines(f.FullName).Count(), Is.GreaterThanOrEqualTo(numberOfRecords)); //can be newlines in middle of file + }); f.Delete(); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Unit/IColumnTests.cs b/Rdmp.Core.Tests/Curation/Unit/IColumnTests.cs index e33c21ff4b..2d39c170db 100644 --- a/Rdmp.Core.Tests/Curation/Unit/IColumnTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/IColumnTests.cs @@ -57,13 +57,16 @@ public void GetRuntimeName_Strings_Pass() { var syntax = MicrosoftQuerySyntaxHelper.Instance; - Assert.AreEqual(syntax.GetRuntimeName("[test]"), "test"); - Assert.AreEqual(syntax.GetRuntimeName("`test`"), "`test`"); - Assert.AreEqual(syntax.GetRuntimeName("`[test]`"), "`[test]`"); - Assert.AreEqual(syntax.GetRuntimeName("[mydb].[test]"), "test"); - Assert.AreEqual(syntax.GetRuntimeName("`mymysqldb`.`test`"), "`test`"); - Assert.AreEqual(syntax.GetRuntimeName("[mydb]..[test]"), "test"); - Assert.AreEqual(syntax.GetRuntimeName("[SERVER].[mydb]..[test]"), "test"); + Assert.Multiple(() => + { + Assert.That(syntax.GetRuntimeName("[test]"), Is.EqualTo("test")); + Assert.That(syntax.GetRuntimeName("`test`"), Is.EqualTo("`test`")); + Assert.That(syntax.GetRuntimeName("`[test]`"), Is.EqualTo("`[test]`")); + Assert.That(syntax.GetRuntimeName("[mydb].[test]"), Is.EqualTo("test")); + Assert.That(syntax.GetRuntimeName("`mymysqldb`.`test`"), Is.EqualTo("`test`")); + Assert.That(syntax.GetRuntimeName("[mydb]..[test]"), Is.EqualTo("test")); + Assert.That(syntax.GetRuntimeName("[SERVER].[mydb]..[test]"), Is.EqualTo("test")); + }); } [Test] @@ -74,14 +77,14 @@ public void GetRuntimeName_IColumns_Pass() Alias = "test" }; - Assert.AreEqual(tc.GetRuntimeName(), "test"); + Assert.That(tc.GetRuntimeName(), Is.EqualTo("test")); tc.SelectSQL = "MangleQuery([mydb]..[myExcitingField])"; //still has Alias - Assert.AreEqual(tc.GetRuntimeName(), "test"); + Assert.That(tc.GetRuntimeName(), Is.EqualTo("test")); tc.Alias = null; tc.SelectSQL = "[mydb]..[myExcitingField]"; - Assert.AreEqual(tc.GetRuntimeName(), "myExcitingField"); + Assert.That(tc.GetRuntimeName(), Is.EqualTo("myExcitingField")); } [Test] @@ -120,7 +123,7 @@ public void CheckSyntax_IColumn_ThrowBecauseInvalidAlias1() Alias = "bob smith" }; var ex = Assert.Throws(() => tc.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("Whitespace found in unwrapped Alias \"bob smith\"", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Whitespace found in unwrapped Alias \"bob smith\"")); } [Test] @@ -132,7 +135,7 @@ public void CheckSyntax_IColumn_ThrowBecauseInvalidAlias2() }; var ex = Assert.Throws(() => tc.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("Invalid characters found in Alias \"`bob\"", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Invalid characters found in Alias \"`bob\"")); } [Test] @@ -143,7 +146,7 @@ public void CheckSyntax_IColumn_ThrowBecauseInvalidAlias3() Alias = "bob]" }; var ex = Assert.Throws(() => tc.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("Invalid characters found in Alias \"bob]\"", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Invalid characters found in Alias \"bob]\"")); } [Test] @@ -155,6 +158,6 @@ public void CheckSyntax_IColumn_ThrowBecauseInvalidSelectSQL() SelectSQL = "GetSomething('here'" }; var ex = Assert.Throws(() => tc.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("Mismatch in the number of opening '(' and closing ')'", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Mismatch in the number of opening '(' and closing ')'")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Unit/IMightBeReadOnlyTests.cs b/Rdmp.Core.Tests/Curation/Unit/IMightBeReadOnlyTests.cs index a42e97f7b3..75f34dfb71 100644 --- a/Rdmp.Core.Tests/Curation/Unit/IMightBeReadOnlyTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/IMightBeReadOnlyTests.cs @@ -22,7 +22,7 @@ public void IsReadonly_AggregateFilterContainer() { //im probably an orphan var c = WhenIHaveA(); - Assert.IsFalse(c.ShouldBeReadOnly(out _)); + Assert.That(c.ShouldBeReadOnly(out _), Is.False); //now I am in a cic var cic = WhenIHaveA(); @@ -30,29 +30,35 @@ public void IsReadonly_AggregateFilterContainer() cic.CreateRootContainerIfNotExists(); cic.RootCohortAggregateContainer.AddChild(c.GetAggregate(), 0); - Assert.IsFalse(c.ShouldBeReadOnly(out _)); + Assert.That(c.ShouldBeReadOnly(out _), Is.False); cic.Frozen = true; - Assert.IsTrue(c.ShouldBeReadOnly(out var reason)); + Assert.Multiple(() => + { + Assert.That(c.ShouldBeReadOnly(out var reason)); - Assert.AreEqual("fff is Frozen", reason); + Assert.That(reason, Is.EqualTo("fff is Frozen")); + }); } [Test] public void IsReadonly_ExtractionFilterContainer() { var c = WhenIHaveA(); - Assert.IsFalse(c.ShouldBeReadOnly(out _)); + Assert.That(c.ShouldBeReadOnly(out _), Is.False); var ec = c.GetSelectedDataSetIfAny().ExtractionConfiguration; - Assert.IsFalse(c.ShouldBeReadOnly(out _)); + Assert.That(c.ShouldBeReadOnly(out _), Is.False); ec.Name = "lll"; ec.IsReleased = true; - Assert.IsTrue(c.ShouldBeReadOnly(out var reason)); + Assert.Multiple(() => + { + Assert.That(c.ShouldBeReadOnly(out var reason)); - Assert.AreEqual("lll has already been released", reason); + Assert.That(reason, Is.EqualTo("lll has already been released")); + }); } [Test] @@ -60,7 +66,7 @@ public void IsReadonly_SpontaneousContainer() { var memoryrepo = new MemoryCatalogueRepository(); var c = new SpontaneouslyInventedFilterContainer(memoryrepo, null, null, FilterContainerOperation.AND); - Assert.IsFalse(c.ShouldBeReadOnly(out _), + Assert.That(c.ShouldBeReadOnly(out _), Is.False, "Spont containers should never be in UI but let's not tell the programmer they shouldn't be edited"); } @@ -70,7 +76,7 @@ public void IsReadonly_AggregateFilter() { //im probably an orphan var f = WhenIHaveA(); - Assert.IsFalse(f.ShouldBeReadOnly(out _)); + Assert.That(f.ShouldBeReadOnly(out _), Is.False); //now I am in a cic var cic = WhenIHaveA(); @@ -78,25 +84,31 @@ public void IsReadonly_AggregateFilter() cic.CreateRootContainerIfNotExists(); cic.RootCohortAggregateContainer.AddChild(f.GetAggregate(), 0); - Assert.IsFalse(f.ShouldBeReadOnly(out _)); + Assert.That(f.ShouldBeReadOnly(out _), Is.False); cic.Frozen = true; - Assert.IsTrue(f.ShouldBeReadOnly(out var reason)); + Assert.Multiple(() => + { + Assert.That(f.ShouldBeReadOnly(out var reason)); - Assert.AreEqual("fff is Frozen", reason); + Assert.That(reason, Is.EqualTo("fff is Frozen")); + }); } [Test] public void IsReadonly_DeployedExtractionFilter() { var f = WhenIHaveA(); - Assert.IsFalse(f.ShouldBeReadOnly(out _)); + Assert.That(f.ShouldBeReadOnly(out _), Is.False); var ec = ((FilterContainer)f.FilterContainer).GetSelectedDataSetIfAny().ExtractionConfiguration; ec.Name = "lll"; ec.IsReleased = true; - Assert.IsTrue(f.ShouldBeReadOnly(out var reason)); + Assert.Multiple(() => + { + Assert.That(f.ShouldBeReadOnly(out var reason)); - Assert.AreEqual("lll has already been released", reason); + Assert.That(reason, Is.EqualTo("lll has already been released")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Unit/ObjectConstructorTests.cs b/Rdmp.Core.Tests/Curation/Unit/ObjectConstructorTests.cs index 6130dbfec2..bbe5a14b51 100644 --- a/Rdmp.Core.Tests/Curation/Unit/ObjectConstructorTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/ObjectConstructorTests.cs @@ -29,7 +29,7 @@ public void ConstructValidTests() //basic case - identical Type parameter var instance = (TestClass2)ObjectConstructor.Construct(typeof(TestClass2), testarg); - Assert.AreEqual(instance.A.Text, "amagad"); + Assert.That(instance.A.Text, Is.EqualTo("amagad")); //also allowed because testarg2 is a testarg derived class ObjectConstructor.Construct(typeof(TestClass2), testarg2); @@ -48,7 +48,7 @@ public void ConstructValidTests() //not valid because there are 2 constructors that are both base classes of TestArg3 so ObjectConstructor doesn't know which to invoke var ex = Assert.Throws(() => ObjectConstructor.Construct(typeof(TestClass4), testarg3)); - Assert.IsTrue(ex?.Message.Contains("Could not pick the correct constructor between")); + Assert.That(ex?.Message, Does.Contain("Could not pick the correct constructor between")); //exactly the same as the above case but one constructor has been decorated with [UseWithObjectConstructor] attribute ObjectConstructor.Construct(typeof(TestClass5), testarg3); @@ -57,11 +57,14 @@ public void ConstructValidTests() [Test] public void ConstructIfPossibleTests_BlankConstructors() { - //blank constructors are only used if no params are specified - Assert.IsNotNull(ObjectConstructor.ConstructIfPossible(typeof(TestClassDefaultConstructor))); + Assert.Multiple(() => + { + //blank constructors are only used if no params are specified + Assert.That(ObjectConstructor.ConstructIfPossible(typeof(TestClassDefaultConstructor)), Is.Not.Null); - //no constructor taking an int - Assert.IsNull(ObjectConstructor.ConstructIfPossible(typeof(TestClassDefaultConstructor), 8)); + //no constructor taking an int + Assert.That(ObjectConstructor.ConstructIfPossible(typeof(TestClassDefaultConstructor), 8), Is.Null); + }); } [Test] @@ -73,7 +76,7 @@ public void GetRepositoryConstructor_AllDatabaseEntities_OneWinningConstructor() foreach (var t in Core.Repositories.MEF.GetAllTypes().Where(typeof(DatabaseEntity).IsAssignableFrom)) try { - Assert.IsNotNull(ObjectConstructor.GetRepositoryConstructor(typeof(Catalogue))); + Assert.That(ObjectConstructor.GetRepositoryConstructor(typeof(Catalogue)), Is.Not.Null); countCompatible++; } catch (Exception e) @@ -81,8 +84,11 @@ public void GetRepositoryConstructor_AllDatabaseEntities_OneWinningConstructor() badTypes.Add(t, e); } - Assert.IsEmpty(badTypes); - Assert.GreaterOrEqual(countCompatible, 10); + Assert.Multiple(() => + { + Assert.That(badTypes, Is.Empty); + Assert.That(countCompatible, Is.GreaterThanOrEqualTo(10)); + }); Console.WriteLine($"Found compatible constructors on {countCompatible} objects"); } diff --git a/Rdmp.Core.Tests/Curation/Unit/ParameterManagerTests.cs b/Rdmp.Core.Tests/Curation/Unit/ParameterManagerTests.cs index 0ff0b8e98c..06b8877816 100644 --- a/Rdmp.Core.Tests/Curation/Unit/ParameterManagerTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/ParameterManagerTests.cs @@ -35,14 +35,17 @@ public void Test_ParameterManager_SimpleRename() var final = pm3.GetFinalResolvedParametersList().ToArray(); - //the final composite parameters should have a rename in them - Assert.AreEqual("@fish", final[0].ParameterName); - Assert.AreEqual("@fish_2", final[1].ParameterName); + Assert.Multiple(() => + { + //the final composite parameters should have a rename in them + Assert.That(final[0].ParameterName, Is.EqualTo("@fish")); + Assert.That(final[1].ParameterName, Is.EqualTo("@fish_2")); - Assert.IsEmpty(renames1); + Assert.That(renames1, Is.Empty); - Assert.AreEqual("@fish", renames2.Single().Key); - Assert.AreEqual("@fish_2", renames2.Single().Value); + Assert.That(renames2.Single().Key, Is.EqualTo("@fish")); + Assert.That(renames2.Single().Value, Is.EqualTo("@fish_2")); + }); } [Test] @@ -63,15 +66,18 @@ public void FindOverridenParameters_OneOnlyTest(ParameterLevel addAt, ParameterL var overrides = pm.GetOverridenParameters().ToArray(); - Assert.IsNull(pm.GetOverrideIfAnyFor(overridingParameter)); - Assert.AreEqual(pm.GetOverrideIfAnyFor(myParameter), overridingParameter); + Assert.Multiple(() => + { + Assert.That(pm.GetOverrideIfAnyFor(overridingParameter), Is.Null); + Assert.That(overridingParameter, Is.EqualTo(pm.GetOverrideIfAnyFor(myParameter))); - Assert.AreEqual(1, overrides.Length); - Assert.AreEqual(myParameter, overrides[0]); + Assert.That(overrides, Has.Length.EqualTo(1)); + }); + Assert.That(overrides[0], Is.EqualTo(myParameter)); var final = pm.GetFinalResolvedParametersList().ToArray(); - Assert.AreEqual(1, final.Length); - Assert.AreEqual(overridingParameter, final[0]); + Assert.That(final, Has.Length.EqualTo(1)); + Assert.That(final[0], Is.EqualTo(overridingParameter)); } [Test] @@ -88,11 +94,14 @@ public void FindOverridenParameters_CaseSensitivityTest() var parameters = pm.GetFinalResolvedParametersList().ToArray(); - Assert.AreEqual(1, parameters.Length); - + Assert.That(parameters, Has.Length.EqualTo(1)); + var final = parameters.Single(); - Assert.AreEqual("@Fish", final.ParameterName); - Assert.AreEqual("3", final.Value); + Assert.Multiple(() => + { + Assert.That(final.ParameterName, Is.EqualTo("@Fish")); + Assert.That(final.Value, Is.EqualTo("3")); + }); } [Test] @@ -113,17 +122,26 @@ public void FindOverridenParameters_TwoTest() var overrides = pm.GetOverridenParameters().ToArray(); - Assert.IsNull(pm.GetOverrideIfAnyFor(overridingParameter)); - Assert.AreEqual(pm.GetOverrideIfAnyFor(myParameter1), overridingParameter); - Assert.AreEqual(pm.GetOverrideIfAnyFor(myParameter2), overridingParameter); - - Assert.AreEqual(2, overrides.Length); - Assert.AreEqual(myParameter1, overrides[0]); - Assert.AreEqual(myParameter2, overrides[1]); + Assert.Multiple(() => + { + Assert.That(pm.GetOverrideIfAnyFor(overridingParameter), Is.Null); + Assert.That(overridingParameter, Is.EqualTo(pm.GetOverrideIfAnyFor(myParameter1))); + }); + Assert.Multiple(() => + { + Assert.That(overridingParameter, Is.EqualTo(pm.GetOverrideIfAnyFor(myParameter2))); + + Assert.That(overrides, Has.Length.EqualTo(2)); + }); + Assert.Multiple(() => + { + Assert.That(overrides[0], Is.EqualTo(myParameter1)); + Assert.That(overrides[1], Is.EqualTo(myParameter2)); + }); var final = pm.GetFinalResolvedParametersList().ToArray(); - Assert.AreEqual(1, final.Length); - Assert.AreEqual(overridingParameter, final[0]); + Assert.That(final, Has.Length.EqualTo(1)); + Assert.That(final[0], Is.EqualTo(overridingParameter)); } [Test] @@ -133,15 +151,18 @@ public void ParameterDeclarationAndDeconstruction() MicrosoftQuerySyntaxHelper.Instance); var sql = QueryBuilder.GetParameterDeclarationSQL(param); - Assert.AreEqual(@"/*I've got a lovely bunch of coconuts*/ + Assert.That(sql, Is.EqualTo(@"/*I've got a lovely bunch of coconuts*/ DECLARE @Fish as int; SET @Fish=3; -", sql); +")); var after = ConstantParameter.Parse(sql, MicrosoftQuerySyntaxHelper.Instance); - Assert.AreEqual(param.ParameterSQL, after.ParameterSQL); - Assert.AreEqual(param.Value, after.Value); - Assert.AreEqual(param.Comment, after.Comment); + Assert.Multiple(() => + { + Assert.That(after.ParameterSQL, Is.EqualTo(param.ParameterSQL)); + Assert.That(after.Value, Is.EqualTo(param.Value)); + Assert.That(after.Comment, Is.EqualTo(param.Comment)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Unit/PermissionWindowTests.cs b/Rdmp.Core.Tests/Curation/Unit/PermissionWindowTests.cs index 66fc32a907..83465452e5 100644 --- a/Rdmp.Core.Tests/Curation/Unit/PermissionWindowTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/PermissionWindowTests.cs @@ -36,15 +36,18 @@ public void TestSerialisation() }; var periods = newPermissionWindow.PermissionWindowPeriods; - Assert.AreEqual(2, periods.Count); + Assert.That(periods, Has.Count.EqualTo(2)); var newPeriod1 = periods[0]; - Assert.AreEqual((int)DayOfWeek.Monday, newPeriod1.DayOfWeek); + Assert.Multiple(() => + { + Assert.That(newPeriod1.DayOfWeek, Is.EqualTo((int)DayOfWeek.Monday)); - Assert.AreEqual(6, newPeriod1.End.Hours); + Assert.That(newPeriod1.End.Hours, Is.EqualTo(6)); + }); var newPeriod2 = periods[1]; - Assert.AreEqual(17, newPeriod2.Start.Hours); + Assert.That(newPeriod2.Start.Hours, Is.EqualTo(17)); } [Test] @@ -63,7 +66,7 @@ public void TestCurrentlyWithinPermissionPeriod() var permissionWindow = new PermissionWindow(CatalogueRepository); permissionWindow.SetPermissionWindowPeriods(new List { period1 }); - Assert.IsTrue(permissionWindow.WithinPermissionWindow()); + Assert.That(permissionWindow.WithinPermissionWindow()); } [Test] @@ -81,6 +84,6 @@ public void TestCurrentlyOutsidePermissionPeriod() var permissionWindow = new PermissionWindow(CatalogueRepository); permissionWindow.SetPermissionWindowPeriods(new List { period1 }); - Assert.IsFalse(permissionWindow.WithinPermissionWindow()); + Assert.That(permissionWindow.WithinPermissionWindow(), Is.False); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Unit/PreInitializeTests.cs b/Rdmp.Core.Tests/Curation/Unit/PreInitializeTests.cs index 3ff3837892..971de5aae0 100644 --- a/Rdmp.Core.Tests/Curation/Unit/PreInitializeTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/PreInitializeTests.cs @@ -24,9 +24,9 @@ public void TestNormal() { var fishUser = new FishUser(); - Assert.AreNotEqual(fishUser.IFish, fish); + Assert.That(fish, Is.Not.EqualTo(fishUser.IFish)); context.PreInitialize(ThrowImmediatelyDataLoadEventListener.Quiet, fishUser, fish); - Assert.AreEqual(fishUser.IFish, fish); + Assert.That(fish, Is.EqualTo(fishUser.IFish)); } [Test] @@ -34,9 +34,9 @@ public void TestOneOFMany() { var fishUser = new FishUser(); - Assert.AreNotEqual(fishUser.IFish, fish); + Assert.That(fish, Is.Not.EqualTo(fishUser.IFish)); context.PreInitialize(ThrowImmediatelyDataLoadEventListener.Quiet, fishUser, new object(), fish); - Assert.AreEqual(fishUser.IFish, fish); + Assert.That(fish, Is.EqualTo(fishUser.IFish)); } [Test] @@ -44,9 +44,9 @@ public void TestCasting() { var fishUser = new FishUser(); - Assert.AreNotEqual(fishUser.IFish, fish); + Assert.That(fish, Is.Not.EqualTo(fishUser.IFish)); context.PreInitialize(ThrowImmediatelyDataLoadEventListener.Quiet, fishUser, (IFish)fish); - Assert.AreEqual(fishUser.IFish, fish); + Assert.That(fish, Is.EqualTo(fishUser.IFish)); } [Test] @@ -55,9 +55,9 @@ public void TestDownCasting() var fishUser = new SpecificFishUser(); IFish f = fish; - Assert.AreNotEqual(fishUser.IFish, fish); + Assert.That(fish, Is.Not.EqualTo(fishUser.IFish)); context.PreInitialize(ThrowImmediatelyDataLoadEventListener.Quiet, fishUser, f); - Assert.AreEqual(fishUser.IFish, fish); + Assert.That(fish, Is.EqualTo(fishUser.IFish)); } [Test] @@ -66,7 +66,7 @@ public void TestNoObjects() var fishUser = new SpecificFishUser(); var ex = Assert.Throws(() => context.PreInitialize(ThrowImmediatelyDataLoadEventListener.Quiet, fishUser, Array.Empty())); - Assert.IsTrue(ex.Message.Contains("The following expected types were not passed to PreInitialize:Fish")); + Assert.That(ex.Message, Does.Contain("The following expected types were not passed to PreInitialize:Fish")); } [Test] @@ -75,9 +75,9 @@ public void TestWrongObjects() var fishUser = new SpecificFishUser(); var ex = Assert.Throws(() => context.PreInitialize(ThrowImmediatelyDataLoadEventListener.Quiet, fishUser, new Penguin())); - Assert.IsTrue(ex.Message.Contains("The following expected types were not passed to PreInitialize:Fish")); - Assert.IsTrue(ex.Message.Contains("The object types passed were:")); - Assert.IsTrue(ex.Message.Contains("Penguin")); + Assert.That(ex.Message, Does.Contain("The following expected types were not passed to PreInitialize:Fish")); + Assert.That(ex.Message, Does.Contain("The object types passed were:")); + Assert.That(ex.Message, Does.Contain("Penguin")); } diff --git a/Rdmp.Core.Tests/Curation/Unit/SimpleColumnInfoTests.cs b/Rdmp.Core.Tests/Curation/Unit/SimpleColumnInfoTests.cs index 15064a041d..72d0047ac7 100644 --- a/Rdmp.Core.Tests/Curation/Unit/SimpleColumnInfoTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/SimpleColumnInfoTests.cs @@ -33,8 +33,7 @@ public void GetColumnLength(string type, int? expectedLength) Import(t, out var ti, out var cis); - Assert.AreEqual(expectedLength, - cis.Single().Discover(DataAccessContext.InternalDataProcessing).DataType.GetLengthIfString()); + Assert.That(cis.Single().Discover(DataAccessContext.InternalDataProcessing).DataType.GetLengthIfString(), Is.EqualTo(expectedLength)); ti.DeleteInDatabase(); } diff --git a/Rdmp.Core.Tests/Curation/Unit/SqlSyntaxHelperTests.cs b/Rdmp.Core.Tests/Curation/Unit/SqlSyntaxHelperTests.cs index 0dc171f0b0..ca5aa79b5f 100644 --- a/Rdmp.Core.Tests/Curation/Unit/SqlSyntaxHelperTests.cs +++ b/Rdmp.Core.Tests/Curation/Unit/SqlSyntaxHelperTests.cs @@ -5,9 +5,7 @@ // You should have received a copy of the GNU General Public License along with RDMP. If not, see . using FAnsi.Implementations.MicrosoftSQL; -using NSubstitute; using NUnit.Framework; -using Rdmp.Core.Curation.Data; using Rdmp.Core.QueryBuilding; namespace Rdmp.Core.Tests.Curation.Unit; @@ -18,24 +16,19 @@ public class SqlSyntaxHelperTests [Test] public void GetNullSubstituteTests() { - Assert.AreEqual("-999", - PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(3)", true)); - Assert.AreEqual("-9999999999", - PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(10)", true)); - Assert.AreEqual("-99.9", - PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(3,1)", true)); - Assert.AreEqual("-.9999", - PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(4,4)", true)); - - - Assert.AreEqual("999", - PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(3)", false)); - Assert.AreEqual("9999999999", - PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(10)", false)); - Assert.AreEqual("99.9", - PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(3,1)", false)); - Assert.AreEqual(".9999", - PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(4,4)", false)); + Assert.Multiple(() => + { + Assert.That(PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(3)", true), Is.EqualTo("-999")); + Assert.That(PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(10)", true), Is.EqualTo("-9999999999")); + Assert.That(PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(3,1)", true), Is.EqualTo("-99.9")); + Assert.That(PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(4,4)", true), Is.EqualTo("-.9999")); + + + Assert.That(PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(3)", false), Is.EqualTo("999")); + Assert.That(PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(10)", false), Is.EqualTo("9999999999")); + Assert.That(PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(3,1)", false), Is.EqualTo("99.9")); + Assert.That(PrimaryKeyCollisionResolver.GetNullSubstituteForComparisonsWithDataType("decimal(4,4)", false), Is.EqualTo(".9999")); + }); } [Test] @@ -45,18 +38,27 @@ public void SplitMethod() syntaxHelper.SplitLineIntoOuterMostMethodAndContents("count(*)", out var method, out var contents); - Assert.AreEqual("count", method); - Assert.AreEqual("*", contents); + Assert.Multiple(() => + { + Assert.That(method, Is.EqualTo("count")); + Assert.That(contents, Is.EqualTo("*")); + }); syntaxHelper.SplitLineIntoOuterMostMethodAndContents("count()", out method, out contents); - Assert.AreEqual("count", method); - Assert.AreEqual("", contents); + Assert.Multiple(() => + { + Assert.That(method, Is.EqualTo("count")); + Assert.That(contents, Is.EqualTo("")); + }); syntaxHelper.SplitLineIntoOuterMostMethodAndContents("LTRIM(RTRIM([Fish]))", out method, out contents); - Assert.AreEqual("LTRIM", method); - Assert.AreEqual("RTRIM([Fish])", contents); + Assert.Multiple(() => + { + Assert.That(method, Is.EqualTo("LTRIM")); + Assert.That(contents, Is.EqualTo("RTRIM([Fish])")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/Unit/TestAcronymGeneration.cs b/Rdmp.Core.Tests/Curation/Unit/TestAcronymGeneration.cs index 26b988e34a..2edb057a1a 100644 --- a/Rdmp.Core.Tests/Curation/Unit/TestAcronymGeneration.cs +++ b/Rdmp.Core.Tests/Curation/Unit/TestAcronymGeneration.cs @@ -25,6 +25,6 @@ public void Predict(string name, string predictedAcronym) var suggestion = DitaCatalogueExtractor.GetAcronymSuggestionFromCatalogueName(name); - Assert.AreEqual(predictedAcronym, suggestion); + Assert.That(suggestion, Is.EqualTo(predictedAcronym)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/UnitTestsAllObjectsSupported.cs b/Rdmp.Core.Tests/Curation/UnitTestsAllObjectsSupported.cs index 35403837c1..95d816bebc 100644 --- a/Rdmp.Core.Tests/Curation/UnitTestsAllObjectsSupported.cs +++ b/Rdmp.Core.Tests/Curation/UnitTestsAllObjectsSupported.cs @@ -63,10 +63,13 @@ public void TestAllSupported() try { //and that it returns an instance - Assert.IsNotNull(instance); - Assert.IsTrue(instance.Exists()); - Assert.AreEqual(ChangeDescription.NoChanges, instance.HasLocalChanges().Evaluation, - "Type was '" + t.Name + "'"); + Assert.That(instance, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(instance.Exists()); + Assert.That(instance.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.NoChanges), + "Type was '" + t.Name + "'"); + }); } catch (Exception e) { @@ -74,7 +77,7 @@ public void TestAllSupported() } } - Assert.IsEmpty(notSupported, + Assert.That(notSupported, Is.Empty, $"The following Types were not supported by WhenIHaveA:{Environment.NewLine}{string.Join(Environment.NewLine, notSupported.Select(t => t.Name))}"); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Curation/YamlRepositoryTests.cs b/Rdmp.Core.Tests/Curation/YamlRepositoryTests.cs index c3b09d93f1..cfe30dfad3 100644 --- a/Rdmp.Core.Tests/Curation/YamlRepositoryTests.cs +++ b/Rdmp.Core.Tests/Curation/YamlRepositoryTests.cs @@ -14,10 +14,8 @@ using Rdmp.Core.Repositories; using Rdmp.Core.Repositories.Managers; using System; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; using System.Text; using Tests.Common; @@ -53,7 +51,7 @@ public void PersistDefaults() repo1.SetDefault(PermissableDefaults.LiveLoggingServer_ID, eds); var repo2 = new YamlRepository(dir); - Assert.AreEqual(eds, repo2.GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID)); + Assert.That(repo2.GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID), Is.EqualTo(eds)); } [Test] @@ -67,13 +65,13 @@ public void PersistPackageContents() var package = UnitTests.WhenIHaveA(repo1); - Assert.IsEmpty(repo1.GetPackageContentsDictionary()); + Assert.That(repo1.GetPackageContentsDictionary(), Is.Empty); repo1.PackageManager.AddDataSetToPackage(package, ds); - Assert.IsNotEmpty(repo1.GetPackageContentsDictionary()); + Assert.That(repo1.GetPackageContentsDictionary(), Is.Not.Empty); // A fresh repo loaded from the same directory should have persisted object relationships var repo2 = new YamlRepository(dir); - Assert.IsNotEmpty(repo2.GetPackageContentsDictionary()); + Assert.That(repo2.GetPackageContentsDictionary(), Is.Not.Empty); } [Test] @@ -86,7 +84,7 @@ public void PersistDataExportPropertyManagerValues() // A fresh repo loaded from the same directory should have persisted object relationships var repo2 = new YamlRepository(dir); - Assert.AreEqual("yarg", repo2.DataExportPropertyManager.GetValue(DataExportProperty.HashingAlgorithmPattern)); + Assert.That(repo2.DataExportPropertyManager.GetValue(DataExportProperty.HashingAlgorithmPattern), Is.EqualTo("yarg")); } [Test] @@ -99,13 +97,13 @@ public void PersistGovernancePeriods() var period = UnitTests.WhenIHaveA(repo1); var cata = UnitTests.WhenIHaveA(repo1); - Assert.IsEmpty(repo1.GetAllGovernedCatalogues(period)); + Assert.That(repo1.GetAllGovernedCatalogues(period), Is.Empty); repo1.Link(period, cata); - Assert.IsNotEmpty(repo1.GetAllGovernedCatalogues(period)); + Assert.That(repo1.GetAllGovernedCatalogues(period), Is.Not.Empty); // A fresh repo loaded from the same directory should have persisted object relationships var repo2 = new YamlRepository(dir); - Assert.IsNotEmpty(repo2.GetAllGovernedCatalogues(period)); + Assert.That(repo2.GetAllGovernedCatalogues(period), Is.Not.Empty); } @@ -119,16 +117,25 @@ public void PersistForcedJoins() var ac = UnitTests.WhenIHaveA(repo1); var t = UnitTests.WhenIHaveA(repo1); - Assert.IsEmpty(ac.ForcedJoins); - Assert.IsEmpty(repo1.AggregateForcedJoinManager.GetAllForcedJoinsFor(ac)); + Assert.Multiple(() => + { + Assert.That(ac.ForcedJoins, Is.Empty); + Assert.That(repo1.AggregateForcedJoinManager.GetAllForcedJoinsFor(ac), Is.Empty); + }); repo1.AggregateForcedJoinManager.CreateLinkBetween(ac, t); - Assert.IsNotEmpty(ac.ForcedJoins); - Assert.IsNotEmpty(repo1.AggregateForcedJoinManager.GetAllForcedJoinsFor(ac)); + Assert.Multiple(() => + { + Assert.That(ac.ForcedJoins, Is.Not.Empty); + Assert.That(repo1.AggregateForcedJoinManager.GetAllForcedJoinsFor(ac), Is.Not.Empty); + }); // A fresh repo loaded from the same directory should have persisted object relationships var repo2 = new YamlRepository(dir); - Assert.IsNotEmpty(ac.ForcedJoins); - Assert.IsNotEmpty(repo2.AggregateForcedJoinManager.GetAllForcedJoinsFor(ac)); + Assert.Multiple(() => + { + Assert.That(ac.ForcedJoins, Is.Not.Empty); + Assert.That(repo2.AggregateForcedJoinManager.GetAllForcedJoinsFor(ac), Is.Not.Empty); + }); } @@ -149,17 +156,23 @@ public void PersistCohortSubcontainers() root.AddChild(sub1); root.AddChild(ac, 0); - Assert.IsNotEmpty(root.GetOrderedContents()); - Assert.AreEqual(ac, root.GetOrderedContents().ToArray()[0]); - Assert.AreEqual(sub1, root.GetOrderedContents().ToArray()[1]); + Assert.That(root.GetOrderedContents(), Is.Not.Empty); + Assert.Multiple(() => + { + Assert.That(root.GetOrderedContents().ToArray()[0], Is.EqualTo(ac)); + Assert.That(root.GetOrderedContents().ToArray()[1], Is.EqualTo(sub1)); + }); // A fresh repo loaded from the same directory should have persisted object relationships var repo2 = new YamlRepository(dir); root = repo2.GetObjectByID(root.ID); - Assert.IsNotEmpty(root.GetOrderedContents()); - Assert.AreEqual(ac, root.GetOrderedContents().ToArray()[0]); - Assert.AreEqual(sub1, root.GetOrderedContents().ToArray()[1]); + Assert.That(root.GetOrderedContents(), Is.Not.Empty); + Assert.Multiple(() => + { + Assert.That(root.GetOrderedContents().ToArray()[0], Is.EqualTo(ac)); + Assert.That(root.GetOrderedContents().ToArray()[1], Is.EqualTo(sub1)); + }); } [Test] @@ -177,15 +190,21 @@ public void PersistFilterContainers() var sub = new AggregateFilterContainer(repo1, FilterContainerOperation.AND); ac.RootFilterContainer.AddChild(sub); - Assert.AreEqual(sub, ac.RootFilterContainer.GetSubContainers().Single()); - Assert.AreEqual(f, ac.RootFilterContainer.GetFilters().Single()); + Assert.Multiple(() => + { + Assert.That(ac.RootFilterContainer.GetSubContainers().Single(), Is.EqualTo(sub)); + Assert.That(ac.RootFilterContainer.GetFilters().Single(), Is.EqualTo(f)); + }); // A fresh repo loaded from the same directory should have persisted object relationships var repo2 = new YamlRepository(dir); ac = repo2.GetObjectByID(ac.ID); - Assert.AreEqual(sub, ac.RootFilterContainer.GetSubContainers().Single()); - Assert.AreEqual(f, ac.RootFilterContainer.GetFilters().Single()); + Assert.Multiple(() => + { + Assert.That(ac.RootFilterContainer.GetSubContainers().Single(), Is.EqualTo(sub)); + Assert.That(ac.RootFilterContainer.GetFilters().Single(), Is.EqualTo(f)); + }); } [Test] @@ -204,15 +223,21 @@ public void PersistFilterContainers_Orphans() var sub = new AggregateFilterContainer(repo1, FilterContainerOperation.AND); ac.RootFilterContainer.AddChild(sub); - Assert.AreEqual(sub, ac.RootFilterContainer.GetSubContainers().Single()); - Assert.AreEqual(f, ac.RootFilterContainer.GetFilters().Single()); + Assert.Multiple(() => + { + Assert.That(ac.RootFilterContainer.GetSubContainers().Single(), Is.EqualTo(sub)); + Assert.That(ac.RootFilterContainer.GetFilters().Single(), Is.EqualTo(f)); + }); // A fresh repo loaded from the same directory should have persisted object relationships var repo2 = new YamlRepository(dir); ac = repo2.GetObjectByID(ac.ID); - Assert.AreEqual(sub, ac.RootFilterContainer.GetSubContainers().Single()); - Assert.AreEqual(f, ac.RootFilterContainer.GetFilters().Single()); + Assert.Multiple(() => + { + Assert.That(ac.RootFilterContainer.GetSubContainers().Single(), Is.EqualTo(sub)); + Assert.That(ac.RootFilterContainer.GetFilters().Single(), Is.EqualTo(f)); + }); // Make an orphan container by deleting the root @@ -226,10 +251,13 @@ public void PersistFilterContainers_Orphans() // A fresh repo loaded from the same directory var repo3 = new YamlRepository(dir); - // all these things should be gone - Assert.IsFalse(repo3.StillExists(sub)); - Assert.IsFalse(repo3.StillExists(root)); - Assert.IsFalse(repo3.StillExists(f)); + Assert.Multiple(() => + { + // all these things should be gone + Assert.That(repo3.StillExists(sub), Is.False); + Assert.That(repo3.StillExists(root), Is.False); + Assert.That(repo3.StillExists(f), Is.False); + }); } [Test] @@ -242,70 +270,40 @@ public void PersistCredentials() var creds = UnitTests.WhenIHaveA(repo1); var t = UnitTests.WhenIHaveA(repo1); - Assert.IsEmpty(creds.GetAllTableInfosThatUseThis().SelectMany(v => v.Value)); - Assert.IsNull(t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.DataLoad)); - Assert.IsNull( - t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.InternalDataProcessing)); + Assert.Multiple(() => + { + Assert.That(creds.GetAllTableInfosThatUseThis().SelectMany(v => v.Value), Is.Empty); + Assert.That(t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.DataLoad), Is.Null); + Assert.That( + t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.InternalDataProcessing), Is.Null); + }); repo1.TableInfoCredentialsManager.CreateLinkBetween(creds, t, ReusableLibraryCode.DataAccess.DataAccessContext.DataLoad); - Assert.AreEqual(t, creds.GetAllTableInfosThatUseThis().SelectMany(v => v.Value).Single()); - Assert.AreEqual(creds, t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.DataLoad)); - Assert.IsNull( - t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.InternalDataProcessing)); + Assert.Multiple(() => + { + Assert.That(creds.GetAllTableInfosThatUseThis().SelectMany(v => v.Value).Single(), Is.EqualTo(t)); + Assert.That(t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.DataLoad), Is.EqualTo(creds)); + Assert.That( + t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.InternalDataProcessing), Is.Null); + }); // A fresh repo loaded from the same directory should have persisted object relationships var repo2 = new YamlRepository(dir); t = repo2.GetObjectByID(t.ID); - Assert.AreEqual(t, creds.GetAllTableInfosThatUseThis().SelectMany(v => v.Value).Single()); - Assert.AreEqual(creds, t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.DataLoad)); - Assert.IsNull( - t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.InternalDataProcessing)); + Assert.Multiple(() => + { + Assert.That(creds.GetAllTableInfosThatUseThis().SelectMany(v => v.Value).Single(), Is.EqualTo(t)); + Assert.That(t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.DataLoad), Is.EqualTo(creds)); + Assert.That( + t.GetCredentialsIfExists(ReusableLibraryCode.DataAccess.DataAccessContext.InternalDataProcessing), Is.Null); + }); } - [Test] - public void YamlRepository_LoadSavePluginClass() - { - var dir = GetUniqueDirectory(); - - var repo1 = new YamlRepository(dir); - var fi = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, "Blah.zip")); - File.WriteAllBytes(fi.FullName, new byte[] { 0x1, 0x2 }); - - var version = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion; - - var lma1 = UnitTests.WhenIHaveA(repo1); - var lma2 = UnitTests.WhenIHaveA(repo1); - - - lma1.Plugin.Name = "MyPlugin1.1.1.1.nupkg"; - lma1.Plugin.RdmpVersion = new Version(version); //the version of Rdmp.Core targetted - lma1.Plugin.PluginVersion = new Version(1, 1, 1, 1); //the version of the plugin - lma1.Plugin.SaveToDatabase(); - lma1.SaveToDatabase(); - - lma2.Plugin.Name = "MyPlugin1.1.1.2.nupkg"; - lma2.Plugin.RdmpVersion = new Version(version); //the version of Rdmp.Core targetted (same as above) - lma2.Plugin.PluginVersion = new Version(1, 1, 1, 2); //the version of the plugin (higher) - lma2.Plugin.SaveToDatabase(); - lma2.SaveToDatabase(); - - var plugins = repo1.PluginManager.GetCompatiblePlugins(); - Assert.That(plugins, Has.Length.EqualTo(1)); - Assert.That(plugins[0], Is.EqualTo(lma2.Plugin)); - - - // A fresh repo loaded from the same directory should have persisted object relationships - var repo2 = new YamlRepository(dir); - plugins = repo2.PluginManager.GetCompatiblePlugins(); - Assert.That(plugins, Has.Length.EqualTo(1)); - Assert.That(plugins.Single(), Is.EqualTo(lma2.Plugin)); - } - [Test] public void TestYamlRepository_LoadObjects() { @@ -314,11 +312,11 @@ public void TestYamlRepository_LoadObjects() var c = new Catalogue(repo, "yar"); - Assert.Contains(c, repo.AllObjects.ToArray()); + Assert.That(repo.AllObjects.ToArray(), Does.Contain(c)); // creating a new repo should load the same object back var repo2 = new YamlRepository(dir); - Assert.Contains(c, repo2.AllObjects.ToArray()); + Assert.That(repo2.AllObjects.ToArray(), Does.Contain(c)); } [Test] @@ -335,8 +333,11 @@ public void TestYamlRepository_Save() // creating a new repo should load the same object back var repo2 = new YamlRepository(dir); - Assert.Contains(c, repo2.AllObjects.ToArray()); - Assert.AreEqual("ffff", repo2.AllObjects.OfType().Single().Name); + Assert.Multiple(() => + { + Assert.That(repo2.AllObjects.ToArray(), Does.Contain(c)); + Assert.That(repo2.AllObjects.OfType().Single().Name, Is.EqualTo("ffff")); + }); } private static string GetUniqueDirectoryName() => Path.Combine(TestContext.CurrentContext.WorkDirectory, diff --git a/Rdmp.Core.Tests/DataExport/Cloning/CloneExtractionConfigurationTests.cs b/Rdmp.Core.Tests/DataExport/Cloning/CloneExtractionConfigurationTests.cs index 3f938c0a08..ff2a99c63b 100644 --- a/Rdmp.Core.Tests/DataExport/Cloning/CloneExtractionConfigurationTests.cs +++ b/Rdmp.Core.Tests/DataExport/Cloning/CloneExtractionConfigurationTests.cs @@ -28,7 +28,7 @@ public void CloneWithFilters(bool introduceOrphanExtractionInformation) if (introduceOrphanExtractionInformation) IntroduceOrphan(); - Assert.IsEmpty(_configuration.ReleaseLog); + Assert.That(_configuration.ReleaseLog, Is.Empty); var filter = new ExtractionFilter(CatalogueRepository, "FilterByFish", _extractionInformations[0]); try @@ -40,7 +40,7 @@ public void CloneWithFilters(bool introduceOrphanExtractionInformation) null); filter.SaveToDatabase(); - Assert.IsTrue(filter.ExtractionFilterParameters.Count() == 1); + Assert.That(filter.ExtractionFilterParameters.Count(), Is.EqualTo(1)); //create a root container var container = new FilterContainer(DataExportRepository); @@ -60,8 +60,8 @@ public void CloneWithFilters(bool introduceOrphanExtractionInformation) var request = new ExtractDatasetCommand(_configuration, new ExtractableDatasetBundle(_extractableDataSet)); request.GenerateQueryBuilder(); - Assert.AreEqual( - CollapseWhitespace( + Assert.That( +CollapseWhitespace(request.QueryBuilder.SQL), Is.EqualTo(CollapseWhitespace( string.Format( @"DECLARE @fish AS varchar(50); SET @fish='jormungander'; @@ -88,17 +88,20 @@ SELECT DISTINCT [{0}CohortDatabase]..[Cohort].[cohortDefinition_id]=-599 " , TestDatabaseNames.Prefix)) - , CollapseWhitespace(request.QueryBuilder.SQL)); +)); var deepClone = _configuration.DeepCloneWithNewIDs(); - Assert.AreEqual(deepClone.Cohort_ID, _configuration.Cohort_ID); - Assert.AreNotEqual(deepClone.ID, _configuration.ID); + Assert.Multiple(() => + { + Assert.That(_configuration.Cohort_ID, Is.EqualTo(deepClone.Cohort_ID)); + Assert.That(_configuration.ID, Is.Not.EqualTo(deepClone.ID)); + }); try { var request2 = new ExtractDatasetCommand(deepClone, new ExtractableDatasetBundle(_extractableDataSet)); request2.GenerateQueryBuilder(); - Assert.AreEqual(request.QueryBuilder.SQL, request2.QueryBuilder.SQL); + Assert.That(request2.QueryBuilder.SQL, Is.EqualTo(request.QueryBuilder.SQL)); } finally { @@ -124,22 +127,28 @@ public void CloneWithExtractionProgress() origProgress.SaveToDatabase(); var deepClone = _configuration.DeepCloneWithNewIDs(); - Assert.AreEqual(deepClone.Cohort_ID, _configuration.Cohort_ID); - Assert.AreNotEqual(deepClone.ID, _configuration.ID); + Assert.Multiple(() => + { + Assert.That(_configuration.Cohort_ID, Is.EqualTo(deepClone.Cohort_ID)); + Assert.That(_configuration.ID, Is.Not.EqualTo(deepClone.ID)); + }); var clonedSds = deepClone.SelectedDataSets.Single(s => s.ExtractableDataSet_ID == sds.ExtractableDataSet_ID); var clonedProgress = clonedSds.ExtractionProgressIfAny; - Assert.IsNotNull(clonedProgress); - Assert.IsNull(clonedProgress.StartDate); - Assert.IsNull(clonedProgress.ProgressDate, - "Cloning a ExtractionProgress should reset its ProgressDate back to null in anticipation of it being extracted again"); + Assert.That(clonedProgress, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(clonedProgress.StartDate, Is.Null); + Assert.That(clonedProgress.ProgressDate, Is.Null, + "Cloning a ExtractionProgress should reset its ProgressDate back to null in anticipation of it being extracted again"); - Assert.AreEqual(clonedProgress.EndDate, origProgress.EndDate); - Assert.AreEqual(clonedProgress.NumberOfDaysPerBatch, origProgress.NumberOfDaysPerBatch); - Assert.AreEqual(clonedProgress.Name, origProgress.Name); - Assert.AreEqual(clonedProgress.ExtractionInformation_ID, origProgress.ExtractionInformation_ID); + Assert.That(origProgress.EndDate, Is.EqualTo(clonedProgress.EndDate)); + Assert.That(origProgress.NumberOfDaysPerBatch, Is.EqualTo(clonedProgress.NumberOfDaysPerBatch)); + Assert.That(origProgress.Name, Is.EqualTo(clonedProgress.Name)); + Assert.That(origProgress.ExtractionInformation_ID, Is.EqualTo(clonedProgress.ExtractionInformation_ID)); + }); deepClone.DeleteInDatabase(); @@ -149,7 +158,7 @@ public void CloneWithExtractionProgress() } - public void IntroduceOrphan() + private void IntroduceOrphan() { var cols = _configuration.GetAllExtractableColumnsFor(_extractableDataSet).Cast().ToArray(); diff --git a/Rdmp.Core.Tests/DataExport/Cohort/CohortTests.cs b/Rdmp.Core.Tests/DataExport/Cohort/CohortTests.cs index 4f32a96364..f6e6cd667a 100644 --- a/Rdmp.Core.Tests/DataExport/Cohort/CohortTests.cs +++ b/Rdmp.Core.Tests/DataExport/Cohort/CohortTests.cs @@ -18,25 +18,28 @@ public class CohortTests : TestsRequiringACohort [Test] public void TestOverridingReleaseIdentifier() { - //get cohort without override - Assert.IsNull(_extractableCohort.OverrideReleaseIdentifierSQL); + Assert.Multiple(() => + { + //get cohort without override + Assert.That(_extractableCohort.OverrideReleaseIdentifierSQL, Is.Null); - //should match global release identifier (from its source because there is no override) - Assert.AreEqual("ReleaseID", _extractableCohort.GetReleaseIdentifier(true)); + //should match global release identifier (from its source because there is no override) + Assert.That(_extractableCohort.GetReleaseIdentifier(true), Is.EqualTo("ReleaseID")); + }); //appy override _extractableCohort.OverrideReleaseIdentifierSQL = "Fish"; _extractableCohort.SaveToDatabase(); //should now match override - Assert.AreEqual("Fish", _extractableCohort.GetReleaseIdentifier()); + Assert.That(_extractableCohort.GetReleaseIdentifier(), Is.EqualTo("Fish")); //now set it back to null (not overriding) _extractableCohort.OverrideReleaseIdentifierSQL = null; _extractableCohort.SaveToDatabase(); //now check that we are back to the original release identifier - Assert.AreEqual("ReleaseID", _extractableCohort.GetReleaseIdentifier(true)); + Assert.That(_extractableCohort.GetReleaseIdentifier(true), Is.EqualTo("ReleaseID")); } [Test] @@ -45,15 +48,18 @@ public void TestSelf_RecordAllFailures() var failures = new RecordAllFailures(); failures.FailureMessages.Add("Hi there Thomas, How's it going?"); - Assert.IsFalse(failures.AnyFailMessageLike("Carmageddon")); + Assert.Multiple(() => + { + Assert.That(failures.AnyFailMessageLike("Carmageddon"), Is.False); - Assert.IsTrue(failures.AnyFailMessageLike("Thomas")); + Assert.That(failures.AnyFailMessageLike("Thomas")); - Assert.IsTrue(failures.AnyFailMessageLike("Thomas", "going")); - Assert.IsTrue(failures.AnyFailMessageLike("Thomas", "going", "Hi")); - Assert.IsTrue(failures.AnyFailMessageLike("thomas", "gOIng", "hi")); + Assert.That(failures.AnyFailMessageLike("Thomas", "going")); + Assert.That(failures.AnyFailMessageLike("Thomas", "going", "Hi")); + Assert.That(failures.AnyFailMessageLike("thomas", "gOIng", "hi")); - Assert.IsFalse(failures.AnyFailMessageLike("Thomas", "going", "Hi", "Fear the babadook")); + Assert.That(failures.AnyFailMessageLike("Thomas", "going", "Hi", "Fear the babadook"), Is.False); + }); } private class RecordAllFailures : ICheckNotifier diff --git a/Rdmp.Core.Tests/DataExport/Cohort/CommittingNewCohortsTests.cs b/Rdmp.Core.Tests/DataExport/Cohort/CommittingNewCohortsTests.cs index f0c8f99c8b..36c574266c 100644 --- a/Rdmp.Core.Tests/DataExport/Cohort/CommittingNewCohortsTests.cs +++ b/Rdmp.Core.Tests/DataExport/Cohort/CommittingNewCohortsTests.cs @@ -55,9 +55,8 @@ public void CommittingNewCohortFile_IDPopulated_Throws() new CohortDefinition(511, "CommittingNewCohorts", 1, 999, _externalCohortTable), DataExportRepository, "fish"); var ex = Assert.Throws(() => request.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual( - "Expected the cohort definition CommittingNewCohorts(Version 1, ID=511) to have a null ID - we are trying to create this, why would it already exist?", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Expected the cohort definition CommittingNewCohorts(Version 1, ID=511) to have a null ID - we are trying to create this, why would it already exist?")); } [Test] @@ -69,9 +68,8 @@ public void CommittingNewCohortFile_ProjectNumberNumberMissing() new CohortDefinition(null, "CommittingNewCohorts", 1, 999, _externalCohortTable), DataExportRepository, "fish"); var ex = Assert.Throws(() => request.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual( - "Project MyProj does not have a ProjectNumber specified, it should have the same number as the CohortCreationRequest (999)", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Project MyProj does not have a ProjectNumber specified, it should have the same number as the CohortCreationRequest (999)")); } [Test] @@ -84,8 +82,7 @@ public void CommittingNewCohortFile_ProjectNumberMismatch() new CohortDefinition(null, "CommittingNewCohorts", 1, 999, _externalCohortTable), DataExportRepository, "fish"); var ex = Assert.Throws(() => request.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("Project MyProj has ProjectNumber=321 but the CohortCreationRequest.ProjectNumber is 999", - ex.Message); + Assert.That(ex.Message, Is.EqualTo("Project MyProj has ProjectNumber=321 but the CohortCreationRequest.ProjectNumber is 999")); } [Test] @@ -116,13 +113,13 @@ public void CommittingNewCohortFile_CallPipeline() pipeline.ExecutePipeline(new GracefulCancellationToken()); //there should be a new ExtractableCohort now - Assert.NotNull(request.NewCohortDefinition.ID); + Assert.That(request.NewCohortDefinition.ID, Is.Not.Null); var ec = DataExportRepository.GetAllObjects() .Single(c => c.OriginID == request.NewCohortDefinition.ID); //with the data in it from the test file - Assert.AreEqual(ec.Count, 3); + Assert.That(ec.Count, Is.EqualTo(3)); } [TestCase(true)] @@ -150,8 +147,8 @@ public void DeprecateOldCohort(bool deprecate) // the definition was imported and should now be a saved ExtractableCohort var cohort998 = request1.CohortCreatedIfAny; - Assert.IsNotNull(cohort998); - Assert.IsFalse(cohort998.IsDeprecated); + Assert.That(cohort998, Is.Not.Null); + Assert.That(cohort998.IsDeprecated, Is.False); // define that the new definition attempts to replace the old one definition999.CohortReplacedIfAny = cohort998; @@ -163,7 +160,7 @@ public void DeprecateOldCohort(bool deprecate) // after committing the new cohort the old one should be deprecated? cohort998.RevertToDatabaseState(); - Assert.AreEqual(deprecate, cohort998.IsDeprecated); + Assert.That(cohort998.IsDeprecated, Is.EqualTo(deprecate)); } @@ -192,8 +189,8 @@ public void MigrateUsages(bool migrate) // the definition was imported and should now be a saved ExtractableCohort var cohort998 = request1.CohortCreatedIfAny; - Assert.IsNotNull(cohort998); - Assert.IsFalse(cohort998.IsDeprecated); + Assert.That(cohort998, Is.Not.Null); + Assert.That(cohort998.IsDeprecated, Is.False); // legit user 1 var ec1 = new ExtractionConfiguration(DataExportRepository, proj) @@ -232,7 +229,7 @@ public void MigrateUsages(bool migrate) // the definition was imported and should now be a saved ExtractableCohort var cohort999 = request2.CohortCreatedIfAny; - Assert.IsNotNull(cohort999); + Assert.That(cohort999, Is.Not.Null); // after committing the new cohort who should be migrated? ec1.RevertToDatabaseState(); @@ -241,13 +238,16 @@ public void MigrateUsages(bool migrate) ec4.RevertToDatabaseState(); // should have been updated to use the new cohort - Assert.AreEqual(ec1.Cohort_ID, migrate ? cohort999.ID : cohort998.ID); - Assert.AreEqual(ec2.Cohort_ID, migrate ? cohort999.ID : cohort998.ID); + Assert.That(migrate ? cohort999.ID : cohort998.ID, Is.EqualTo(ec1.Cohort_ID)); + Assert.Multiple(() => + { + Assert.That(migrate ? cohort999.ID : cohort998.ID, Is.EqualTo(ec2.Cohort_ID)); - // should not have magically gotten a cohort - Assert.IsNull(ec3.Cohort_ID); + // should not have magically gotten a cohort + Assert.That(ec3.Cohort_ID, Is.Null); - // is frozen so should not have been changed to the new cohort (and therefore still use cohort998) - Assert.AreEqual(ec4.Cohort_ID, cohort998.ID); + // is frozen so should not have been changed to the new cohort (and therefore still use cohort998) + Assert.That(cohort998.ID, Is.EqualTo(ec4.Cohort_ID)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/Cohort/ProjectConsistentGuidReleaseIdentifierAllocatorTests.cs b/Rdmp.Core.Tests/DataExport/Cohort/ProjectConsistentGuidReleaseIdentifierAllocatorTests.cs index 7b6f2c1f39..802f9d62a9 100644 --- a/Rdmp.Core.Tests/DataExport/Cohort/ProjectConsistentGuidReleaseIdentifierAllocatorTests.cs +++ b/Rdmp.Core.Tests/DataExport/Cohort/ProjectConsistentGuidReleaseIdentifierAllocatorTests.cs @@ -48,9 +48,12 @@ public void TestPreserveHistoricalReleaseIdentifiers(DatabaseType databaseType) var allocator = new ProjectConsistentGuidReleaseIdentifierAllocator(); allocator.Initialize(req); - //allocator is being asked to allocate when there are no cohorts at all defined - Assert.AreEqual(0, defTable.GetRowCount()); - Assert.IsNotNull(allocator.AllocateReleaseIdentifier("0101010101")); + Assert.Multiple(() => + { + //allocator is being asked to allocate when there are no cohorts at all defined + Assert.That(defTable.GetRowCount(), Is.EqualTo(0)); + Assert.That(allocator.AllocateReleaseIdentifier("0101010101"), Is.Not.Null); + }); //Now let's define a cohort identifier for someone (0202020202) who is not in our project defTable.Insert(new Dictionary @@ -60,7 +63,7 @@ public void TestPreserveHistoricalReleaseIdentifiers(DatabaseType databaseType) { "description", "flibble" } }); - Assert.AreEqual(1, defTable.GetRowCount()); + Assert.That(defTable.GetRowCount(), Is.EqualTo(1)); cohortTable.Insert(new Dictionary { @@ -73,11 +76,14 @@ public void TestPreserveHistoricalReleaseIdentifiers(DatabaseType databaseType) allocator = new ProjectConsistentGuidReleaseIdentifierAllocator(); allocator.Initialize(req); - //allocator is being asked to allocate when there are cohorts defined including one with our person 02020202 but that person was in a different project - Assert.AreEqual(1, defTable.GetRowCount()); - Assert.AreEqual(1, cohortTable.GetRowCount()); - Assert.IsNotNull(allocator.AllocateReleaseIdentifier("0202020202")); - Assert.AreNotEqual("0x0123", allocator.AllocateReleaseIdentifier("0202020202")); + Assert.Multiple(() => + { + //allocator is being asked to allocate when there are cohorts defined including one with our person 02020202 but that person was in a different project + Assert.That(defTable.GetRowCount(), Is.EqualTo(1)); + Assert.That(cohortTable.GetRowCount(), Is.EqualTo(1)); + Assert.That(allocator.AllocateReleaseIdentifier("0202020202"), Is.Not.Null); + }); + Assert.That(allocator.AllocateReleaseIdentifier("0202020202"), Is.Not.EqualTo("0x0123")); //Now let's define a cohort identifier for someone (0202020202) who IS in our project @@ -88,7 +94,7 @@ public void TestPreserveHistoricalReleaseIdentifiers(DatabaseType databaseType) { "description", "flibble" } }); - Assert.AreEqual(2, defTable.GetRowCount()); + Assert.That(defTable.GetRowCount(), Is.EqualTo(2)); cohortTable.Insert(new Dictionary { @@ -101,11 +107,14 @@ public void TestPreserveHistoricalReleaseIdentifiers(DatabaseType databaseType) allocator = new ProjectConsistentGuidReleaseIdentifierAllocator(); allocator.Initialize(req); - //allocator is being asked to allocate when the person 0202020202 has previously appeared under our project (10) - Assert.AreEqual(2, defTable.GetRowCount()); - Assert.AreEqual(2, cohortTable.GetRowCount()); - Assert.IsNotNull(allocator.AllocateReleaseIdentifier("0202020202")); - Assert.AreEqual("0x0127", allocator.AllocateReleaseIdentifier("0202020202")); + Assert.Multiple(() => + { + //allocator is being asked to allocate when the person 0202020202 has previously appeared under our project (10) + Assert.That(defTable.GetRowCount(), Is.EqualTo(2)); + Assert.That(cohortTable.GetRowCount(), Is.EqualTo(2)); + Assert.That(allocator.AllocateReleaseIdentifier("0202020202"), Is.Not.Null); + }); + Assert.That(allocator.AllocateReleaseIdentifier("0202020202"), Is.EqualTo("0x0127")); //finally let's break it by giving it conflicting historical records @@ -117,7 +126,7 @@ public void TestPreserveHistoricalReleaseIdentifiers(DatabaseType databaseType) { "description", "flibble" } }); - Assert.AreEqual(3, defTable.GetRowCount()); + Assert.That(defTable.GetRowCount(), Is.EqualTo(3)); cohortTable.Insert(new Dictionary { @@ -130,15 +139,18 @@ public void TestPreserveHistoricalReleaseIdentifiers(DatabaseType databaseType) allocator = new ProjectConsistentGuidReleaseIdentifierAllocator(); allocator.Initialize(req); - //allocator is being asked to allocate when the person 0202020202 has previously appeared under our project (10) as release identifiers 0x0127 and 0x0128 - Assert.AreEqual(3, defTable.GetRowCount()); - Assert.AreEqual(3, cohortTable.GetRowCount()); + Assert.Multiple(() => + { + //allocator is being asked to allocate when the person 0202020202 has previously appeared under our project (10) as release identifiers 0x0127 and 0x0128 + Assert.That(defTable.GetRowCount(), Is.EqualTo(3)); + Assert.That(cohortTable.GetRowCount(), Is.EqualTo(3)); + }); var ex = Assert.Throws(() => allocator.AllocateReleaseIdentifier("0202020202")); //should be complaining about both of these conflicting release identifiers existing - StringAssert.Contains("0x0127", ex.Message); - StringAssert.Contains("0x0128", ex.Message); + Assert.That(ex.Message, Does.Contain("0x0127")); + Assert.That(ex.Message, Does.Contain("0x0128")); //fix the problem using (var con = db.Server.GetConnection()) @@ -148,10 +160,13 @@ public void TestPreserveHistoricalReleaseIdentifiers(DatabaseType databaseType) .ExecuteScalar(); } - //should be happy now again - Assert.AreEqual(3, defTable.GetRowCount()); - Assert.AreEqual(3, cohortTable.GetRowCount()); - Assert.IsNotNull(allocator.AllocateReleaseIdentifier("0202020202")); - Assert.AreEqual("0x0127", allocator.AllocateReleaseIdentifier("0202020202")); + Assert.Multiple(() => + { + //should be happy now again + Assert.That(defTable.GetRowCount(), Is.EqualTo(3)); + Assert.That(cohortTable.GetRowCount(), Is.EqualTo(3)); + Assert.That(allocator.AllocateReleaseIdentifier("0202020202"), Is.Not.Null); + }); + Assert.That(allocator.AllocateReleaseIdentifier("0202020202"), Is.EqualTo("0x0127")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/ConfigurationPropertiesTests.cs b/Rdmp.Core.Tests/DataExport/ConfigurationPropertiesTests.cs index b22e9e50e9..fd90bec80c 100644 --- a/Rdmp.Core.Tests/DataExport/ConfigurationPropertiesTests.cs +++ b/Rdmp.Core.Tests/DataExport/ConfigurationPropertiesTests.cs @@ -16,12 +16,11 @@ public class ConfigurationPropertiesTests : DatabaseTests public void CreateNewArgumentAndGetValue() { DataExportRepository.DataExportPropertyManager.SetValue(DataExportProperty.HashingAlgorithmPattern, "hi"); - Assert.AreEqual( - DataExportRepository.DataExportPropertyManager.GetValue(DataExportProperty.HashingAlgorithmPattern), "hi"); + Assert.That( +DataExportRepository.DataExportPropertyManager.GetValue(DataExportProperty.HashingAlgorithmPattern), Is.EqualTo("hi")); //make sure delete DataExportRepository.DataExportPropertyManager.SetValue(DataExportProperty.HashingAlgorithmPattern, null); - Assert.AreEqual( - DataExportRepository.DataExportPropertyManager.GetValue(DataExportProperty.HashingAlgorithmPattern), null); + Assert.That(DataExportRepository.DataExportPropertyManager.GetValue(DataExportProperty.HashingAlgorithmPattern), Is.Null); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/CustomData/CustomDataImportingTests.cs b/Rdmp.Core.Tests/DataExport/CustomData/CustomDataImportingTests.cs index c1d2a97cae..c0a31b4e1a 100644 --- a/Rdmp.Core.Tests/DataExport/CustomData/CustomDataImportingTests.cs +++ b/Rdmp.Core.Tests/DataExport/CustomData/CustomDataImportingTests.cs @@ -11,8 +11,6 @@ using Rdmp.Core.Curation.Data; using Rdmp.Core.DataExport.Data; using Rdmp.Core.DataExport.DataExtraction.Commands; -using Rdmp.Core.DataExport.DataExtraction.Pipeline; -using Rdmp.Core.DataExport.DataExtraction.Pipeline.Destinations; using Rdmp.Core.DataExport.DataExtraction.UserPicks; using Tests.Common.Scenarios; @@ -41,13 +39,16 @@ public void Extract_ProjectSpecificCatalogue_WholeDataset() var customDataCsv = results.DirectoryPopulated.GetFiles().Single(f => f.Name.Equals("custTable99.csv")); - Assert.IsNotNull(customDataCsv); + Assert.That(customDataCsv, Is.Not.Null); var lines = File.ReadAllLines(customDataCsv.FullName); - Assert.AreEqual("SuperSecretThing,ReleaseID", lines[0]); - Assert.AreEqual("monkeys can all secretly fly,Pub_54321", lines[1]); - Assert.AreEqual("the wizard of OZ was a man behind a machine,Pub_11ftw", lines[2]); + Assert.Multiple(() => + { + Assert.That(lines[0], Is.EqualTo("SuperSecretThing,ReleaseID")); + Assert.That(lines[1], Is.EqualTo("monkeys can all secretly fly,Pub_54321")); + Assert.That(lines[2], Is.EqualTo("the wizard of OZ was a man behind a machine,Pub_11ftw")); + }); } finally { @@ -108,18 +109,21 @@ public void Extract_ProjectSpecificCatalogue_AppendedColumn() var mainDataTableCsv = results.DirectoryPopulated.GetFiles().Single(f => f.Name.Equals("TestTable.csv")); - Assert.IsNotNull(mainDataTableCsv); - Assert.AreEqual("TestTable.csv", mainDataTableCsv.Name); + Assert.That(mainDataTableCsv, Is.Not.Null); + Assert.That(mainDataTableCsv.Name, Is.EqualTo("TestTable.csv")); var lines = File.ReadAllLines(mainDataTableCsv.FullName); - Assert.AreEqual("ReleaseID,Name,DateOfBirth,SuperSecretThing", lines[0]); + Assert.That(lines[0], Is.EqualTo("ReleaseID,Name,DateOfBirth,SuperSecretThing")); var bobLine = lines.Single(l => l.StartsWith("Pub_54321,Bob")); var frankLine = lines.Single(l => l.StartsWith("Pub_11ftw,Frank")); - Assert.AreEqual("Pub_54321,Bob,2001-01-01,monkeys can all secretly fly", bobLine); - Assert.AreEqual("Pub_11ftw,Frank,2001-10-29,the wizard of OZ was a man behind a machine", frankLine); + Assert.Multiple(() => + { + Assert.That(bobLine, Is.EqualTo("Pub_54321,Bob,2001-01-01,monkeys can all secretly fly")); + Assert.That(frankLine, Is.EqualTo("Pub_11ftw,Frank,2001-10-29,the wizard of OZ was a man behind a machine")); + }); asExtractable.DeleteInDatabase(); } @@ -184,13 +188,16 @@ public void Extract_ProjectSpecificCatalogue_FilterReference() var mainDataTableCsv = results.DirectoryPopulated.GetFiles().Single(f => f.Name.Equals("TestTable.csv")); - Assert.IsNotNull(mainDataTableCsv); + Assert.That(mainDataTableCsv, Is.Not.Null); var lines = File.ReadAllLines(mainDataTableCsv.FullName); - Assert.AreEqual("ReleaseID,Name,DateOfBirth", lines[0]); - Assert.AreEqual("Pub_54321,Bob,2001-01-01", lines[1]); - Assert.AreEqual(2, lines.Length); + Assert.Multiple(() => + { + Assert.That(lines[0], Is.EqualTo("ReleaseID,Name,DateOfBirth")); + Assert.That(lines[1], Is.EqualTo("Pub_54321,Bob,2001-01-01")); + Assert.That(lines, Has.Length.EqualTo(2)); + }); } diff --git a/Rdmp.Core.Tests/DataExport/Data/ExternalCohortTableTests.cs b/Rdmp.Core.Tests/DataExport/Data/ExternalCohortTableTests.cs index 28aa290c88..79df0c6f3e 100644 --- a/Rdmp.Core.Tests/DataExport/Data/ExternalCohortTableTests.cs +++ b/Rdmp.Core.Tests/DataExport/Data/ExternalCohortTableTests.cs @@ -38,7 +38,7 @@ public void Create_ExternalCohortTable_Manually() table.SaveToDatabase(); var ex = Assert.Throws(() => table.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("Could not connect to Cohort database called 'My Cohort Database'", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Could not connect to Cohort database called 'My Cohort Database'")); } /// @@ -49,9 +49,12 @@ public void Create_ExternalCohortTable_InTests() { var tbl = WhenIHaveA(); - Assert.IsNotNull(tbl); - Assert.IsNotNull(tbl.PrivateIdentifierField); - Assert.IsNotNull(tbl.ReleaseIdentifierField); + Assert.That(tbl, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(tbl.PrivateIdentifierField, Is.Not.Null); + Assert.That(tbl.ReleaseIdentifierField, Is.Not.Null); + }); } [Test] @@ -60,12 +63,15 @@ public void TestExternalCohortTableProperties_BasicValues() var table = new ExternalCohortTable(RepositoryLocator.DataExportRepository, "ffff", DatabaseType.MicrosoftSQLServer); - Assert.IsNull(table.Database); - Assert.IsNull(table.Server); - Assert.IsNull(table.TableName); - Assert.IsNull(table.PrivateIdentifierField); - Assert.IsNull(table.ReleaseIdentifierField); - Assert.IsNull(table.DefinitionTableForeignKeyField); + Assert.Multiple(() => + { + Assert.That(table.Database, Is.Null); + Assert.That(table.Server, Is.Null); + Assert.That(table.TableName, Is.Null); + Assert.That(table.PrivateIdentifierField, Is.Null); + Assert.That(table.ReleaseIdentifierField, Is.Null); + Assert.That(table.DefinitionTableForeignKeyField, Is.Null); + }); table.Database = "mydb"; table.Server = "myserver"; @@ -74,14 +80,17 @@ public void TestExternalCohortTableProperties_BasicValues() table.ReleaseIdentifierField = "rel"; table.DefinitionTableForeignKeyField = "fk"; - Assert.AreEqual("mydb", table.Database); - Assert.AreEqual("myserver", table.Server); - Assert.AreEqual("[mydb]..[mytbl]", table.TableName); - Assert.IsNull(table.DefinitionTableName); - - Assert.AreEqual("[mydb]..[mytbl].[priv]", table.PrivateIdentifierField); - Assert.AreEqual("[mydb]..[mytbl].[rel]", table.ReleaseIdentifierField); - Assert.AreEqual("[mydb]..[mytbl].[fk]", table.DefinitionTableForeignKeyField); + Assert.Multiple(() => + { + Assert.That(table.Database, Is.EqualTo("mydb")); + Assert.That(table.Server, Is.EqualTo("myserver")); + Assert.That(table.TableName, Is.EqualTo("[mydb]..[mytbl]")); + Assert.That(table.DefinitionTableName, Is.Null); + + Assert.That(table.PrivateIdentifierField, Is.EqualTo("[mydb]..[mytbl].[priv]")); + Assert.That(table.ReleaseIdentifierField, Is.EqualTo("[mydb]..[mytbl].[rel]")); + Assert.That(table.DefinitionTableForeignKeyField, Is.EqualTo("[mydb]..[mytbl].[fk]")); + }); } [Test] @@ -90,12 +99,15 @@ public void TestExternalCohortTableProperties_SetFullValues() var table = new ExternalCohortTable(RepositoryLocator.DataExportRepository, "ffff", DatabaseType.MicrosoftSQLServer); - Assert.IsNull(table.Database); - Assert.IsNull(table.Server); - Assert.IsNull(table.TableName); - Assert.IsNull(table.PrivateIdentifierField); - Assert.IsNull(table.ReleaseIdentifierField); - Assert.IsNull(table.DefinitionTableForeignKeyField); + Assert.Multiple(() => + { + Assert.That(table.Database, Is.Null); + Assert.That(table.Server, Is.Null); + Assert.That(table.TableName, Is.Null); + Assert.That(table.PrivateIdentifierField, Is.Null); + Assert.That(table.ReleaseIdentifierField, Is.Null); + Assert.That(table.DefinitionTableForeignKeyField, Is.Null); + }); table.PrivateIdentifierField = "[mydb]..[mytbl].[priv]"; table.ReleaseIdentifierField = "[mydb]..[mytbl].[rel]"; @@ -104,13 +116,16 @@ public void TestExternalCohortTableProperties_SetFullValues() table.Server = "myserver"; table.TableName = "[mydb]..[mytbl]"; - Assert.AreEqual("mydb", table.Database); - Assert.AreEqual("myserver", table.Server); - Assert.AreEqual("[mydb]..[mytbl]", table.TableName); - Assert.IsNull(table.DefinitionTableName); - - Assert.AreEqual("[mydb]..[mytbl].[priv]", table.PrivateIdentifierField); - Assert.AreEqual("[mydb]..[mytbl].[rel]", table.ReleaseIdentifierField); - Assert.AreEqual("[mydb]..[mytbl].[fk]", table.DefinitionTableForeignKeyField); + Assert.Multiple(() => + { + Assert.That(table.Database, Is.EqualTo("mydb")); + Assert.That(table.Server, Is.EqualTo("myserver")); + Assert.That(table.TableName, Is.EqualTo("[mydb]..[mytbl]")); + Assert.That(table.DefinitionTableName, Is.Null); + + Assert.That(table.PrivateIdentifierField, Is.EqualTo("[mydb]..[mytbl].[priv]")); + Assert.That(table.ReleaseIdentifierField, Is.EqualTo("[mydb]..[mytbl].[rel]")); + Assert.That(table.DefinitionTableForeignKeyField, Is.EqualTo("[mydb]..[mytbl].[fk]")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/Data/ExtractableCohortAuditLogBuilderTests.cs b/Rdmp.Core.Tests/DataExport/Data/ExtractableCohortAuditLogBuilderTests.cs index daa8f64c25..7eb755cb3c 100644 --- a/Rdmp.Core.Tests/DataExport/Data/ExtractableCohortAuditLogBuilderTests.cs +++ b/Rdmp.Core.Tests/DataExport/Data/ExtractableCohortAuditLogBuilderTests.cs @@ -27,10 +27,13 @@ public void AuditLogReFetch_FileInfo() moqCohort.AuditLog.Returns(desc); var fi2 = ExtractableCohortAuditLogBuilder.GetObjectIfAny(moqCohort, RepositoryLocator); - Assert.IsNotNull(fi2); - Assert.IsInstanceOf(fi2); - Assert.AreEqual(fi.FullName, ((FileInfo)fi2).FullName); - } + Assert.That(fi2, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(fi2, Is.InstanceOf()); + Assert.That(((FileInfo)fi2).FullName, Is.EqualTo(fi.FullName)); + }); + } [Test] @@ -43,9 +46,9 @@ public void AuditLogReFetch_CohortIdentificationConfiguration() var moqCohort = Substitute.For(); moqCohort.AuditLog.Returns(desc); var cic2 = ExtractableCohortAuditLogBuilder.GetObjectIfAny(moqCohort, RepositoryLocator); - Assert.IsNotNull(cic2); - Assert.IsInstanceOf(cic2); - Assert.AreEqual(cic, cic2); + Assert.That(cic2, Is.Not.Null); + Assert.That(cic2, Is.InstanceOf()); + Assert.That(cic2, Is.EqualTo(cic)); } [Test] @@ -58,9 +61,9 @@ public void AuditLogReFetch_ExtractionInformation() var moqCohort = Substitute.For(); moqCohort.AuditLog.Returns(desc); var ei2 = ExtractableCohortAuditLogBuilder.GetObjectIfAny(moqCohort, RepositoryLocator); - Assert.IsNotNull(ei2); - Assert.IsInstanceOf(ei2); - Assert.AreEqual(ei, ei2); + Assert.That(ei2, Is.Not.Null); + Assert.That(ei2, Is.InstanceOf()); + Assert.That(ei2, Is.EqualTo(ei)); } [Test] @@ -68,7 +71,7 @@ public void AuditLogReFetch_WhenAuditLogIsNull() { var moqCohort = Substitute.For(); moqCohort.AuditLog.Returns(x => null); - Assert.IsNull(ExtractableCohortAuditLogBuilder.GetObjectIfAny(moqCohort, RepositoryLocator)); + Assert.That(ExtractableCohortAuditLogBuilder.GetObjectIfAny(moqCohort, RepositoryLocator), Is.Null); } [Test] @@ -76,7 +79,7 @@ public void AuditLogReFetch_WhenAuditLogIsRubbish() { var moqCohort = Substitute.For(); moqCohort.AuditLog.Returns("troll doll dur I invented this cohort myself"); - Assert.IsNull(ExtractableCohortAuditLogBuilder.GetObjectIfAny(moqCohort, RepositoryLocator)); + Assert.That(ExtractableCohortAuditLogBuilder.GetObjectIfAny(moqCohort, RepositoryLocator), Is.Null); } [Test] @@ -93,7 +96,7 @@ public void AuditLogReFetch_WhenSourceIsDeleted() // delete the source ei.DeleteInDatabase(); - // should now return null - Assert.IsNull(ExtractableCohortAuditLogBuilder.GetObjectIfAny(moqCohort, RepositoryLocator)); + // should now return null + Assert.That(ExtractableCohortAuditLogBuilder.GetObjectIfAny(moqCohort, RepositoryLocator), Is.Null); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/Data/ExtractableCohortTests.cs b/Rdmp.Core.Tests/DataExport/Data/ExtractableCohortTests.cs index 6839416933..314fd05042 100644 --- a/Rdmp.Core.Tests/DataExport/Data/ExtractableCohortTests.cs +++ b/Rdmp.Core.Tests/DataExport/Data/ExtractableCohortTests.cs @@ -19,8 +19,8 @@ public void TestExtractableCohort_Identifiable() { var cohort = _extractableCohort; - Assert.IsNotNull(cohort.GetPrivateIdentifier()); - Assert.AreNotEqual(cohort.GetReleaseIdentifier(), cohort.GetPrivateIdentifier()); + Assert.That(cohort.GetPrivateIdentifier(), Is.Not.Null); + Assert.That(cohort.GetPrivateIdentifier(), Is.Not.EqualTo(cohort.GetReleaseIdentifier())); var ect = cohort.ExternalCohortTable; ect.ReleaseIdentifierField = ect.PrivateIdentifierField; @@ -30,13 +30,12 @@ public void TestExtractableCohort_Identifiable() var ex = Assert.Throws(() => cohort.GetReleaseIdentifier()); - Assert.AreEqual( - "R004 PrivateIdentifierField and ReleaseIdentifierField are the same, this means your cohort will extract identifiable data (no cohort identifier substitution takes place)", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("R004 PrivateIdentifierField and ReleaseIdentifierField are the same, this means your cohort will extract identifiable data (no cohort identifier substitution takes place)")); UserSettings.SetErrorReportingLevelFor(ErrorCodes.ExtractionIsIdentifiable, CheckResult.Warning); - Assert.AreEqual(cohort.GetReleaseIdentifier(), cohort.GetPrivateIdentifier()); + Assert.That(cohort.GetPrivateIdentifier(), Is.EqualTo(cohort.GetReleaseIdentifier())); UserSettings.SetErrorReportingLevelFor(ErrorCodes.ExtractionIsIdentifiable, CheckResult.Fail); } diff --git a/Rdmp.Core.Tests/DataExport/Data/ExtractionProgressTests.cs b/Rdmp.Core.Tests/DataExport/Data/ExtractionProgressTests.cs index e97af90839..711f706de6 100644 --- a/Rdmp.Core.Tests/DataExport/Data/ExtractionProgressTests.cs +++ b/Rdmp.Core.Tests/DataExport/Data/ExtractionProgressTests.cs @@ -26,9 +26,8 @@ public void ExtractionProgressConstructor_NoTimePeriodicity() var sds = new SelectedDataSets(DataExportRepository, config, eds, null); var ex = Assert.Throws(() => new ExtractionProgress(DataExportRepository, sds)); - Assert.AreEqual( - "Cannot create ExtractionProgress because Catalogue MyCata does not have a time coverage column", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Cannot create ExtractionProgress because Catalogue MyCata does not have a time coverage column")); } [Test] @@ -49,7 +48,7 @@ public void ExtractionProgressConstructor_CannotHaveTwoAtOnce() // try to create a second progress for the same dataset being extracted var ex = Assert.Throws(() => new ExtractionProgress(DataExportRepository, sds)); - Assert.AreEqual("There is already an ExtractionProgress associated with MyCata", ex.Message); + Assert.That(ex.Message, Is.EqualTo("There is already an ExtractionProgress associated with MyCata")); // now delete the original and make sure we can recreate it ok progress.DeleteInDatabase(); @@ -64,25 +63,25 @@ public void ExtractionProgressConstructor_DeleteSdsMustCascade() { var progress = CreateAnExtractionProgress(); - Assert.IsTrue(progress.Exists()); + Assert.That(progress.Exists()); progress.SelectedDataSets.DeleteInDatabase(); - Assert.IsFalse(progress.Exists()); + Assert.That(progress.Exists(), Is.False); } [Test] public void ExtractionProgress_RetrySave() { var progress = CreateAnExtractionProgress(); - Assert.AreEqual(progress.Retry, RetryStrategy.NoRetry); + Assert.That(progress.Retry, Is.EqualTo(RetryStrategy.NoRetry)); progress.Retry = RetryStrategy.IterativeBackoff1Hour; progress.SaveToDatabase(); progress.RevertToDatabaseState(); - Assert.AreEqual(progress.Retry, RetryStrategy.IterativeBackoff1Hour); + Assert.That(progress.Retry, Is.EqualTo(RetryStrategy.IterativeBackoff1Hour)); var freshCopy = progress.Repository.GetObjectByID(progress.ID); - Assert.AreEqual(freshCopy.Retry, RetryStrategy.IterativeBackoff1Hour); + Assert.That(freshCopy.Retry, Is.EqualTo(RetryStrategy.IterativeBackoff1Hour)); progress.DeleteInDatabase(); } @@ -108,13 +107,12 @@ public void TestQueryGeneration_FirstBatch() Execute(out _, out var result); - Assert.IsTrue(result.GeneratesFiles); + Assert.That(result.GeneratesFiles); var fileContents = File.ReadAllText(result.OutputFile); // Headers should be in file because it is a first batch - Assert.AreEqual( - $"ReleaseID,Name,DateOfBirth{Environment.NewLine}Pub_54321,Dave,2001-01-01{Environment.NewLine}", - fileContents); + Assert.That( + fileContents, Is.EqualTo($"ReleaseID,Name,DateOfBirth{Environment.NewLine}Pub_54321,Dave,2001-01-01{Environment.NewLine}")); File.Delete(result.OutputFile); progress.DeleteInDatabase(); @@ -140,13 +138,19 @@ public void TestCloneResetsProgress() var cloneSds = clone.SelectedDataSets.Single(); var cloneProgress = cloneSds.ExtractionProgressIfAny; + Assert.Multiple(() => + { - // should be different instances - Assert.AreNotSame(origProgress, cloneProgress); + // should be different instances + Assert.That(cloneProgress, Is.Not.SameAs(origProgress)); - Assert.AreEqual(cloneProgress.StartDate, new DateTime(2001, 01, 01)); - Assert.IsNull(cloneProgress.ProgressDate, "Expected progress to be reset on clone"); - Assert.AreEqual(cloneProgress.EndDate, new DateTime(2020, 01, 01)); + Assert.That(new DateTime(2001, 01, 01), Is.EqualTo(cloneProgress.StartDate)); + }); + Assert.Multiple(() => + { + Assert.That(cloneProgress.ProgressDate, Is.Null, "Expected progress to be reset on clone"); + Assert.That(new DateTime(2020, 01, 01), Is.EqualTo(cloneProgress.EndDate)); + }); } private ExtractionProgress CreateAnExtractionProgress() => CreateAnExtractionProgress(out _); diff --git a/Rdmp.Core.Tests/DataExport/Data/SelectedDataSetsCheckerTests.cs b/Rdmp.Core.Tests/DataExport/Data/SelectedDataSetsCheckerTests.cs index 413fe0368e..b40bf0379a 100644 --- a/Rdmp.Core.Tests/DataExport/Data/SelectedDataSetsCheckerTests.cs +++ b/Rdmp.Core.Tests/DataExport/Data/SelectedDataSetsCheckerTests.cs @@ -42,9 +42,8 @@ public void TestExtractionProgress_MidwayWithNoAuditRecord() ep.SaveToDatabase(); var ex = Assert.Throws(() => checker.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual( - "R0016 ExtractionProgress 'mybatch' is 'in progress' (ProgressDate is not null) but there is no audit of previously extracted SQL (needed for checking cohort changes)", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("R0016 ExtractionProgress 'mybatch' is 'in progress' (ProgressDate is not null) but there is no audit of previously extracted SQL (needed for checking cohort changes)")); } [Test] @@ -72,9 +71,8 @@ public void TestExtractionProgress_AuditRecordHasDifferentCohort() audit.SaveToDatabase(); var ex = Assert.Throws(() => checker.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual( - $"R0017 ExtractionProgress 'mybatch' is 'in progress' (ProgressDate is not null) but we did not find the expected Cohort WHERE Sql in the audit of SQL extracted with the last batch. Did you change the cohort without resetting the ProgressDate? The SQL we expected to find was '[{TestDatabaseNames.Prefix}CohortDatabase]..[Cohort].[cohortDefinition_id]=-599'", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo($"R0017 ExtractionProgress 'mybatch' is 'in progress' (ProgressDate is not null) but we did not find the expected Cohort WHERE Sql in the audit of SQL extracted with the last batch. Did you change the cohort without resetting the ProgressDate? The SQL we expected to find was '[{TestDatabaseNames.Prefix}CohortDatabase]..[Cohort].[cohortDefinition_id]=-599'")); // tidy up ep.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/DataExport/DataAccess/PackageContentsTests.cs b/Rdmp.Core.Tests/DataExport/DataAccess/PackageContentsTests.cs index 0c3cdf0382..4f32a254ea 100644 --- a/Rdmp.Core.Tests/DataExport/DataAccess/PackageContentsTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataAccess/PackageContentsTests.cs @@ -24,7 +24,7 @@ public void AddAndRemove() var package = new ExtractableDataSetPackage(DataExportRepository, "My Cool Package"); try { - Assert.AreEqual("My Cool Package", package.Name); + Assert.That(package.Name, Is.EqualTo("My Cool Package")); package.Name = "FishPackage"; package.SaveToDatabase(); @@ -32,13 +32,13 @@ public void AddAndRemove() var packageContents = DataExportRepository; var results = packageContents.GetAllDataSets(package, null); - Assert.AreEqual(0, results.Length); + Assert.That(results, Is.Empty); packageContents.AddDataSetToPackage(package, ds); results = packageContents.GetAllDataSets(package, DataExportRepository.GetAllObjects()); - Assert.AreEqual(1, results.Length); - Assert.AreEqual(ds, results[0]); + Assert.That(results, Has.Length.EqualTo(1)); + Assert.That(results[0], Is.EqualTo(ds)); packageContents.RemoveDataSetFromPackage(package, ds); diff --git a/Rdmp.Core.Tests/DataExport/DataAccess/SelectedColumnsTests.cs b/Rdmp.Core.Tests/DataExport/DataAccess/SelectedColumnsTests.cs index 2402e4628c..6cad7f8764 100644 --- a/Rdmp.Core.Tests/DataExport/DataAccess/SelectedColumnsTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataAccess/SelectedColumnsTests.cs @@ -37,13 +37,13 @@ public void CreateAndAssociateColumns() var cols = config.GetAllExtractableColumnsFor(ds); - Assert.AreEqual(1, cols.Length); - Assert.AreEqual(extractableColumn, cols.Single()); + Assert.That(cols, Has.Length.EqualTo(1)); + Assert.That(cols.Single(), Is.EqualTo(extractableColumn)); cols = config.GetAllExtractableColumnsFor(ds); - Assert.AreEqual(1, cols.Length); - Assert.AreEqual(extractableColumn, cols.Single()); + Assert.That(cols, Has.Length.EqualTo(1)); + Assert.That(cols.Single(), Is.EqualTo(extractableColumn)); } finally { diff --git a/Rdmp.Core.Tests/DataExport/DataExportRepositoryTests.cs b/Rdmp.Core.Tests/DataExport/DataExportRepositoryTests.cs index b7727ecb7e..549d07c207 100644 --- a/Rdmp.Core.Tests/DataExport/DataExportRepositoryTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataExportRepositoryTests.cs @@ -18,7 +18,7 @@ internal class DataExportRepositoryTests : DatabaseTests public void TestNoIsExtractionIdentifierFinding() { //nothing in database means no dodgy datasets - Assert.IsEmpty(DataExportRepository.GetSelectedDatasetsWithNoExtractionIdentifiers()); + Assert.That(DataExportRepository.GetSelectedDatasetsWithNoExtractionIdentifiers(), Is.Empty); var cata = new Catalogue(CatalogueRepository, "ommn"); var ds = new ExtractableDataSet(DataExportRepository, cata); @@ -28,8 +28,8 @@ public void TestNoIsExtractionIdentifierFinding() //only one selected dataset var dodgy = DataExportRepository.GetSelectedDatasetsWithNoExtractionIdentifiers().ToArray(); - Assert.AreEqual(1, dodgy.Length); - Assert.AreEqual(sds, dodgy[0]); + Assert.That(dodgy, Has.Length.EqualTo(1)); + Assert.That(dodgy[0], Is.EqualTo(sds)); //make an extarctable column on that dataset var col = new ColumnInfo(CatalogueRepository, "ff", "varchar(1)", new TableInfo(CatalogueRepository, "fff")); @@ -39,8 +39,8 @@ public void TestNoIsExtractionIdentifierFinding() //still shouldn't be dodgy dodgy = DataExportRepository.GetSelectedDatasetsWithNoExtractionIdentifiers().ToArray(); - Assert.AreEqual(1, dodgy.Length); - Assert.AreEqual(sds, dodgy[0]); + Assert.That(dodgy, Has.Length.EqualTo(1)); + Assert.That(dodgy[0], Is.EqualTo(sds)); //now make it non dodgy by being IsExtractionIdentifier ec.IsExtractionIdentifier = true; @@ -48,6 +48,6 @@ public void TestNoIsExtractionIdentifierFinding() //no longer dodgy because there is an extraction identifier dodgy = DataExportRepository.GetSelectedDatasetsWithNoExtractionIdentifiers().ToArray(); - Assert.AreEqual(0, dodgy.Length); + Assert.That(dodgy, Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/EmptyDataExtractionTests.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/EmptyDataExtractionTests.cs index 15c25627da..9413d161e6 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/EmptyDataExtractionTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/EmptyDataExtractionTests.cs @@ -53,17 +53,20 @@ public void TestAllowingEmptyDatasets(bool allowEmptyDatasetExtractions) if (allowEmptyDatasetExtractions) { var dt = host.Source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, token); - Assert.IsNull(host.Source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, token)); + Assert.Multiple(() => + { + Assert.That(host.Source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, token), Is.Null); - Assert.AreEqual(0, dt.Rows.Count); - Assert.AreEqual(3, dt.Columns.Count); + Assert.That(dt.Rows, Is.Empty); + Assert.That(dt.Columns, Has.Count.EqualTo(3)); + }); } else { var exception = Assert.Throws(() => host.Source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, token)); - Assert.IsTrue(exception.Message.StartsWith("There is no data to load, query returned no rows, query was")); + Assert.That(exception.Message, Does.StartWith("There is no data to load, query returned no rows, query was")); } p.DeleteInDatabase(); @@ -75,16 +78,19 @@ public void ProducesEmptyCSV() TruncateDataTable(); AllowEmptyExtractions = true; - Assert.AreEqual(1, _request.ColumnsToExtract.Count(c => c.IsExtractionIdentifier)); + Assert.That(_request.ColumnsToExtract.Count(c => c.IsExtractionIdentifier), Is.EqualTo(1)); Execute(out _, out var result); var r = (ExecuteDatasetExtractionFlatFileDestination)result; - //this should be what is in the file, the private identifier and the 1 that was put into the table in the first place (see parent class for the test data setup) - Assert.AreEqual(@"ReleaseID,Name,DateOfBirth", File.ReadAllText(r.OutputFile).Trim()); + Assert.Multiple(() => + { + //this should be what is in the file, the private identifier and the 1 that was put into the table in the first place (see parent class for the test data setup) + Assert.That(File.ReadAllText(r.OutputFile).Trim(), Is.EqualTo(@"ReleaseID,Name,DateOfBirth")); - Assert.AreEqual(1, _request.QueryBuilder.SelectColumns.Count(c => c.IColumn is ReleaseIdentifierSubstitution)); + Assert.That(_request.QueryBuilder.SelectColumns.Count(c => c.IColumn is ReleaseIdentifierSubstitution), Is.EqualTo(1)); + }); File.Delete(r.OutputFile); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteCrossServerDatasetExtractionSourceTest.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteCrossServerDatasetExtractionSourceTest.cs index 797511071c..845b472ef9 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteCrossServerDatasetExtractionSourceTest.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteCrossServerDatasetExtractionSourceTest.cs @@ -10,7 +10,6 @@ using NUnit.Framework; using Rdmp.Core.Curation.Data.Pipelines; using Rdmp.Core.DataExport.Data; -using Rdmp.Core.DataExport.DataExtraction.Pipeline; using Rdmp.Core.DataExport.DataExtraction.Pipeline.Destinations; using Rdmp.Core.DataExport.DataExtraction.Pipeline.Sources; using Rdmp.Core.ReusableLibraryCode.Progress; @@ -29,8 +28,8 @@ public void CrossServerExtraction() var r = (ExecuteDatasetExtractionFlatFileDestination)result; //this should be what is in the file, the private identifier and the 1 that was put into the table in the first place (see parent class for the test data setup) - Assert.AreEqual($@"ReleaseID,Name,DateOfBirth -{_cohortKeysGenerated[_cohortKeysGenerated.Keys.First()]},Dave,2001-01-01", File.ReadAllText(r.OutputFile).Trim()); + Assert.That(File.ReadAllText(r.OutputFile).Trim(), Is.EqualTo($@"ReleaseID,Name,DateOfBirth +{_cohortKeysGenerated[_cohortKeysGenerated.Keys.First()]},Dave,2001-01-01")); File.Delete(r.OutputFile); } @@ -122,7 +121,7 @@ SELECT DISTINCT var hacked = s.HackExtractionSQL(_request.QueryBuilder.SQL, ThrowImmediatelyDataLoadEventListener.QuietPicky); - Assert.AreEqual(expectedOutput.Trim(), hacked.Trim()); + Assert.That(hacked.Trim(), Is.EqualTo(expectedOutput.Trim())); } finally { diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteDatasetExtractionFlatFileDestinationTests.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteDatasetExtractionFlatFileDestinationTests.cs index 62bff5ca5c..98ec316b49 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteDatasetExtractionFlatFileDestinationTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteDatasetExtractionFlatFileDestinationTests.cs @@ -12,6 +12,7 @@ using System; using System.Data; using System.IO; +using NUnit.Framework.Legacy; using Rdmp.Core.ReusableLibraryCode.Progress; using Tests.Common.Scenarios; @@ -46,13 +47,13 @@ public void ExtractionDestination_FloatRounding(bool lotsOfDecimalPlaces) dest.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); dest.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, null); - Assert.IsNotNull(dest.OutputFile); + Assert.That(dest.OutputFile, Is.Not.Null); FileAssert.Exists(dest.OutputFile); - Assert.AreEqual( - lotsOfDecimalPlaces + Assert.That( +File.ReadAllText(dest.OutputFile), Is.EqualTo(lotsOfDecimalPlaces ? $"Floats{Environment.NewLine}3.1415926536{Environment.NewLine}" - : $"Floats{Environment.NewLine}3.14{Environment.NewLine}", File.ReadAllText(dest.OutputFile)); + : $"Floats{Environment.NewLine}3.14{Environment.NewLine}")); dt.Dispose(); } diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteFullExtractionToDatabaseMSSqlChecksTests.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteFullExtractionToDatabaseMSSqlChecksTests.cs index 70f3674baa..f0537382bb 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteFullExtractionToDatabaseMSSqlChecksTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteFullExtractionToDatabaseMSSqlChecksTests.cs @@ -49,8 +49,11 @@ public void NoServer() var tomemory = new ToMemoryCheckNotifier(); destination.Check(tomemory); - Assert.AreEqual(CheckResult.Fail, tomemory.Messages[0].Result); - Assert.IsTrue(tomemory.Messages[0].Message.StartsWith("Target database server property has not been set")); + Assert.Multiple(() => + { + Assert.That(tomemory.Messages[0].Result, Is.EqualTo(CheckResult.Fail)); + Assert.That(tomemory.Messages[0].Message, Does.StartWith("Target database server property has not been set")); + }); } [Test] @@ -67,9 +70,12 @@ public void ServerMissingServerName() var tomemory = new ToMemoryCheckNotifier(); destination.Check(tomemory); - Assert.AreEqual(CheckResult.Fail, tomemory.Messages[0].Result); - Assert.IsTrue(tomemory.Messages[0].Message - .StartsWith("TargetDatabaseServer does not have a .Server specified")); + Assert.Multiple(() => + { + Assert.That(tomemory.Messages[0].Result, Is.EqualTo(CheckResult.Fail)); + Assert.That(tomemory.Messages[0].Message + , Does.StartWith("TargetDatabaseServer does not have a .Server specified")); + }); } finally { @@ -107,7 +113,7 @@ public void ServerDatabaseIsPresentAndCorrect(bool alreadyExists) var tomemory = new ToMemoryCheckNotifier(ThrowImmediatelyCheckNotifier.Quiet); destination.Check(tomemory); - Assert.AreEqual(alreadyExists ? CheckResult.Warning : CheckResult.Success, tomemory.GetWorst()); + Assert.That(tomemory.GetWorst(), Is.EqualTo(alreadyExists ? CheckResult.Warning : CheckResult.Success)); } finally { @@ -145,7 +151,7 @@ public void ServerDatabaseIsPresentAndCorrectButHasTablesInIt() var tomemory = new ToMemoryCheckNotifier(ThrowImmediatelyCheckNotifier.Quiet); destination.Check(tomemory); - Assert.AreEqual(CheckResult.Warning, tomemory.GetWorst()); + Assert.That(tomemory.GetWorst(), Is.EqualTo(CheckResult.Warning)); Database.ExpectTable("Bob").Drop(); } diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteFullExtractionToDatabaseMSSqlDestinationTest.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteFullExtractionToDatabaseMSSqlDestinationTest.cs index 87acc4a642..885aa46c65 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteFullExtractionToDatabaseMSSqlDestinationTest.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/ExecuteFullExtractionToDatabaseMSSqlDestinationTest.cs @@ -77,18 +77,20 @@ public void SQLServerDestination() ExecuteRunner(); var destinationTable = dbToExtractTo.ExpectTable(_expectedTableName); - Assert.IsTrue(destinationTable.Exists()); + Assert.That(destinationTable.Exists()); var dt = destinationTable.GetDataTable(); - Assert.AreEqual(1, dt.Rows.Count); - Assert.AreEqual(_cohortKeysGenerated[_cohortKeysGenerated.Keys.First()].Trim(), dt.Rows[0]["ReleaseID"]); - Assert.AreEqual(new DateTime(2001, 1, 1), dt.Rows[0]["DateOfBirth"]); - Assert.AreEqual(2001, dt.Rows[0]["YearOfBirth"]); + Assert.That(dt.Rows, Has.Count.EqualTo(1)); + Assert.Multiple(() => + { + Assert.That(dt.Rows[0]["ReleaseID"], Is.EqualTo(_cohortKeysGenerated[_cohortKeysGenerated.Keys.First()].Trim())); + Assert.That(dt.Rows[0]["DateOfBirth"], Is.EqualTo(new DateTime(2001, 1, 1))); + Assert.That(dt.Rows[0]["YearOfBirth"], Is.EqualTo(2001)); - Assert.AreEqual(_columnToTransform.Data_type, - destinationTable.DiscoverColumn("DateOfBirth").DataType.SQLType); - Assert.AreEqual("int", destinationTable.DiscoverColumn("YearOfBirth").DataType.SQLType); + Assert.That(destinationTable.DiscoverColumn("DateOfBirth").DataType.SQLType, Is.EqualTo(_columnToTransform.Data_type)); + Assert.That(destinationTable.DiscoverColumn("YearOfBirth").DataType.SQLType, Is.EqualTo("int")); + }); AssertLookupsEtcExist(dbToExtractTo); } @@ -103,12 +105,15 @@ public void SQLServerDestination() private static void AssertLookupsEtcExist(DiscoveredDatabase dbToExtractTo) { - Assert.IsTrue(dbToExtractTo.ExpectTable("ExecuteFullExtractionToDatabaseMSSqlDestinationTest_TestTable_Biochem") - .Exists()); - Assert.IsTrue(dbToExtractTo.ExpectTable("ExecuteFullExtractionToDatabaseMSSqlDestinationTest_Globals_Hosp") - .Exists()); - Assert.IsTrue(dbToExtractTo.ExpectTable("ExecuteFullExtractionToDatabaseMSSqlDestinationTest_TestTable_z_fff") - .Exists()); + Assert.Multiple(() => + { + Assert.That(dbToExtractTo.ExpectTable("ExecuteFullExtractionToDatabaseMSSqlDestinationTest_TestTable_Biochem") + .Exists()); + Assert.That(dbToExtractTo.ExpectTable("ExecuteFullExtractionToDatabaseMSSqlDestinationTest_Globals_Hosp") + .Exists()); + Assert.That(dbToExtractTo.ExpectTable("ExecuteFullExtractionToDatabaseMSSqlDestinationTest_TestTable_z_fff") + .Exists()); + }); } private void CreateLookupsEtc() @@ -210,7 +215,7 @@ protected override Pipeline SetupPipeline() var argumentDbNamePattern = destinationArguments.Single(a => a.Name == "DatabaseNamingPattern"); var argumentTblNamePattern = destinationArguments.Single(a => a.Name == "TableNamingPattern"); - Assert.AreEqual("TargetDatabaseServer", argumentServer.Name); + Assert.That(argumentServer.Name, Is.EqualTo("TargetDatabaseServer")); argumentServer.SetValue(_extractionServer); argumentServer.SaveToDatabase(); argumentDbNamePattern.SetValue($"{TestDatabaseNames.Prefix}$p_$n"); diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/ExecutePkSynthesizerDatasetExtractionSourceTests.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/ExecutePkSynthesizerDatasetExtractionSourceTests.cs index 3908df8180..9e79e915b7 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/ExecutePkSynthesizerDatasetExtractionSourceTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/ExecutePkSynthesizerDatasetExtractionSourceTests.cs @@ -48,9 +48,12 @@ public void Test_CatalogueItems_ExtractionInformationPrimaryKey_IsRespected() source.PreInitialize(request, ThrowImmediatelyDataLoadEventListener.Quiet); var chunk = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.That(chunk.PrimaryKey, Is.Not.Null); - Assert.That(chunk.Columns.Cast().ToList(), - Has.Count.EqualTo(_columnInfos.Length)); // NO new column added + Assert.Multiple(() => + { + Assert.That(chunk.PrimaryKey, Is.Not.Null); + Assert.That(chunk.Columns.Cast().ToList(), + Has.Count.EqualTo(_columnInfos.Length)); // NO new column added + }); Assert.That(chunk.PrimaryKey, Has.Length.EqualTo(1)); Assert.That(chunk.PrimaryKey.First().ColumnName, Is.EqualTo("DateOfBirth")); } @@ -65,8 +68,11 @@ public void Test_CatalogueItems_ExtractionInformationMultiPrimaryKey_IsRespected source.PreInitialize(request, ThrowImmediatelyDataLoadEventListener.Quiet); var chunk = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.That(chunk.PrimaryKey, Is.Not.Null); - Assert.That(chunk.Columns.Cast().ToList(), Has.Count.EqualTo(_columnInfos.Length)); + Assert.Multiple(() => + { + Assert.That(chunk.PrimaryKey, Is.Not.Null); + Assert.That(chunk.Columns.Cast().ToList(), Has.Count.EqualTo(_columnInfos.Length)); + }); Assert.That(chunk.PrimaryKey, Has.Length.EqualTo(2)); Assert.That(chunk.PrimaryKey.First().ColumnName, Is.EqualTo("ReleaseID")); } @@ -81,14 +87,17 @@ public void Test_CatalogueItems_NonExtractedPrimaryKey_AreRespected() source.PreInitialize(request, ThrowImmediatelyDataLoadEventListener.Quiet); var chunk = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.That(chunk.PrimaryKey, Is.Not.Null); - Assert.That(chunk.Columns.Cast().ToList(), - Has.Count.EqualTo(_columnInfos.Length + 1)); // synth PK is added + Assert.Multiple(() => + { + Assert.That(chunk.PrimaryKey, Is.Not.Null); + Assert.That(chunk.Columns.Cast().ToList(), + Has.Count.EqualTo(_columnInfos.Length + 1)); // synth PK is added + }); Assert.That(chunk.PrimaryKey, Has.Length.EqualTo(1)); Assert.That(chunk.PrimaryKey.First().ColumnName, Is.EqualTo("SynthesizedPk")); var firstvalue = chunk.Rows[0]["SynthesizedPk"].ToString(); - Assert.IsTrue(reghex.IsMatch(firstvalue)); + Assert.That(reghex.IsMatch(firstvalue)); } [Test] @@ -101,14 +110,17 @@ public void Test_CatalogueItems_NonExtractedPrimaryKey_MultiTable_PksAreMerged() source.PreInitialize(request, ThrowImmediatelyDataLoadEventListener.Quiet); var chunk = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.That(chunk.PrimaryKey, Is.Not.Null); - Assert.That(chunk.Columns.Cast().ToList(), - Has.Count.EqualTo(_columnInfos.Length + 3)); // the "desc" column is added to the existing ones + Assert.Multiple(() => + { + Assert.That(chunk.PrimaryKey, Is.Not.Null); + Assert.That(chunk.Columns.Cast().ToList(), + Has.Count.EqualTo(_columnInfos.Length + 3)); // the "desc" column is added to the existing ones + }); Assert.That(chunk.PrimaryKey, Has.Length.EqualTo(1)); Assert.That(chunk.PrimaryKey.First().ColumnName, Is.EqualTo("SynthesizedPk")); var firstvalue = chunk.Rows[0]["SynthesizedPk"].ToString(); - Assert.IsTrue(reghex.IsMatch(firstvalue)); + Assert.That(reghex.IsMatch(firstvalue)); Database.ExpectTable("SimpleLookup").Drop(); Database.ExpectTable("SimpleJoin").Drop(); @@ -124,15 +136,18 @@ public void Test_CatalogueItems_NonExtractedPrimaryKey_LookupsOnly_IsRespected() source.PreInitialize(request, ThrowImmediatelyDataLoadEventListener.Quiet); var chunk = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.That(chunk.PrimaryKey, Is.Not.Null); - Assert.That(chunk.Columns.Cast().ToList(), - Has.Count.EqualTo(_columnInfos.Length + - 2)); // the "desc" column is added to the existing ones + the SynthPk + Assert.Multiple(() => + { + Assert.That(chunk.PrimaryKey, Is.Not.Null); + Assert.That(chunk.Columns.Cast().ToList(), + Has.Count.EqualTo(_columnInfos.Length + + 2)); // the "desc" column is added to the existing ones + the SynthPk + }); Assert.That(chunk.PrimaryKey, Has.Length.EqualTo(1)); Assert.That(chunk.PrimaryKey.First().ColumnName, Is.EqualTo("SynthesizedPk")); var firstvalue = chunk.Rows[0]["SynthesizedPk"].ToString(); - Assert.IsTrue(reghex.IsMatch(firstvalue)); + Assert.That(reghex.IsMatch(firstvalue)); Database.ExpectTable("SimpleLookup").Drop(); } @@ -207,7 +222,7 @@ private ExtractDatasetCommand SetupExtractDatasetCommand(string testTableName, s dt.Columns.Cast().Where(col => pkColumnInfos.Contains(col.ColumnName)).ToArray(); dt.Rows.Add(new object[] { _cohortKeysGenerated.Keys.First(), "Dave", "2001-01-01" }); - + var tbl = Database.CreateTable(testTableName, dt, new[] { new DatabaseColumnRequest("Name", new DatabaseTypeRequest(typeof(string), 50)) }); diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/ExtractionSubdirectoryPatternTests.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/ExtractionSubdirectoryPatternTests.cs index f8fa30df85..12e117e068 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/ExtractionSubdirectoryPatternTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/ExtractionSubdirectoryPatternTests.cs @@ -26,7 +26,7 @@ public void Test_NoRelativePaths() }; var ex = Assert.Throws(() => dest.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.Contains("ExtractionSubdirectoryPattern cannot contain dots", ex.Message); + Assert.That(ex.Message, Does.Contain("ExtractionSubdirectoryPattern cannot contain dots")); } [TestCase("bad")] @@ -42,7 +42,7 @@ public void Test_NoConfigToken(string badString) }; var ex = Assert.Throws(() => dest.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.Contains("ExtractionSubdirectoryPattern must contain a Configuration element", ex.Message); + Assert.That(ex.Message, Does.Contain("ExtractionSubdirectoryPattern must contain a Configuration element")); } [TestCase("$c/fff")] @@ -55,7 +55,7 @@ public void Test_NoDatasetToken(string badString) }; var ex = Assert.Throws(() => dest.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.Contains("ExtractionSubdirectoryPattern must contain a Dataset element", ex.Message); + Assert.That(ex.Message, Does.Contain("ExtractionSubdirectoryPattern must contain a Dataset element")); } /* @@ -94,6 +94,6 @@ public void Test_ValidPaths(string goodString, string pattern) Assert.DoesNotThrow(() => dest.Check(ThrowImmediatelyCheckNotifier.Quiet)); var answer = dest.GetDirectoryFor(cmd); - StringAssert.IsMatch(pattern, answer.FullName.Replace('\\', '/')); + Assert.That(answer.FullName.Replace('\\', '/'), Does.Match(pattern)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/HashedDataExtractionTests.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/HashedDataExtractionTests.cs index eb5a9e7875..6c5d45f132 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/HashedDataExtractionTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/HashedDataExtractionTests.cs @@ -7,7 +7,6 @@ using System.IO; using System.Linq; using NUnit.Framework; -using Rdmp.Core.DataExport.DataExtraction.Pipeline; using Rdmp.Core.DataExport.DataExtraction.Pipeline.Destinations; using Rdmp.Core.QueryBuilding; using Rdmp.Core.ReusableLibraryCode.Progress; @@ -34,7 +33,7 @@ public void ExtractNormally() _catalogue.SaveToDatabase(); _request.DatasetBundle.DataSet.RevertToDatabaseState(); - Assert.AreEqual(1, _request.ColumnsToExtract.Count(c => c.IsExtractionIdentifier)); + Assert.That(_request.ColumnsToExtract.Count(c => c.IsExtractionIdentifier), Is.EqualTo(1)); var listener = new ToMemoryDataLoadEventListener(true); Execute(out _, out var result, listener); @@ -45,17 +44,20 @@ public void ExtractNormally() m.Message.Contains("/*Decided on extraction SQL:*/")) .ToArray(); - Assert.AreEqual(1, messages.Length, "Expected a message about what the final extraction SQL was"); - Assert.IsTrue(messages[0].Message.Contains(" HASH JOIN "), + Assert.That(messages, Has.Length.EqualTo(1), "Expected a message about what the final extraction SQL was"); + Assert.That(messages[0].Message, Does.Contain(" HASH JOIN "), "expected use of hash matching was not reported by ExecuteDatasetExtractionSource in the SQL actually executed"); var r = (ExecuteDatasetExtractionFlatFileDestination)result; - //this should be what is in the file, the private identifier and the 1 that was put into the table in the first place (see parent class for the test data setup) - Assert.AreEqual($@"ReleaseID,Name,DateOfBirth -{_cohortKeysGenerated[_cohortKeysGenerated.Keys.First()]},Dave,2001-01-01", File.ReadAllText(r.OutputFile).Trim()); + Assert.Multiple(() => + { + //this should be what is in the file, the private identifier and the 1 that was put into the table in the first place (see parent class for the test data setup) + Assert.That(File.ReadAllText(r.OutputFile).Trim(), Is.EqualTo($@"ReleaseID,Name,DateOfBirth +{_cohortKeysGenerated[_cohortKeysGenerated.Keys.First()]},Dave,2001-01-01")); - Assert.AreEqual(1, _request.QueryBuilder.SelectColumns.Count(c => c.IColumn is ReleaseIdentifierSubstitution)); + Assert.That(_request.QueryBuilder.SelectColumns.Count(c => c.IColumn is ReleaseIdentifierSubstitution), Is.EqualTo(1)); + }); File.Delete(r.OutputFile); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/NormalDataExtractionTests.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/NormalDataExtractionTests.cs index 0a883fa157..68e0862a01 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/NormalDataExtractionTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/NormalDataExtractionTests.cs @@ -10,7 +10,6 @@ using NUnit.Framework; using Rdmp.Core.Curation.Data; using Rdmp.Core.DataExport.DataExtraction; -using Rdmp.Core.DataExport.DataExtraction.Pipeline; using Rdmp.Core.DataExport.DataExtraction.Pipeline.Destinations; using Rdmp.Core.QueryBuilding; using Tests.Common.Scenarios; @@ -26,17 +25,20 @@ public void ExtractNormally() _catalogue.SaveToDatabase(); _request.DatasetBundle.DataSet.RevertToDatabaseState(); - Assert.AreEqual(1, _request.ColumnsToExtract.Count(c => c.IsExtractionIdentifier)); + Assert.That(_request.ColumnsToExtract.Count(c => c.IsExtractionIdentifier), Is.EqualTo(1)); Execute(out _, out var result); var r = (ExecuteDatasetExtractionFlatFileDestination)result; - //this should be what is in the file, the private identifier and the 1 that was put into the table in the first place (see parent class for the test data setup) - Assert.AreEqual($@"ReleaseID,Name,DateOfBirth -{_cohortKeysGenerated[_cohortKeysGenerated.Keys.First()]},Dave,2001-01-01", File.ReadAllText(r.OutputFile).Trim()); + Assert.Multiple(() => + { + //this should be what is in the file, the private identifier and the 1 that was put into the table in the first place (see parent class for the test data setup) + Assert.That(File.ReadAllText(r.OutputFile).Trim(), Is.EqualTo($@"ReleaseID,Name,DateOfBirth +{_cohortKeysGenerated[_cohortKeysGenerated.Keys.First()]},Dave,2001-01-01")); - Assert.AreEqual(1, _request.QueryBuilder.SelectColumns.Count(c => c.IColumn is ReleaseIdentifierSubstitution)); + Assert.That(_request.QueryBuilder.SelectColumns.Count(c => c.IColumn is ReleaseIdentifierSubstitution), Is.EqualTo(1)); + }); File.Delete(r.OutputFile); } @@ -48,7 +50,7 @@ public void DodgyCharactersInCatalogueName() try { _catalogue.Name = "Fish;#:::FishFish"; - Assert.IsFalse(Catalogue.IsAcceptableName(_catalogue.Name)); + Assert.That(Catalogue.IsAcceptableName(_catalogue.Name), Is.False); _catalogue.SaveToDatabase(); _extractableDataSet.RevertToDatabaseState(); @@ -61,9 +63,8 @@ public void DodgyCharactersInCatalogueName() var dir = extractionDirectory.GetDirectoryForDataset(_extractableDataSet); }); - Assert.AreEqual( - "Cannot extract dataset Fish;#:::FishFish because it points at Catalogue with an invalid name, name is invalid because:The following invalid characters were found:'#'", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Cannot extract dataset Fish;#:::FishFish because it points at Catalogue with an invalid name, name is invalid because:The following invalid characters were found:'#'")); } finally { diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/RowPeekerTests.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/RowPeekerTests.cs index 10b194e603..2d762a3b25 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/RowPeekerTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/RowPeekerTests.cs @@ -39,9 +39,9 @@ public void Peeker() //Reads fish and peeks dish p.AddWhile(mock, r => (string)r["MyCol"] == "fish", dt2); - //read one row - Assert.AreEqual(1, dt2.Rows.Count); - Assert.AreEqual("fish", dt2.Rows[0]["MyCol"]); + //read one row + Assert.That(dt2.Rows, Has.Count.EqualTo(1)); + Assert.That(dt2.Rows[0]["MyCol"], Is.EqualTo("fish")); using var dt3 = new DataTable(); dt3.Columns.Add("MyCol"); @@ -52,8 +52,8 @@ public void Peeker() //clear the peek //unpeeks dish p.AddPeekedRowsIfAny(dt3); - Assert.AreEqual(1, dt3.Rows.Count); - Assert.AreEqual("dish", dt3.Rows[0]["MyCol"]); + Assert.That(dt3.Rows, Has.Count.EqualTo(1)); + Assert.That(dt3.Rows[0]["MyCol"], Is.EqualTo("dish")); //now we can read into dt4 but the condition is false //Reads nothing but peeks splish @@ -61,18 +61,18 @@ public void Peeker() dt4.Columns.Add("MyCol"); p.AddWhile(mock, r => (string)r["MyCol"] == "fish", dt4); - Assert.AreEqual(0, dt4.Rows.Count); + Assert.That(dt4.Rows, Is.Empty); //we passed a null chunk and that pulls back the legit data table var dt5 = p.AddPeekedRowsIfAny(null); - Assert.IsNotNull(dt5); - Assert.AreEqual("splish", dt5.Rows[0]["MyCol"]); + Assert.That(dt5, Is.Not.Null); + Assert.That(dt5.Rows[0]["MyCol"], Is.EqualTo("splish")); using var dt6 = new DataTable(); dt6.Columns.Add("MyCol"); p.AddWhile(mock, r => (string)r["MyCol"] == "fish", dt6); - Assert.AreEqual(0, dt6.Rows.Count); + Assert.That(dt6.Rows, Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/SimpleFileExtractorTests.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/SimpleFileExtractorTests.cs index 135eb694fa..01ef535a95 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/SimpleFileExtractorTests.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/SimpleFileExtractorTests.cs @@ -12,6 +12,7 @@ using System.Linq; using Rdmp.Core.ReusableLibraryCode.Checks; using Rdmp.Core.ReusableLibraryCode.Progress; +using NUnit.Framework.Legacy; namespace Rdmp.Core.Tests.DataExport.DataExtraction; @@ -167,10 +168,12 @@ public void PatientFileMissingOne() FileAssert.DoesNotExist(Path.Combine(_outDir.FullName, "blah2.txt")); FileAssert.Exists(Path.Combine(_outDir.FullName, "Rel1.txt")); - Assert.AreEqual(ProgressEventType.Warning, mem.GetWorst()); + Assert.Multiple(() => + { + Assert.That(mem.GetWorst(), Is.EqualTo(ProgressEventType.Warning)); - StringAssert.StartsWith("No Files were found matching Pattern Pat2.txt in ", - mem.GetAllMessagesByProgressEventType()[ProgressEventType.Warning].Single().Message); + Assert.That(mem.GetAllMessagesByProgressEventType()[ProgressEventType.Warning].Single().Message, Does.StartWith("No Files were found matching Pattern Pat2.txt in ")); + }); } [Test] @@ -216,9 +219,8 @@ public void PatientBothDirs() // does not exist var ex = Assert.Throws(() => _extractor.MovePatient("Sub3", "Rel3", _outDir, ThrowImmediatelyDataLoadEventListener.QuietPicky, new GracefulCancellationToken())); - Assert.AreEqual( - $"No Directories were found matching Pattern Sub3 in {_inDir.FullName}. For private identifier 'Sub3'", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo($"No Directories were found matching Pattern Sub3 in {_inDir.FullName}. For private identifier 'Sub3'")); // if not throwing on warnings then a missing sub just passes through and is ignored _extractor.MovePatient("Sub3", "Rel3", _outDir, ThrowImmediatelyDataLoadEventListener.Quiet, diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/SupplementalExtractionResultsTest.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/SupplementalExtractionResultsTest.cs index c45b91d115..9f06e8372a 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/SupplementalExtractionResultsTest.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/SupplementalExtractionResultsTest.cs @@ -27,8 +27,11 @@ public void TestCreating() var result = new SupplementalExtractionResults(DataExportRepository, ec, "select * from Globalsglba", tbl); - Assert.IsTrue(result.IsReferenceTo(typeof(SupportingSQLTable))); - Assert.IsTrue(result.IsReferenceTo(tbl)); - Assert.IsFalse(result.IsReferenceTo(othertbl)); + Assert.Multiple(() => + { + Assert.That(result.IsReferenceTo(typeof(SupportingSQLTable))); + Assert.That(result.IsReferenceTo(tbl)); + Assert.That(result.IsReferenceTo(othertbl), Is.False); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/DataExtraction/TestCohortRefreshing.cs b/Rdmp.Core.Tests/DataExport/DataExtraction/TestCohortRefreshing.cs index 5640033088..a719fe8715 100644 --- a/Rdmp.Core.Tests/DataExport/DataExtraction/TestCohortRefreshing.cs +++ b/Rdmp.Core.Tests/DataExport/DataExtraction/TestCohortRefreshing.cs @@ -13,8 +13,6 @@ using Rdmp.Core.Curation.Data.Cohort; using Rdmp.Core.Curation.Data.Pipelines; using Rdmp.Core.Databases; -using Rdmp.Core.DataExport.DataExtraction.Pipeline; -using Rdmp.Core.DataExport.DataExtraction.Pipeline.Destinations; using Rdmp.Core.DataFlowPipeline; using Rdmp.Core.MapsDirectlyToDatabaseTable.Versioning; using Rdmp.Core.ReusableLibraryCode.Checks; @@ -45,14 +43,17 @@ public void RefreshCohort() var engine = new CohortRefreshEngine(ThrowImmediatelyDataLoadEventListener.Quiet, _configuration); - Assert.NotNull(engine.Request.NewCohortDefinition); + Assert.That(engine.Request.NewCohortDefinition, Is.Not.Null); var oldData = oldcohort.GetExternalData(); engine.Request.NewCohortDefinition.CohortReplacedIfAny = oldcohort; - Assert.AreEqual(oldData.ExternalDescription, engine.Request.NewCohortDefinition.Description); - Assert.AreEqual(oldData.ExternalVersion + 1, engine.Request.NewCohortDefinition.Version); + Assert.Multiple(() => + { + Assert.That(engine.Request.NewCohortDefinition.Description, Is.EqualTo(oldData.ExternalDescription)); + Assert.That(engine.Request.NewCohortDefinition.Version, Is.EqualTo(oldData.ExternalVersion + 1)); + }); } /// @@ -133,14 +134,17 @@ public void RefreshCohort_WithCaching() var engine = new CohortRefreshEngine(ThrowImmediatelyDataLoadEventListener.Quiet, _configuration); engine.Execute(); - Assert.NotNull(engine.Request.NewCohortDefinition); + Assert.That(engine.Request.NewCohortDefinition, Is.Not.Null); var oldData = oldcohort.GetExternalData(); - Assert.AreEqual(oldData.ExternalDescription, engine.Request.NewCohortDefinition.Description); - Assert.AreEqual(oldData.ExternalVersion + 1, engine.Request.NewCohortDefinition.Version); + Assert.Multiple(() => + { + Assert.That(engine.Request.NewCohortDefinition.Description, Is.EqualTo(oldData.ExternalDescription)); + Assert.That(engine.Request.NewCohortDefinition.Version, Is.EqualTo(oldData.ExternalVersion + 1)); - Assert.AreNotEqual(oldcohort.CountDistinct, engine.Request.CohortCreatedIfAny.CountDistinct); + Assert.That(engine.Request.CohortCreatedIfAny.CountDistinct, Is.Not.EqualTo(oldcohort.CountDistinct)); + }); //now nuke all data in the catalogue so the cic returns nobody (except that the identifiers are cached eh?) DataAccessPortal.ExpectDatabase(_tableInfo, DataAccessContext.InternalDataProcessing) @@ -154,15 +158,16 @@ public void RefreshCohort_WithCaching() //execute it var ex = Assert.Throws(() => engine.Execute()); - Assert.IsTrue( - ex.InnerException.InnerException.Message.Contains( - "CohortIdentificationCriteria execution resulted in an empty dataset")); + Assert.Multiple(() => + { + Assert.That( + ex.InnerException.InnerException.Message, Does.Contain("CohortIdentificationCriteria execution resulted in an empty dataset")); - //expected this message to happen - //that it did clear the cache - Assert.AreEqual(1, - toMem.EventsReceivedBySender.SelectMany(kvp => kvp.Value) - .Count(msg => msg.Message.Equals("Clearing Cohort Identifier Cache"))); + //expected this message to happen + //that it did clear the cache + Assert.That(toMem.EventsReceivedBySender.SelectMany(kvp => kvp.Value) + .Count(msg => msg.Message.Equals("Clearing Cohort Identifier Cache")), Is.EqualTo(1)); + }); } finally { diff --git a/Rdmp.Core.Tests/DataExport/ExtractionConfigurationTest.cs b/Rdmp.Core.Tests/DataExport/ExtractionConfigurationTest.cs index 3ac5f49f3b..8b77d1d7fb 100644 --- a/Rdmp.Core.Tests/DataExport/ExtractionConfigurationTest.cs +++ b/Rdmp.Core.Tests/DataExport/ExtractionConfigurationTest.cs @@ -47,7 +47,7 @@ public void ExtractableColumnTest() _ = new ExtractableColumn(DataExportRepository, dataSet, configuration, extractionInformation, 0, "Hashme2(Name)"); - Assert.AreEqual(configuration.GetAllExtractableColumnsFor(dataSet).Length, 1); + Assert.That(configuration.GetAllExtractableColumnsFor(dataSet), Has.Length.EqualTo(1)); } finally { diff --git a/Rdmp.Core.Tests/DataExport/ImportFileTests.cs b/Rdmp.Core.Tests/DataExport/ImportFileTests.cs index 34bad9d1b6..0c74766cb0 100644 --- a/Rdmp.Core.Tests/DataExport/ImportFileTests.cs +++ b/Rdmp.Core.Tests/DataExport/ImportFileTests.cs @@ -70,16 +70,19 @@ public void ImportFile() var tablesInDatabase = server.ExpectDatabase(databaseName).DiscoverTables(false); //there should be 1 table in this database - Assert.AreEqual(1, tablesInDatabase.Length); + Assert.That(tablesInDatabase, Has.Length.EqualTo(1)); - //it should be called the same as the file loaded - Assert.AreEqual(Path.GetFileNameWithoutExtension(file), tablesInDatabase[0].GetRuntimeName()); + Assert.Multiple(() => + { + //it should be called the same as the file loaded + Assert.That(tablesInDatabase[0].GetRuntimeName(), Is.EqualTo(Path.GetFileNameWithoutExtension(file))); - Assert.AreEqual("varchar(7)", GetColumnType(database, tableName, "Name")); - Assert.AreEqual("varchar(13)", GetColumnType(database, tableName, "Surname")); - Assert.AreEqual("int", GetColumnType(database, tableName, "Age")); - Assert.AreEqual("decimal(3,2)", GetColumnType(database, tableName, "Healthiness")); - Assert.AreEqual("datetime2", GetColumnType(database, tableName, "DateOfImagining")); + Assert.That(GetColumnType(database, tableName, "Name"), Is.EqualTo("varchar(7)")); + Assert.That(GetColumnType(database, tableName, "Surname"), Is.EqualTo("varchar(13)")); + Assert.That(GetColumnType(database, tableName, "Age"), Is.EqualTo("int")); + Assert.That(GetColumnType(database, tableName, "Healthiness"), Is.EqualTo("decimal(3,2)")); + Assert.That(GetColumnType(database, tableName, "DateOfImagining"), Is.EqualTo("datetime2")); + }); using (var con = (SqlConnection)server.GetConnection()) { @@ -90,23 +93,26 @@ public void ImportFile() $"Select * from {tablesInDatabase[0].GetRuntimeName()} WHERE Name='Frank'", con); var r = cmdReadData.ExecuteReader(); - //expected 1 record only - Assert.IsTrue(r.Read()); + Assert.Multiple(() => + { + //expected 1 record only + Assert.That(r.Read()); - Assert.AreEqual("Frank", r["Name"]); - Assert.AreEqual("Mortus,M", r["Surname"]); - Assert.AreEqual(41, r["Age"]); - Assert.AreEqual(0.0f, r["Healthiness"]); - Assert.AreEqual(new DateTime(2005, 12, 1), r["DateOfImagining"]); + Assert.That(r["Name"], Is.EqualTo("Frank")); + Assert.That(r["Surname"], Is.EqualTo("Mortus,M")); + Assert.That(r["Age"], Is.EqualTo(41)); + Assert.That(r["Healthiness"], Is.EqualTo(0.0f)); + Assert.That(r["DateOfImagining"], Is.EqualTo(new DateTime(2005, 12, 1))); + }); //and no more records - Assert.IsFalse(r.Read()); + Assert.That(r.Read(), Is.False); con.Close(); } server.ExpectDatabase(databaseName).Drop(); - Assert.IsFalse(server.ExpectDatabase(databaseName).Exists()); + Assert.That(server.ExpectDatabase(databaseName).Exists(), Is.False); } finally { diff --git a/Rdmp.Core.Tests/DataExport/ProjectChecksTestsComplex.cs b/Rdmp.Core.Tests/DataExport/ProjectChecksTestsComplex.cs index 93ff3b445e..4e336d908a 100644 --- a/Rdmp.Core.Tests/DataExport/ProjectChecksTestsComplex.cs +++ b/Rdmp.Core.Tests/DataExport/ProjectChecksTestsComplex.cs @@ -35,9 +35,8 @@ public void DatasetIsDisabled() var exception = Assert.Throws(() => new ProjectChecker(new ThrowImmediatelyActivator(RepositoryLocator), _project).Check( ThrowImmediatelyCheckNotifier.QuietPicky)); - Assert.AreEqual( - "Dataset TestTable is set to DisableExtraction=true, probably someone doesn't want you extracting this dataset at the moment", - exception.Message); + Assert.That( + exception.Message, Is.EqualTo("Dataset TestTable is set to DisableExtraction=true, probably someone doesn't want you extracting this dataset at the moment")); //but if the user goes ahead and executes the extraction that should fail too var source = new ExecuteDatasetExtractionSource(); @@ -45,6 +44,6 @@ public void DatasetIsDisabled() var exception2 = Assert.Throws(() => source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.AreEqual("Cannot extract TestTable because DisableExtraction is set to true", exception2?.Message); + Assert.That(exception2?.Message, Is.EqualTo("Cannot extract TestTable because DisableExtraction is set to true")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/ProjectChecksTestsSimple.cs b/Rdmp.Core.Tests/DataExport/ProjectChecksTestsSimple.cs index 8ac6874346..809f155500 100644 --- a/Rdmp.Core.Tests/DataExport/ProjectChecksTestsSimple.cs +++ b/Rdmp.Core.Tests/DataExport/ProjectChecksTestsSimple.cs @@ -29,7 +29,7 @@ public void Project_NoConfigurations() var ex = Assert.Throws(() => new ProjectChecker(new ThrowImmediatelyActivator(RepositoryLocator), p).Check( ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("Project does not have any ExtractionConfigurations yet", ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("Project does not have any ExtractionConfigurations yet")); } finally { @@ -42,7 +42,7 @@ public void Project_NoDirectory() { var p = GetProjectWithConfig(out var config); var ex = Assert.Throws(() => RunTestWithCleanup(p, config)); - Assert.AreEqual("Project does not have an ExtractionDirectory", ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("Project does not have an ExtractionDirectory")); } [Test] @@ -55,7 +55,7 @@ public void Project_NonExistentDirectory(string dir) p.ExtractionDirectory = dir; var ex = Assert.Throws(() => RunTestWithCleanup(p, config)); - Assert.IsTrue(Regex.IsMatch(ex.Message, @"Project ExtractionDirectory .* Does Not Exist")); + Assert.That(Regex.IsMatch(ex.Message, @"Project ExtractionDirectory .* Does Not Exist")); } [Test] @@ -65,7 +65,7 @@ public void Project_DodgyCharactersInExtractionDirectoryName() p.ExtractionDirectory = @"C:\|||"; var ex = Assert.Throws(() => RunTestWithCleanup(p, config)); - Assert.AreEqual(@"Project ExtractionDirectory ('C:\|||') Does Not Exist", ex.Message); + Assert.That(ex.Message, Is.EqualTo(@"Project ExtractionDirectory ('C:\|||') Does Not Exist")); } [Test] @@ -84,16 +84,22 @@ public void ConfigurationFrozen_Remnants() try { - //remnant exists - Assert.IsTrue(dir.Exists); - Assert.IsTrue(remnantDir.Exists); + Assert.Multiple(() => + { + //remnant exists + Assert.That(dir.Exists); + Assert.That(remnantDir.Exists); + }); //resolve accepting deletion new ProjectChecker(new ThrowImmediatelyActivator(RepositoryLocator), p).Check(new AcceptAllCheckNotifier()); - //boom remnant doesnt exist anymore (but parent does obviously) - Assert.IsTrue(dir.Exists); - Assert.IsFalse(Directory.Exists(remnantDir.FullName)); //cant use .Exists for some reason, c# caches answer? + Assert.Multiple(() => + { + //boom remnant doesn't exist anymore (but parent does obviously) + Assert.That(dir.Exists); + Assert.That(Directory.Exists(remnantDir.FullName), Is.False); //cant use .Exists for some reason, c# caches answer? + }); } finally { @@ -124,7 +130,7 @@ public void ConfigurationFrozen_RemnantsWithFiles() var notifier = new ToMemoryCheckNotifier(); RunTestWithCleanup(p, config, notifier); - Assert.IsTrue(notifier.Messages.Any( + Assert.That(notifier.Messages.Any( m => m.Result == CheckResult.Fail && Regex.IsMatch(m.Message, @"Found non-empty folder .* which is left over extracted folder after data release \(First file found was '.*[/\\]DMPTestCatalogue[/\\]Lookups[/\\]Text.txt' but there may be others\)"))); @@ -140,8 +146,7 @@ public void Configuration_NoDatasets() { var p = GetProjectWithConfigDirectory(out var config, out _); var ex = Assert.Throws(() => RunTestWithCleanup(p, config)); - StringAssert.StartsWith("There are no datasets selected for open configuration 'New ExtractionConfiguration", - ex.Message); + Assert.That(ex.Message, Does.StartWith("There are no datasets selected for open configuration 'New ExtractionConfiguration")); } @@ -151,9 +156,8 @@ public void Configuration_NoProjectNumber() var p = GetProjectWithConfigDirectory(out var config, out _); p.ProjectNumber = null; var ex = Assert.Throws(() => RunTestWithCleanup(p, config)); - StringAssert.Contains( - "Project does not have a Project Number, this is a number which is meaningful to you (as opposed to ID which is the ", - ex.Message); + Assert.That( + ex.Message, Does.Contain("Project does not have a Project Number, this is a number which is meaningful to you (as opposed to ID which is the ")); } private void RunTestWithCleanup(Project p, ExtractionConfiguration config, ICheckNotifier notifier = null) diff --git a/Rdmp.Core.Tests/DataExport/ProjectCohortIdentificationConfigurationAssociationTests.cs b/Rdmp.Core.Tests/DataExport/ProjectCohortIdentificationConfigurationAssociationTests.cs index 4dbd479367..ac70883cbb 100644 --- a/Rdmp.Core.Tests/DataExport/ProjectCohortIdentificationConfigurationAssociationTests.cs +++ b/Rdmp.Core.Tests/DataExport/ProjectCohortIdentificationConfigurationAssociationTests.cs @@ -31,11 +31,14 @@ public void TestOrphanCic() //fetch the instance var cicAssoc = memory.GetAllObjects().Single(); - //relationship from p should resolve to the association link - Assert.AreEqual(cicAssoc, p.ProjectCohortIdentificationConfigurationAssociations[0]); + Assert.Multiple(() => + { + //relationship from p should resolve to the association link + Assert.That(p.ProjectCohortIdentificationConfigurationAssociations[0], Is.EqualTo(cicAssoc)); - //relationship from p should resolve to the cic - Assert.AreEqual(cic, p.GetAssociatedCohortIdentificationConfigurations()[0]); + //relationship from p should resolve to the cic + Assert.That(p.GetAssociatedCohortIdentificationConfigurations()[0], Is.EqualTo(cic)); + }); //in order to make it an orphan we have to suppress the system default behaviour of cascading across the deletion var obscure = memory.ObscureDependencyFinder as CatalogueObscureDependencyFinder; @@ -46,19 +49,21 @@ public void TestOrphanCic() cicAssoc.ClearAllInjections(); //assoc should still exist - Assert.AreEqual(cicAssoc, p.ProjectCohortIdentificationConfigurationAssociations[0]); - Assert.IsNull(p.ProjectCohortIdentificationConfigurationAssociations[0].CohortIdentificationConfiguration); + Assert.That(p.ProjectCohortIdentificationConfigurationAssociations[0], Is.EqualTo(cicAssoc)); + Assert.Multiple(() => + { + Assert.That(p.ProjectCohortIdentificationConfigurationAssociations[0].CohortIdentificationConfiguration, Is.Null); - //relationship from p should resolve to the cic - Assert.IsEmpty(p.GetAssociatedCohortIdentificationConfigurations()); + //relationship from p should resolve to the cic + Assert.That(p.GetAssociatedCohortIdentificationConfigurations(), Is.Empty); + }); //error should be reported in top right of program var ex = Assert.Throws(() => new DataExportChildProvider(new RepositoryProvider(memory), null, ThrowImmediatelyCheckNotifier.Quiet, null)); - StringAssert.IsMatch( - @"Failed to find Associated Cohort Identification Configuration with ID \d+ which was supposed to be associated with my proj", - ex.Message); + Assert.That( + ex.Message, Does.Match(@"Failed to find Associated Cohort Identification Configuration with ID \d+ which was supposed to be associated with my proj")); //but UI should still respond var childProvider = new DataExportChildProvider(new RepositoryProvider(memory), null, @@ -69,6 +74,6 @@ public void TestOrphanCic() var cics = childProvider.GetChildren(cohorts).OfType() .First(); - Assert.IsEmpty(childProvider.GetChildren(cics)); + Assert.That(childProvider.GetChildren(cics), Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataExport/TableValuedFunctionTests/EndToEndTableValuedFunction.cs b/Rdmp.Core.Tests/DataExport/TableValuedFunctionTests/EndToEndTableValuedFunction.cs index 4505acc528..a06af0e9f3 100644 --- a/Rdmp.Core.Tests/DataExport/TableValuedFunctionTests/EndToEndTableValuedFunction.cs +++ b/Rdmp.Core.Tests/DataExport/TableValuedFunctionTests/EndToEndTableValuedFunction.cs @@ -220,7 +220,7 @@ definitionID int var engineer = new ForwardEngineerCatalogue(tbl, cols); engineer.ExecuteForwardEngineering(out var cata, out var cis, out var eis); - Assert.AreEqual("chi", eis[0].GetRuntimeName()); + Assert.That(eis[0].GetRuntimeName(), Is.EqualTo("chi")); eis[0].IsExtractionIdentifier = true; eis[0].SaveToDatabase(); @@ -264,12 +264,12 @@ private void TestThatQueryBuilderWithoutParametersBeingSetThrowsQueryBuildingExc var qb = new QueryBuilder("", ""); //table valued function should have 2 fields (chi and definitionID) - Assert.AreEqual(2, _tvfCatalogue.GetAllExtractionInformation(ExtractionCategory.Any).Length); + Assert.That(_tvfCatalogue.GetAllExtractionInformation(ExtractionCategory.Any), Has.Length.EqualTo(2)); qb.AddColumnRange(_tvfCatalogue.GetAllExtractionInformation(ExtractionCategory.Any)); var ex = Assert.Throws(() => Console.WriteLine(qb.SQL)); - Assert.AreEqual("No Value defined for Parameter @numberOfRecords", ex.Message); + Assert.That(ex.Message, Is.EqualTo("No Value defined for Parameter @numberOfRecords")); } private void TestWithParameterValueThatRowsAreReturned() @@ -293,11 +293,14 @@ private void TestWithParameterValueThatRowsAreReturned() while (r.Read()) { rowsReturned++; - Assert.NotNull(r["chi"]); - Assert.NotNull(r["definitionID"]); + Assert.Multiple(() => + { + Assert.That(r["chi"], Is.Not.Null); + Assert.That(r["definitionID"], Is.Not.Null); + }); } - Assert.AreEqual(rowsReturned, 5); + Assert.That(rowsReturned, Is.EqualTo(5)); } private void TestUsingTvfForAggregates() @@ -342,11 +345,14 @@ private void TestUsingTvfForAggregates() con.Open(); var r = db.Server.GetCommand(sql, con).ExecuteReader(); - Assert.IsTrue(r.Read()); + Assert.Multiple(() => + { + Assert.That(r.Read()); - Assert.AreEqual(r[1], 10); + Assert.That(r[1], Is.EqualTo(10)); + }); - Assert.IsFalse(r.Read()); + Assert.That(r.Read(), Is.False); } //create a global overriding parameter on the aggregate @@ -365,11 +371,14 @@ private void TestUsingTvfForAggregates() con.Open(); var r = db.Server.GetCommand(sql, con).ExecuteReader(); - Assert.IsTrue(r.Read()); + Assert.Multiple(() => + { + Assert.That(r.Read()); - Assert.AreEqual(r[1], 1); //should now only have 1 record being retrned and counted when executing + Assert.That(r[1], Is.EqualTo(1)); //should now only have 1 record being returned and counted when executing + }); - Assert.IsFalse(r.Read()); + Assert.That(r.Read(), Is.False); } } @@ -383,7 +392,7 @@ private void TestAddingTvfToCIC() _cicAggregate = _cic.ImportAggregateConfigurationAsIdentifierList(_aggregate, (s, e) => null); //it should have imported the global parameter as part of the import right? - Assert.AreEqual(1, _cicAggregate.GetAllParameters().Length); + Assert.That(_cicAggregate.GetAllParameters(), Has.Length.EqualTo(1)); //add the new cic to the container root.AddChild(_cicAggregate, 2); @@ -404,10 +413,10 @@ private void TestAddingTvfToCIC() var r = db.Server.GetCommand(sql, con).ExecuteReader(); //2 chi numbers should be returned - Assert.IsTrue(r.Read()); - Assert.IsTrue(r.Read()); + Assert.That(r.Read()); + Assert.That(r.Read()); - Assert.IsFalse(r.Read()); + Assert.That(r.Read(), Is.False); } private void TestDataExportOfTvf() @@ -427,7 +436,7 @@ private void TestDataExportOfTvf() config.AddColumnToExtraction(tvfExtractable, e); //the default value should be 10 - Assert.AreEqual("10", _tvfTableInfo.GetAllParameters().Single().Value); + Assert.That(_tvfTableInfo.GetAllParameters().Single().Value, Is.EqualTo("10")); //configure an extraction specific global of 1 so that only 1 chi number is fetched (which will be in the cohort) var globalP = @@ -445,13 +454,16 @@ private void TestDataExportOfTvf() var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(1, dt.Rows.Count); + Assert.Multiple(() => + { + Assert.That(dt.Rows, Has.Count.EqualTo(1)); - Assert.AreEqual("ReleaseId", dt.Columns[0].ColumnName); + Assert.That(dt.Columns[0].ColumnName, Is.EqualTo("ReleaseId")); + }); //should be a guid - Assert.IsTrue(dt.Rows[0][0].ToString().Length > 10); - Assert.IsTrue(dt.Rows[0][0].ToString().Contains('-')); + Assert.That(dt.Rows[0][0].ToString(), Has.Length.GreaterThan(10)); + Assert.That(dt.Rows[0][0].ToString(), Does.Contain('-')); selected.DeleteInDatabase(); globalP.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/DataExport/TestExtractableTables.cs b/Rdmp.Core.Tests/DataExport/TestExtractableTables.cs index 3c35d94b7e..e1b304b820 100644 --- a/Rdmp.Core.Tests/DataExport/TestExtractableTables.cs +++ b/Rdmp.Core.Tests/DataExport/TestExtractableTables.cs @@ -25,7 +25,7 @@ public void DodgyID_CreateCohortDatabaseTable_Fails() { var ex = Assert.Throws(() => new ExtractableCohort(DataExportRepository, _externalCohortTable, -899)); - Assert.IsTrue(ex.Message.StartsWith("ID -899 does not exist in Cohort Definitions")); + Assert.That(ex.Message, Does.StartWith("ID -899 does not exist in Cohort Definitions")); } @@ -38,7 +38,7 @@ public void CreateExtractableDataSet() { //creates with a Null Catalogue until it is associated with a catalogue and saved eds = new ExtractableDataSet(DataExportRepository, cata); - Assert.AreEqual(cata.ID, eds.Catalogue_ID); + Assert.That(eds.Catalogue_ID, Is.EqualTo(cata.ID)); } finally { @@ -56,7 +56,7 @@ public void UpdateProjectDatabaseTable() try { - Assert.AreEqual(table.Name, "unit_test_UpdateProjectDatabaseTable"); + Assert.That(table.Name, Is.EqualTo("unit_test_UpdateProjectDatabaseTable")); table.Name = "unit_test_UpdateProjectDatabaseTable2"; table.SaveToDatabase(); @@ -79,7 +79,7 @@ public void CreateExtractionConfiguration() try { - Assert.AreEqual(table.Username, Environment.UserName); + Assert.That(Environment.UserName, Is.EqualTo(table.Username)); } finally { @@ -91,7 +91,7 @@ public void CreateExtractionConfiguration() #region helper methods - public static void PropertyValuesAreEquals(object actual, object expected) + private static void PropertyValuesAreEquals(object actual, object expected) { var properties = expected.GetType().GetProperties() .Where(info => !Attribute.IsDefined(info, typeof(DoNotExtractProperty))).ToArray(); @@ -106,29 +106,24 @@ public static void PropertyValuesAreEquals(object actual, object expected) var actualValue = property.GetValue(actual, null); if (expectedValue is SqlCommand && - actualValue is SqlCommand) //don't compare sql commands they will be subtly different or just refer to different objects iwth the exact same values + actualValue is SqlCommand) //don't compare sql commands they will be subtly different or just refer to different objects with the exact same values continue; if (actualValue is IList list) AssertListsAreEquals(property, list, (IList)expectedValue); else if (!Equals(expectedValue, actualValue)) - Assert.Fail("Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType?.Name, - property.Name, expectedValue, actualValue); + Assert.Fail($"Property {property.DeclaringType?.Name}.{property.Name} does not match. Expected: {expectedValue} but was: {actualValue}"); } } private static void AssertListsAreEquals(PropertyInfo property, IList actualList, IList expectedList) { if (actualList.Count != expectedList.Count) - Assert.Fail( - "Property {0}.{1} does not match. Expected IList containing {2} elements but was IList containing {3} elements", - property.PropertyType.Name, property.Name, expectedList.Count, actualList.Count); + Assert.Fail($"Property {property.PropertyType.Name}.{property.Name} does not match. Expected IList containing {expectedList.Count} elements but was IList containing {actualList.Count} elements"); for (var i = 0; i < actualList.Count; i++) if (!Equals(actualList[i], expectedList[i])) - Assert.Fail( - "Property {0}.{1} does not match. Expected IList with element {1} equals to {2} but was IList with element {1} equals to {3}", - property.PropertyType.Name, property.Name, expectedList[i], actualList[i]); + Assert.Fail($"Property {property.PropertyType.Name}.{property.Name} does not match. Expected IList with element {property.Name} equals to {expectedList[i]} but was IList with element {property.Name} equals to {actualList[i]}"); } #endregion diff --git a/Rdmp.Core.Tests/DataLoad/Engine/DatabaseManagement/EntityNaming/HICDatabaseConfigurationTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/DatabaseManagement/EntityNaming/HICDatabaseConfigurationTests.cs index f997c0f00c..038f405bcc 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/DatabaseManagement/EntityNaming/HICDatabaseConfigurationTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/DatabaseManagement/EntityNaming/HICDatabaseConfigurationTests.cs @@ -46,25 +46,37 @@ public void TestHICDatabaseConfiguration_ExpectTables(bool testLookup) var result = conf.ExpectTables(job, LoadBubble.Raw, testLookup).ToArray(); - Assert.AreEqual(testLookup ? 2 : 1, result.Length); - StringAssert.AreEqualIgnoringCase("mydb_RAW", result[0].Database.GetRuntimeName()); - StringAssert.AreEqualIgnoringCase("My_Table", result[0].GetRuntimeName()); + Assert.That(result, Has.Length.EqualTo(testLookup ? 2 : 1)); + Assert.Multiple(() => + { + Assert.That(result[0].Database.GetRuntimeName(), Is.EqualTo("mydb_RAW").IgnoreCase); + Assert.That(result[0].GetRuntimeName(), Is.EqualTo("My_Table").IgnoreCase); + }); if (testLookup) { - StringAssert.AreEqualIgnoringCase("mydb_RAW", result[1].Database.GetRuntimeName()); - StringAssert.AreEqualIgnoringCase("MyHeartyLookup", result[1].GetRuntimeName()); + Assert.Multiple(() => + { + Assert.That(result[1].Database.GetRuntimeName(), Is.EqualTo("mydb_RAW").IgnoreCase); + Assert.That(result[1].GetRuntimeName(), Is.EqualTo("MyHeartyLookup").IgnoreCase); + }); } result = conf.ExpectTables(job, LoadBubble.Staging, testLookup).ToArray(); - Assert.AreEqual(testLookup ? 2 : 1, result.Length); - StringAssert.AreEqualIgnoringCase("DLE_STAGING", result[0].Database.GetRuntimeName()); - StringAssert.AreEqualIgnoringCase("mydb_My_Table_STAGING", result[0].GetRuntimeName()); + Assert.That(result, Has.Length.EqualTo(testLookup ? 2 : 1)); + Assert.Multiple(() => + { + Assert.That(result[0].Database.GetRuntimeName(), Is.EqualTo("DLE_STAGING").IgnoreCase); + Assert.That(result[0].GetRuntimeName(), Is.EqualTo("mydb_My_Table_STAGING").IgnoreCase); + }); if (testLookup) { - StringAssert.AreEqualIgnoringCase("DLE_STAGING", result[1].Database.GetRuntimeName()); - StringAssert.AreEqualIgnoringCase("mydb_MyHeartyLookup_STAGING", result[1].GetRuntimeName()); + Assert.Multiple(() => + { + Assert.That(result[1].Database.GetRuntimeName(), Is.EqualTo("DLE_STAGING").IgnoreCase); + Assert.That(result[1].GetRuntimeName(), Is.EqualTo("mydb_MyHeartyLookup_STAGING").IgnoreCase); + }); } } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/DatabaseManagement/TableInfoCloneOperationTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/DatabaseManagement/TableInfoCloneOperationTests.cs index 553f1115f4..c0f6e13fe9 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/DatabaseManagement/TableInfoCloneOperationTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/DatabaseManagement/TableInfoCloneOperationTests.cs @@ -37,6 +37,6 @@ public void Test_CloneTable() var tbl2 = tbl.Database.ExpectTable($"{tbl.GetRuntimeName()}_copy"); - Assert.IsTrue(tbl2.Exists()); + Assert.That(tbl2.Exists()); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/BackfillSqlHelperTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/BackfillSqlHelperTests.cs index a6a161b922..7d0136803b 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/BackfillSqlHelperTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/BackfillSqlHelperTests.cs @@ -63,11 +63,11 @@ public void TestGenerateSqlForThreeLevelJoinPath_TimePeriodIsGrandparent() From, joinPath); - Assert.AreEqual(string.Format(@"SELECT CurrentTable.*, TimePeriodicityTable.HeaderDate AS TimePeriodicityField + Assert.That(sql, Is.EqualTo(string.Format(@"SELECT CurrentTable.*, TimePeriodicityTable.HeaderDate AS TimePeriodicityField FROM [{0}]..[Results] CurrentTable LEFT JOIN [{0}]..[Samples] j1 ON j1.ID = CurrentTable.SampleID LEFT JOIN [{0}]..[Headers] TimePeriodicityTable ON TimePeriodicityTable.ID = j1.HeaderID", - From.GetRuntimeName()), sql); + From.GetRuntimeName()))); } private void ThreeTableSetupWhereTimePeriodIsGrandparent() @@ -90,7 +90,7 @@ private void ThreeTableSetupWhereTimePeriodIsGrandparent() tiHeaders.IsPrimaryExtractionTable = true; tiHeaders.SaveToDatabase(); - Assert.AreEqual(15, _catalogue.CatalogueItems.Length, "Unexpected number of items in catalogue"); + Assert.That(_catalogue.CatalogueItems, Has.Length.EqualTo(15), "Unexpected number of items in catalogue"); // Headers (1:M) Samples join new JoinInfo(CatalogueRepository, ciSamples.Single(ci => ci.GetRuntimeName().Equals("HeaderID")), @@ -149,7 +149,7 @@ private ITableInfo AddTableToCatalogue(string databaseName, string tableName, st return ti; } - public static void CreateTableWithColumnDefinitions(DiscoveredDatabase db, string tableName, + private static void CreateTableWithColumnDefinitions(DiscoveredDatabase db, string tableName, string columnDefinitions) { using var conn = db.Server.GetConnection(); @@ -157,7 +157,7 @@ public static void CreateTableWithColumnDefinitions(DiscoveredDatabase db, strin CreateTableWithColumnDefinitions(db, tableName, columnDefinitions, conn); } - public static void CreateTableWithColumnDefinitions(DiscoveredDatabase db, string tableName, + private static void CreateTableWithColumnDefinitions(DiscoveredDatabase db, string tableName, string columnDefinitions, DbConnection conn) { var sql = $"CREATE TABLE {tableName} ({columnDefinitions})"; diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/BackfillTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/BackfillTests.cs index e6a7e1800f..75df657fb8 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/BackfillTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/BackfillTests.cs @@ -78,11 +78,11 @@ public void Backfill_SingleTable_LoadContainsNewerUpdate() var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(1, numRows, "Should still be 1 record, this would be migrated to To"); + Assert.That(numRows, Is.EqualTo(1), "Should still be 1 record, this would be migrated to To"); cmd = new SqlCommand(@"SELECT Description FROM Samples", connection); var description = cmd.ExecuteScalar().ToString(); - Assert.AreEqual(description, "Newer than in To, should update To", + Assert.That(description, Is.EqualTo("Newer than in To, should update To"), "Description has been altered but is a valid update to To so should not have been touched."); } } @@ -94,7 +94,7 @@ private void SingleTableSetup() // Set SetUp catalogue entities AddTableToCatalogue(DatabaseName, "Samples", "ID", out _, true); - Assert.AreEqual(5, _catalogue.CatalogueItems.Length, "Unexpected number of items in catalogue"); + Assert.That(_catalogue.CatalogueItems, Has.Length.EqualTo(5), "Unexpected number of items in catalogue"); } private void Mutilate(string timeColumnName) @@ -154,7 +154,7 @@ public void Backfill_SingleTable_LoadContainsOlderUpdate() var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(0, numRows, + Assert.That(numRows, Is.EqualTo(0), "The record to be loaded is older than the corresponding record in To, should have been deleted"); } } @@ -202,11 +202,11 @@ public void Backfill_SingleTable_LoadContainsInsert() var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(1, numRows, "The record to be loaded is an insert should not have been deleted"); + Assert.That(numRows, Is.EqualTo(1), "The record to be loaded is an insert should not have been deleted"); cmd = new SqlCommand(@"SELECT Description FROM Samples", connection); var description = cmd.ExecuteScalar().ToString(); - Assert.AreEqual(description, "Does not exist in To, should remain in From after mutilation.", + Assert.That(description, Is.EqualTo("Does not exist in To, should remain in From after mutilation."), "Description has been altered but is a valid update to To so should not have been touched."); } } @@ -254,7 +254,7 @@ public void Backfill_SingleTable_Combined() var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(2, numRows, + Assert.That(numRows, Is.EqualTo(2), "Record 2 should have been deleted as it is an update to a record for which we have a later version."); } } @@ -276,7 +276,7 @@ private void TwoTableSetupWhereTimePeriodIsParent() tiSamples.IsPrimaryExtractionTable = true; tiSamples.SaveToDatabase(); - Assert.AreEqual(10, _catalogue.CatalogueItems.Length, "Unexpected number of items in catalogue"); + Assert.That(_catalogue.CatalogueItems, Has.Length.EqualTo(10), "Unexpected number of items in catalogue"); // Samples (1:M) Results join new JoinInfo(CatalogueRepository, ciResults.Single(info => info.GetRuntimeName().Equals("SampleID")), @@ -346,11 +346,11 @@ public void Backfill_TwoTables_TimePeriodParent_LoadContainsNewerUpdate() var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(1, numRows); + Assert.That(numRows, Is.EqualTo(1)); cmd = new SqlCommand(@"SELECT COUNT(*) FROM Results", connection); numRows = cmd.ExecuteScalar(); - Assert.AreEqual(3, numRows); + Assert.That(numRows, Is.EqualTo(3)); } } @@ -416,31 +416,31 @@ public void Backfill_TwoTables_TimePeriodParent_LoadContainsOlderUpdate() var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(1, numRows, "Item should still remain as there still should be a single result to insert."); + Assert.That(numRows, Is.EqualTo(1), "Item should still remain as there still should be a single result to insert."); cmd = new SqlCommand(@"SELECT * FROM Results", connection); using (var reader = cmd.ExecuteReader()) { - Assert.IsTrue(reader.HasRows); + Assert.That(reader.HasRows); reader.Read(); - Assert.AreEqual(12, reader["ID"]); + Assert.That(reader["ID"], Is.EqualTo(12)); var hasMoreResults = reader.Read(); - Assert.IsFalse(hasMoreResults, "Should only be one Result row left in From"); + Assert.That(hasMoreResults, Is.False, "Should only be one Result row left in From"); } cmd = new SqlCommand(@"SELECT * FROM Samples", connection); using (var reader = cmd.ExecuteReader()) { - Assert.IsTrue(reader.HasRows); + Assert.That(reader.HasRows); reader.Read(); - Assert.AreEqual("", reader["Description"].ToString(), + Assert.That(reader["Description"].ToString(), Is.EqualTo(""), "The To sample had a blank description which should have been copied in to the earlier From record."); var hasMoreResults = reader.Read(); - Assert.IsFalse(hasMoreResults, "Should only be one Samples row in From"); + Assert.That(hasMoreResults, Is.False, "Should only be one Samples row in From"); } } } @@ -507,11 +507,11 @@ public void Backfill_TwoTables_TimePeriodParent_LoadContainInsert() var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(1, numRows, "This is an insert, no data should be deleted/altered."); + Assert.That(numRows, Is.EqualTo(1), "This is an insert, no data should be deleted/altered."); cmd = new SqlCommand(@"SELECT COUNT(*) FROM Results", connection); numRows = cmd.ExecuteScalar(); - Assert.AreEqual(3, numRows, "This is an insert, no data should be deleted/altered."); + Assert.That(numRows, Is.EqualTo(3), "This is an insert, no data should be deleted/altered."); } } @@ -533,7 +533,7 @@ private void TwoTableSetupWhereTimePeriodIsChild() tiSamples.IsPrimaryExtractionTable = true; tiSamples.SaveToDatabase(); - Assert.AreEqual(10, _catalogue.CatalogueItems.Length, "Unexpected number of items in catalogue"); + Assert.That(_catalogue.CatalogueItems, Has.Length.EqualTo(10), "Unexpected number of items in catalogue"); // Headers (1:M) Samples join new JoinInfo(CatalogueRepository, ciSamples.Single(info => info.GetRuntimeName().Equals("HeaderID")), @@ -600,11 +600,11 @@ public void Backfill_TwoTables_TimePeriodChild_LoadContainsOlderUpdate() var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(0, numRows, "Sample should be deleted as it is older than corresponding row in To."); + Assert.That(numRows, Is.EqualTo(0), "Sample should be deleted as it is older than corresponding row in To."); cmd = new SqlCommand(@"SELECT COUNT(*) FROM Headers", connection); numRows = cmd.ExecuteScalar(); - Assert.AreEqual(0, numRows, "Header should have been pruned as it no longer has any children in From."); + Assert.That(numRows, Is.EqualTo(0), "Header should have been pruned as it no longer has any children in From."); } } @@ -672,16 +672,16 @@ public void Backfill_TwoTables_TimePeriodChild_LoadContainsOldInsert_WithOldPare var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(1, numRows, "Should still be 1 sample"); + Assert.That(numRows, Is.EqualTo(1), "Should still be 1 sample"); cmd = new SqlCommand(@"SELECT COUNT(*) FROM Headers", connection); numRows = cmd.ExecuteScalar(); - Assert.AreEqual(1, numRows, + Assert.That(numRows, Is.EqualTo(1), "Header should still be there (shouldn't be able to delete it as there should be a FK constraint with Samples)"); cmd = new SqlCommand(@"SELECT Discipline FROM Headers WHERE ID=1", connection); var discipline = cmd.ExecuteScalar().ToString(); - Assert.AreEqual("Biochemistry", discipline, + Assert.That(discipline, Is.EqualTo("Biochemistry"), "Header record in From be updated to reflect what is in To: the To record is authoritative as it contains at least one child from a later date."); } } @@ -746,16 +746,16 @@ public void Backfill_TwoTables_TimePeriodChild_LoadContainsNewInsert_WithNewPare var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(1, numRows, "Should still be 1 sample"); + Assert.That(numRows, Is.EqualTo(1), "Should still be 1 sample"); cmd = new SqlCommand(@"SELECT COUNT(*) FROM Headers", connection); numRows = cmd.ExecuteScalar(); - Assert.AreEqual(1, numRows, + Assert.That(numRows, Is.EqualTo(1), "Header should still be there (shouldn't be able to delete it as there should be a FK constraint with Samples)"); cmd = new SqlCommand(@"SELECT Discipline FROM Headers WHERE ID=1", connection); var discipline = cmd.ExecuteScalar().ToString(); - Assert.AreEqual("Haematology", discipline, + Assert.That(discipline, Is.EqualTo("Haematology"), "Header record in From should not be updated as it is 'correct'."); } } @@ -834,38 +834,56 @@ public void Backfill_TwoTables_TimePeriodChild_Combined() using (var reader = cmd.ExecuteReader()) { reader.Read(); - Assert.AreEqual(11, reader["ID"]); - Assert.AreEqual("2016-01-05T12:00:00", ((DateTime)reader["SampleDate"]).ToString("s")); + Assert.Multiple(() => + { + Assert.That(reader["ID"], Is.EqualTo(11)); + Assert.That(((DateTime)reader["SampleDate"]).ToString("s"), Is.EqualTo("2016-01-05T12:00:00")); + }); reader.Read(); - Assert.AreEqual(14, reader["ID"]); - Assert.AreEqual("2016-01-15T12:00:00", ((DateTime)reader["SampleDate"]).ToString("s")); + Assert.Multiple(() => + { + Assert.That(reader["ID"], Is.EqualTo(14)); + Assert.That(((DateTime)reader["SampleDate"]).ToString("s"), Is.EqualTo("2016-01-15T12:00:00")); + }); reader.Read(); - Assert.AreEqual(17, reader["ID"]); - Assert.AreEqual("2016-01-05T12:00:00", ((DateTime)reader["SampleDate"]).ToString("s")); + Assert.Multiple(() => + { + Assert.That(reader["ID"], Is.EqualTo(17)); + Assert.That(((DateTime)reader["SampleDate"]).ToString("s"), Is.EqualTo("2016-01-05T12:00:00")); - Assert.IsFalse(reader.Read(), "Should only be three samples"); + Assert.That(reader.Read(), Is.False, "Should only be three samples"); + }); } cmd = new SqlCommand(@"SELECT * FROM Headers ORDER BY ID", connection); using (var reader = cmd.ExecuteReader()) { - Assert.IsTrue(reader.HasRows); + Assert.That(reader.HasRows); reader.Read(); - Assert.AreEqual(1, reader["ID"]); - Assert.AreEqual("Haematology", reader["Discipline"]); + Assert.Multiple(() => + { + Assert.That(reader["ID"], Is.EqualTo(1)); + Assert.That(reader["Discipline"], Is.EqualTo("Haematology")); + }); reader.Read(); - Assert.AreEqual(2, reader["ID"]); - Assert.AreEqual("Biochemistry", reader["Discipline"]); + Assert.Multiple(() => + { + Assert.That(reader["ID"], Is.EqualTo(2)); + Assert.That(reader["Discipline"], Is.EqualTo("Biochemistry")); + }); reader.Read(); - Assert.AreEqual(5, reader["ID"]); - Assert.AreEqual("Biochemistry", reader["Discipline"]); + Assert.Multiple(() => + { + Assert.That(reader["ID"], Is.EqualTo(5)); + Assert.That(reader["Discipline"], Is.EqualTo("Biochemistry")); - Assert.IsFalse(reader.Read(), "Should only be three headers"); + Assert.That(reader.Read(), Is.False, "Should only be three headers"); + }); } } } @@ -927,7 +945,7 @@ public void DeleteNewerCollisionsFromTable() var tiHeaders = AddHeaderTableToCatalogue(DatabaseName, ciSamples); // should be all entities set SetUp now - Assert.AreEqual(15, _catalogue.CatalogueItems.Length, "Unexpected number of items in catalogue"); + Assert.That(_catalogue.CatalogueItems, Has.Length.EqualTo(15), "Unexpected number of items in catalogue"); #endregion @@ -1020,11 +1038,11 @@ public void DeleteNewerCollisionsFromTable() var cmd = new SqlCommand(@"SELECT COUNT(*) FROM Header", connection); var numRows = cmd.ExecuteScalar(); - Assert.AreEqual(3, numRows, "Should be 3 header records"); + Assert.That(numRows, Is.EqualTo(3), "Should be 3 header records"); cmd = new SqlCommand(@"SELECT Discipline FROM Header WHERE ID=1", connection); var discipline = cmd.ExecuteScalar(); - Assert.AreEqual("Biochemistry", discipline, + Assert.That(discipline, Is.EqualTo("Biochemistry"), "The mutilator should **NOT** have updated record 1 from Biochemistry to Haematology. Although the load updates one of the To samples, the most recent To sample is later than the most recent loaded sample so the parent data in To takes precedence over the parent data in From."); // Not convinced about this test case @@ -1034,20 +1052,20 @@ public void DeleteNewerCollisionsFromTable() cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples WHERE ID = 2", connection); numRows = cmd.ExecuteScalar(); - Assert.AreEqual(0, numRows, "Sample ID = 2 has not been deleted"); + Assert.That(numRows, Is.EqualTo(0), "Sample ID = 2 has not been deleted"); cmd = new SqlCommand(@"SELECT COUNT(*) FROM Samples", connection); numRows = cmd.ExecuteScalar(); - Assert.AreEqual(2, numRows, + Assert.That(numRows, Is.EqualTo(2), "Sample ID = 2 has been deleted but something has happened to the other samples (should be untouched)"); cmd = new SqlCommand(@"SELECT COUNT(*) FROM Results WHERE SampleID = 2", connection); numRows = cmd.ExecuteScalar(); - Assert.AreEqual(0, numRows, "Results belonging to Sample ID = 2 have not been deleted"); + Assert.That(numRows, Is.EqualTo(0), "Results belonging to Sample ID = 2 have not been deleted"); cmd = new SqlCommand(@"SELECT COUNT(*) FROM Results", connection); numRows = cmd.ExecuteScalar(); - Assert.AreEqual(4, numRows, + Assert.That(numRows, Is.EqualTo(4), "Results belonging to Sample ID = 2 have been deleted but something has happeded to the other results (should be untouched)"); connection.Close(); diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CachedFileRetrieverTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CachedFileRetrieverTests.cs index b497712c1c..c3078e37db 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CachedFileRetrieverTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CachedFileRetrieverTests.cs @@ -73,9 +73,8 @@ public void AttemptToLoadDataWithFilesInForLoading_DisagreementBetweenCacheAndFo // Should fail after determining that the files in ForLoading do not match the job specification var ex = Assert.Throws(() => retriever.Fetch(job, new GracefulCancellationToken())); - Assert.IsTrue( - ex.Message.StartsWith( - "The files in ForLoading do not match what this job expects to be loading from the cache."), + Assert.That( + ex.Message, Does.StartWith("The files in ForLoading do not match what this job expects to be loading from the cache."), ex.Message + Environment.NewLine + Environment.NewLine + ex.StackTrace); } finally @@ -121,7 +120,7 @@ public void AttemptToLoadDataWithFilesInForLoading_AgreementBetweenForLoadingAnd retriever.Fetch(job, new GracefulCancellationToken()); // And ForLoading should still have the file in it (i.e. it hasn't mysteriously disappeared) - Assert.IsTrue(File.Exists(Path.Combine(loadDirectory.ForLoading.FullName, "2016-01-01.zip"))); + Assert.That(File.Exists(Path.Combine(loadDirectory.ForLoading.FullName, "2016-01-01.zip"))); } finally { @@ -164,7 +163,7 @@ public void AttemptToLoadDataWithoutFilesInForLoading() retriever.Fetch(job, new GracefulCancellationToken()); // And the retriever should have copied the cached archive file into ForLoading - Assert.IsTrue(File.Exists(Path.Combine(loadDirectory.ForLoading.FullName, "2016-01-01.zip"))); + Assert.That(File.Exists(Path.Combine(loadDirectory.ForLoading.FullName, "2016-01-01.zip"))); } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CheckingTests/ProcessTaskCheckingTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CheckingTests/ProcessTaskCheckingTests.cs index 335032c5ca..112d2aff06 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CheckingTests/ProcessTaskCheckingTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CheckingTests/ProcessTaskCheckingTests.cs @@ -70,7 +70,7 @@ public void EmptyFilePath(string path, ProcessTaskType typeThatRequiresFiles) _task.Path = path; _task.SaveToDatabase(); var ex = Assert.Throws(() => _checker.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.Contains("does not have a path specified", ex.Message); + Assert.That(ex.Message, Does.Contain("does not have a path specified")); } [Test] @@ -86,7 +86,7 @@ public void EmptyClassPath(string path, ProcessTaskType typeThatRequiresMEF, Loa _task.LoadStage = stage; _task.SaveToDatabase(); var ex = Assert.Throws(() => _checker.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.IsTrue(Regex.IsMatch(ex.Message, + Assert.That(Regex.IsMatch(ex.Message, "Path is blank for ProcessTask 'New Process.*' - it should be a class name of type")); } @@ -98,9 +98,8 @@ public void MEFIncompatibleType() _task.Path = typeof(object).ToString(); _task.SaveToDatabase(); var ex = Assert.Throws(() => _checker.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual( - "Requested typeToCreate 'System.Object' was not assignable to the required Type 'IMutilateDataTables'", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Requested typeToCreate 'System.Object' was not assignable to the required Type 'IMutilateDataTables'")); } [Test] @@ -116,8 +115,7 @@ public void MEFCompatibleType_NoProjectDirectory() _task.CreateArgumentsForClassIfNotExists(); var ex = Assert.Throws(() => _checker.Check(ThrowImmediatelyCheckNotifier.QuietPicky)); - Assert.AreEqual($@"No Project Directory (LocationOfFlatFiles) has been configured on LoadMetadata {_lmd.Name}", - ex.InnerException.Message); + Assert.That(ex.InnerException.Message, Is.EqualTo($@"No Project Directory (LocationOfFlatFiles) has been configured on LoadMetadata {_lmd.Name}")); } [Test] @@ -137,9 +135,8 @@ public void MEFCompatibleType_NoArgs() var ex = Assert.Throws(() => _checker.Check(ThrowImmediatelyCheckNotifier.QuietPicky)); - Assert.AreEqual( - @"Class AnySeparatorFileAttacher has a Mandatory property 'Separator' marked with DemandsInitialization but no corresponding argument was provided in ArgumentCollection", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo(@"Class AnySeparatorFileAttacher has a Mandatory property 'Separator' marked with DemandsInitialization but no corresponding argument was provided in ArgumentCollection")); } finally { @@ -188,7 +185,7 @@ public void MEFCompatibleType_Passes() Console.WriteLine(ExceptionHelper.ExceptionToListOfInnerMessages(msg.Ex)); } - Assert.AreEqual(CheckResult.Success, results.GetWorst()); + Assert.That(results.GetWorst(), Is.EqualTo(CheckResult.Success)); } finally { @@ -207,6 +204,6 @@ public void ImaginaryFile(string path) _task.Path = path; _task.SaveToDatabase(); var ex = Assert.Throws(() => _checker.Check(ThrowImmediatelyCheckNotifier.QuietPicky)); - StringAssert.Contains("bob.exe which does not exist at this time.", ex?.Message); + Assert.That(ex?.Message, Does.Contain("bob.exe which does not exist at this time.")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CoalescerTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CoalescerTests.cs index a267bc79f4..fa7181fc4a 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CoalescerTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CoalescerTests.cs @@ -114,10 +114,13 @@ public void TestCoalescer_RampantNullness(DatabaseType type, bool useCustomNamer foreach (DataRow row in dt2.Rows) { - Assert.AreNotEqual(DBNull.Value, row["f1"]); - Assert.AreNotEqual(DBNull.Value, row["f2"]); - Assert.AreNotEqual(DBNull.Value, row["f3"]); - Assert.AreNotEqual(DBNull.Value, row["f4"]); + Assert.Multiple(() => + { + Assert.That(row["f1"], Is.Not.EqualTo(DBNull.Value)); + Assert.That(row["f2"], Is.Not.EqualTo(DBNull.Value)); + Assert.That(row["f3"], Is.Not.EqualTo(DBNull.Value)); + Assert.That(row["f4"], Is.Not.EqualTo(DBNull.Value)); + }); } db.Drop(); diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/CrossDatabaseDataLoadTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/CrossDatabaseDataLoadTests.cs index 5fa6d848ba..bf0f2c1657 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/CrossDatabaseDataLoadTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/CrossDatabaseDataLoadTests.cs @@ -131,16 +131,15 @@ public void Load(DatabaseType databaseType, TestCase testCase) blk.Upload(dt); } - Assert.AreEqual(1, - tbl.DiscoverColumns().Count(c => - c.GetRuntimeName().Equals("ID", StringComparison.CurrentCultureIgnoreCase)), + Assert.That(tbl.DiscoverColumns().Count(c => + c.GetRuntimeName().Equals("ID", StringComparison.CurrentCultureIgnoreCase)), Is.EqualTo(1), "Table created did not contain ID column"); break; } case TestCase.AllPrimaryKeys: dt.PrimaryKey = dt.Columns.Cast().ToArray(); tbl = db.CreateTable("MyTable", dt, new[] { nameCol }); //upload the column as is - Assert.IsTrue(tbl.DiscoverColumns().All(c => c.IsPrimaryKey)); + Assert.That(tbl.DiscoverColumns().All(c => c.IsPrimaryKey)); break; default: tbl = db.CreateTable("MyTable", dt, new[] @@ -152,7 +151,7 @@ public void Load(DatabaseType databaseType, TestCase testCase) break; } - Assert.AreEqual(2, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(2)); //define a new load configuration var lmd = new LoadMetadata(CatalogueRepository, "MyLoad"); @@ -191,12 +190,13 @@ public void Load(DatabaseType databaseType, TestCase testCase) SetupLowPrivilegeUserRightsFor(db.Server.ExpectDatabase("DLE_STAGING"), TestLowPrivilegePermissions.All); } - Assert.AreEqual(testCase != TestCase.NoTrigger, - tbl.DiscoverColumns().Select(c => c.GetRuntimeName()).Contains(SpecialFieldNames.DataLoadRunID), - $"When running with NoTrigger there shouldn't be any additional columns added to table. Test case was {testCase}"); - Assert.AreEqual(testCase != TestCase.NoTrigger, - tbl.DiscoverColumns().Select(c => c.GetRuntimeName()).Contains(SpecialFieldNames.ValidFrom), - $"When running with NoTrigger there shouldn't be any additional columns added to table. Test case was {testCase}"); + Assert.Multiple(() => + { + Assert.That(tbl.DiscoverColumns().Select(c => c.GetRuntimeName()).Contains(SpecialFieldNames.DataLoadRunID), Is.EqualTo(testCase != TestCase.NoTrigger), + $"When running with NoTrigger there shouldn't be any additional columns added to table. Test case was {testCase}"); + Assert.That(tbl.DiscoverColumns().Select(c => c.GetRuntimeName()).Contains(SpecialFieldNames.ValidFrom), Is.EqualTo(testCase != TestCase.NoTrigger), + $"When running with NoTrigger there shouldn't be any additional columns added to table. Test case was {testCase}"); + }); var dbConfig = new HICDatabaseConfiguration(lmd, testCase == TestCase.WithCustomTableNamer ? new CustomINameDatabasesAndTablesDuringLoads() : null); @@ -226,62 +226,69 @@ public void Load(DatabaseType databaseType, TestCase testCase) ThrowImmediatelyDataLoadEventListener.Quiet, dbConfig), new GracefulCancellationToken()); - Assert.AreEqual(ExitCodeType.Success, exitCode); + Assert.That(exitCode, Is.EqualTo(ExitCodeType.Success)); if (testCase == TestCase.AllPrimaryKeys) { - Assert.AreEqual(4, tbl.GetRowCount()); //Bob, Frank, Frank (with also pk Neon) & MrMurder + Assert.That(tbl.GetRowCount(), Is.EqualTo(4)); //Bob, Frank, Frank (with also pk Neon) & MrMurder Assert.Pass(); } if (testCase == TestCase.WithDiffColumnIgnoreRegex) { - Assert.AreEqual(3, tbl.GetRowCount()); //Bob, Frank (original since the diff was skipped), & MrMurder + Assert.That(tbl.GetRowCount(), Is.EqualTo(3)); //Bob, Frank (original since the diff was skipped), & MrMurder //frank should be updated to like Neon instead of Orange - Assert.AreEqual(3, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(3)); var frankOld = tbl.GetDataTable().Rows.Cast().Single(r => (string)r["Name"] == "Frank"); - Assert.AreEqual("Orange", frankOld["FavouriteColour"]); + Assert.That(frankOld["FavouriteColour"], Is.EqualTo("Orange")); Assert.Pass(); } //frank should be updated to like Neon instead of Orange - Assert.AreEqual(3, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(3)); var result = tbl.GetDataTable(); var frank = result.Rows.Cast().Single(r => (string)r["Name"] == "Frank"); - Assert.AreEqual("Neon", frank["FavouriteColour"]); + Assert.That(frank["FavouriteColour"], Is.EqualTo("Neon")); if (testCase != TestCase.NoTrigger) AssertHasDataLoadRunId(frank); //MrMurder is a new person who likes Yella var mrmurder = result.Rows.Cast().Single(r => (string)r["Name"] == "MrMurder"); - Assert.AreEqual("Yella", mrmurder["FavouriteColour"]); - Assert.AreEqual(new DateTime(2001, 01, 01), mrmurder["DateOfBirth"]); + Assert.Multiple(() => + { + Assert.That(mrmurder["FavouriteColour"], Is.EqualTo("Yella")); + Assert.That(mrmurder["DateOfBirth"], Is.EqualTo(new DateTime(2001, 01, 01))); + }); if (testCase != TestCase.NoTrigger) AssertHasDataLoadRunId(mrmurder); //bob should be untouched (same values as before and no dataloadrunID) var bob = result.Rows.Cast().Single(r => (string)r["Name"] == "Bob"); - Assert.AreEqual("Pink", bob["FavouriteColour"]); - Assert.AreEqual(new DateTime(2001, 01, 01), bob["DateOfBirth"]); + Assert.Multiple(() => + { + Assert.That(bob["FavouriteColour"], Is.EqualTo("Pink")); + Assert.That(bob["DateOfBirth"], Is.EqualTo(new DateTime(2001, 01, 01))); + }); if (testCase != TestCase.NoTrigger) { - Assert.AreEqual(DBNull.Value, bob[SpecialFieldNames.DataLoadRunID]); + Assert.That(bob[SpecialFieldNames.DataLoadRunID], Is.EqualTo(DBNull.Value)); //MySql add default of now() on a table will auto populate all the column values with the the now() date while Sql Server will leave them as nulls if (databaseType == DatabaseType.MicrosoftSQLServer) - Assert.AreEqual(DBNull.Value, bob[SpecialFieldNames.ValidFrom]); + Assert.That(bob[SpecialFieldNames.ValidFrom], Is.EqualTo(DBNull.Value)); } - Assert.AreEqual(testCase != TestCase.NoTrigger, - tbl.DiscoverColumns().Select(c => c.GetRuntimeName()).Contains(SpecialFieldNames.DataLoadRunID), - $"When running with NoTrigger there shouldn't be any additional columns added to table. Test case was {testCase}"); - Assert.AreEqual(testCase != TestCase.NoTrigger, - tbl.DiscoverColumns().Select(c => c.GetRuntimeName()).Contains(SpecialFieldNames.ValidFrom), - $"When running with NoTrigger there shouldn't be any additional columns added to table. Test case was {testCase}"); + Assert.Multiple(() => + { + Assert.That(tbl.DiscoverColumns().Select(c => c.GetRuntimeName()).Contains(SpecialFieldNames.DataLoadRunID), Is.EqualTo(testCase != TestCase.NoTrigger), + $"When running with NoTrigger there shouldn't be any additional columns added to table. Test case was {testCase}"); + Assert.That(tbl.DiscoverColumns().Select(c => c.GetRuntimeName()).Contains(SpecialFieldNames.ValidFrom), Is.EqualTo(testCase != TestCase.NoTrigger), + $"When running with NoTrigger there shouldn't be any additional columns added to table. Test case was {testCase}"); + }); } finally { @@ -365,8 +372,11 @@ public void DLELoadTwoTables(DatabaseType databaseType) var childTbl = db.CreateTable(args); - Assert.AreEqual(1, parentTbl.GetRowCount()); - Assert.AreEqual(2, childTbl.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(parentTbl.GetRowCount(), Is.EqualTo(1)); + Assert.That(childTbl.GetRowCount(), Is.EqualTo(2)); + }); //create a new load var lmd = new LoadMetadata(CatalogueRepository, "MyLoading2"); @@ -416,29 +426,37 @@ public void DLELoadTwoTables(DatabaseType databaseType) ThrowImmediatelyDataLoadEventListener.Quiet, config), new GracefulCancellationToken()); - Assert.AreEqual(ExitCodeType.Success, exitCode); + Assert.Multiple(() => + { + Assert.That(exitCode, Is.EqualTo(ExitCodeType.Success)); - //should now be 2 parents (the original - who was updated) + 1 new one (Man2) - Assert.AreEqual(2, parentTbl.GetRowCount()); + //should now be 2 parents (the original - who was updated) + 1 new one (Man2) + Assert.That(parentTbl.GetRowCount(), Is.EqualTo(2)); + }); var result = parentTbl.GetDataTable(); var dave = result.Rows.Cast().Single(r => (string)r["Name"] == "Dave"); - Assert.AreEqual(3.2f, dave["Height"]); //should now be only 3.2 inches high + Assert.That(dave["Height"], Is.EqualTo(3.2f)); //should now be only 3.2 inches high AssertHasDataLoadRunId(dave); //should be 3 children (Child1 who gets updated to be called UpdC1) and NewC1 - Assert.AreEqual(3, childTbl.GetRowCount()); + Assert.That(childTbl.GetRowCount(), Is.EqualTo(3)); result = childTbl.GetDataTable(); var updC1 = result.Rows.Cast().Single(r => (string)r["Name"] == "UpdC1"); - Assert.AreEqual(1, updC1["Parent_ID"]); - Assert.AreEqual(1, updC1["ChildNumber"]); + Assert.Multiple(() => + { + Assert.That(updC1["Parent_ID"], Is.EqualTo(1)); + Assert.That(updC1["ChildNumber"], Is.EqualTo(1)); + }); AssertHasDataLoadRunId(updC1); var newC1 = result.Rows.Cast().Single(r => (string)r["Name"] == "NewC1"); - Assert.AreEqual(2, newC1["Parent_ID"]); - Assert.AreEqual(1, newC1["ChildNumber"]); - Assert.AreEqual(DBNull.Value, - newC1["Height"]); //the "null" in the input file should be DBNull.Value in the final database + Assert.Multiple(() => + { + Assert.That(newC1["Parent_ID"], Is.EqualTo(2)); + Assert.That(newC1["ChildNumber"], Is.EqualTo(1)); + Assert.That(newC1["Height"], Is.EqualTo(DBNull.Value)); //the "null" in the input file should be DBNull.Value in the final database + }); AssertHasDataLoadRunId(newC1); } finally diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/CrossDatabaseMergeCommandTest.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/CrossDatabaseMergeCommandTest.cs index 8ab992b6f5..4be06938e6 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/CrossDatabaseMergeCommandTest.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/CrossDatabaseMergeCommandTest.cs @@ -54,9 +54,12 @@ public void TestMerge(DatabaseType databaseType) var toTbl = To.CreateTable("ToTable", dt); - Assert.IsTrue(toTbl.DiscoverColumn("Name").IsPrimaryKey); - Assert.IsTrue(toTbl.DiscoverColumn("Age").IsPrimaryKey); - Assert.IsFalse(toTbl.DiscoverColumn("Postcode").IsPrimaryKey); + Assert.Multiple(() => + { + Assert.That(toTbl.DiscoverColumn("Name").IsPrimaryKey); + Assert.That(toTbl.DiscoverColumn("Age").IsPrimaryKey); + Assert.That(toTbl.DiscoverColumn("Postcode").IsPrimaryKey, Is.False); + }); dt.Rows.Clear(); @@ -102,7 +105,7 @@ public void TestMerge(DatabaseType databaseType) migrationHost.Migrate(job, new GracefulCancellationToken()); var resultantDt = toTbl.GetDataTable(); - Assert.AreEqual(7, resultantDt.Rows.Count); + Assert.That(resultantDt.Rows, Has.Count.EqualTo(7)); AssertRowEquals(resultantDt, "Dave", 25, "DD1 1PS"); AssertRowEquals(resultantDt, "Chutney", 32, DBNull.Value); @@ -118,18 +121,19 @@ public void TestMerge(DatabaseType databaseType) var archival = logManager.GetArchivalDataLoadInfos("CrossDatabaseMergeCommandTest", new CancellationToken()); var log = archival.First(); - - Assert.AreEqual(dli.ID, log.ID); - Assert.AreEqual(2, log.TableLoadInfos.Single().Inserts); - Assert.AreEqual(3, log.TableLoadInfos.Single().Updates); + Assert.Multiple(() => + { + Assert.That(log.ID, Is.EqualTo(dli.ID)); + Assert.That(log.TableLoadInfos.Single().Inserts, Is.EqualTo(2)); + Assert.That(log.TableLoadInfos.Single().Updates, Is.EqualTo(3)); + }); } private static void AssertRowEquals(DataTable resultantDt, string name, int age, object postcode) { - Assert.AreEqual( - 1, + Assert.That( resultantDt.Rows.Cast().Count(r => - Equals(r["Name"], name) && Equals(r["Age"], age) && Equals(r["Postcode"], postcode)), + Equals(r["Name"], name) && Equals(r["Age"], age) && Equals(r["Postcode"], postcode)), Is.EqualTo(1), "Did not find expected record:" + string.Join(",", name, age, postcode)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/HowDoWeAchieveMd5Test.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/HowDoWeAchieveMd5Test.cs index d824f8b095..94a9e00580 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/HowDoWeAchieveMd5Test.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/CrossDatabaseTypeTests/HowDoWeAchieveMd5Test.cs @@ -39,9 +39,9 @@ public void TestMd5String(DatabaseType type) Console.WriteLine($"Value was:{value}"); - Assert.IsNotNull(value); - Assert.AreNotEqual("Fish", value); - Assert.GreaterOrEqual(value.ToString().Length, 32); + Assert.That(value, Is.Not.Null); + Assert.That(value, Is.Not.EqualTo("Fish")); + Assert.That(value.ToString(), Has.Length.GreaterThanOrEqualTo(32)); } [TestCase(DatabaseType.MicrosoftSQLServer)] @@ -58,8 +58,7 @@ public void TestMd5Date(DatabaseType type) var col = tbl.DiscoverColumn("F"); - Assert.AreEqual(typeof(DateTime), - tbl.GetQuerySyntaxHelper().TypeTranslater.GetCSharpTypeForSQLDBType(col.DataType.SQLType)); + Assert.That(tbl.GetQuerySyntaxHelper().TypeTranslater.GetCSharpTypeForSQLDBType(col.DataType.SQLType), Is.EqualTo(typeof(DateTime))); var sql = @@ -74,7 +73,7 @@ public void TestMd5Date(DatabaseType type) Console.WriteLine($"Value was:{value}"); - Assert.IsNotNull(value); - Assert.GreaterOrEqual(value.ToString().Length, 32); + Assert.That(value, Is.Not.Null); + Assert.That(value.ToString(), Has.Length.GreaterThanOrEqualTo(32)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataLoadEngineTestsBase.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataLoadEngineTestsBase.cs index 073179f22d..7d20e0201f 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataLoadEngineTestsBase.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataLoadEngineTestsBase.cs @@ -29,18 +29,24 @@ protected static void AssertHasDataLoadRunId(DataRow row) { var o = row[SpecialFieldNames.DataLoadRunID]; - Assert.IsNotNull(o, "A row which was expected to have a hic_dataLoadRunID had null instead"); - Assert.AreNotEqual(DBNull.Value, o, - "A row which was expected to have a hic_dataLoadRunID had DBNull.Value instead"); - Assert.GreaterOrEqual((int)o, 0); + Assert.That(o, Is.Not.Null, "A row which was expected to have a hic_dataLoadRunID had null instead"); + Assert.Multiple(() => + { + Assert.That(o, Is.Not.EqualTo(DBNull.Value), + "A row which was expected to have a hic_dataLoadRunID had DBNull.Value instead"); + Assert.That((int)o, Is.GreaterThanOrEqualTo(0)); + }); var d = row[SpecialFieldNames.ValidFrom]; - Assert.IsNotNull(d, "A row which was expected to have a hic_validFrom had null instead"); - Assert.AreNotEqual(DBNull.Value, d, - "A row which was expected to have a hic_validFrom had DBNull.Value instead"); + Assert.That(d, Is.Not.Null, "A row which was expected to have a hic_validFrom had null instead"); + Assert.Multiple(() => + { + Assert.That(d, Is.Not.EqualTo(DBNull.Value), + "A row which was expected to have a hic_validFrom had DBNull.Value instead"); - //expect validFrom to be after 2 hours ago (to handle UTC / BST nonsense) - Assert.GreaterOrEqual((DateTime)d, DateTime.Now.Subtract(new TimeSpan(2, 0, 0))); + //expect validFrom to be after 2 hours ago (to handle UTC / BST nonsense) + Assert.That((DateTime)d, Is.GreaterThanOrEqualTo(DateTime.Now.Subtract(new TimeSpan(2, 0, 0)))); + }); } protected void CreateCSVProcessTask(LoadMetadata lmd, ITableInfo ti, string regex) @@ -87,7 +93,7 @@ protected ITableInfo Import(DiscoveredTable tbl, LoadMetadata lmd, LogManager lo //make the catalogue use the load configuration cata.LoadMetadata_ID = lmd.ID; cata.LoggingDataTask = lmd.Name; - Assert.IsNotNull(cata.LiveLoggingServer_ID); //catalogue should have one of these because of system defaults + Assert.That(cata.LiveLoggingServer_ID, Is.Not.Null); //catalogue should have one of these because of system defaults cata.SaveToDatabase(); return ti; diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataLoadProgressUpdateInfoTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataLoadProgressUpdateInfoTests.cs index 65034cc993..8bfade42a4 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataLoadProgressUpdateInfoTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataLoadProgressUpdateInfoTests.cs @@ -46,14 +46,14 @@ public void AddBasicNormalStrategy_NoDates() { var updateInfo = new DataLoadProgressUpdateInfo(); var ex = Assert.Throws(() => updateInfo.AddAppropriateDisposeStep(_job, null)); - Assert.IsTrue(ex.Message.StartsWith("Job does not have any DatesToRetrieve")); + Assert.That(ex.Message, Does.StartWith("Job does not have any DatesToRetrieve")); } [Test] public void AddBasicNormalStrategy_MaxDate() { var updateInfo = new DataLoadProgressUpdateInfo(); - Assert.AreEqual(DataLoadProgressUpdateStrategy.UseMaxRequestedDay, updateInfo.Strategy); + Assert.That(updateInfo.Strategy, Is.EqualTo(DataLoadProgressUpdateStrategy.UseMaxRequestedDay)); _job.DatesToRetrieve = new List { @@ -66,7 +66,7 @@ public void AddBasicNormalStrategy_MaxDate() var added = (UpdateProgressIfLoadsuccessful)updateInfo.AddAppropriateDisposeStep(_job, null); - Assert.AreEqual(new DateTime(2001, 1, 3), added.DateToSetProgressTo); + Assert.That(added.DateToSetProgressTo, Is.EqualTo(new DateTime(2001, 1, 3))); } finally { @@ -85,7 +85,7 @@ public void AddRAWSQLStrategy_NoSQL() var ex = Assert.Throws(() => updateInfo.AddAppropriateDisposeStep(_job, GetCleanedServer(FAnsi.DatabaseType.MicrosoftSQLServer))); - Assert.IsTrue(ex.Message.StartsWith("Strategy is ExecuteScalarSQLInRAW but there is no ExecuteScalarSQL")); + Assert.That(ex.Message, Does.StartWith("Strategy is ExecuteScalarSQLInRAW but there is no ExecuteScalarSQL")); } [Test] @@ -100,8 +100,11 @@ public void AddRAWSQLStrategy_SQLDodgy_SqlCrashes() var ex = Assert.Throws(() => updateInfo.AddAppropriateDisposeStep(_job, GetCleanedServer(FAnsi.DatabaseType.MicrosoftSQLServer))); - Assert.IsTrue(ex.Message.StartsWith("Failed to execute the following SQL in the RAW database")); - Assert.IsInstanceOf(ex.InnerException); + Assert.Multiple(() => + { + Assert.That(ex.Message, Does.StartWith("Failed to execute the following SQL in the RAW database")); + Assert.That(ex.InnerException, Is.InstanceOf()); + }); } [Test] @@ -116,8 +119,8 @@ public void AddRAWSQLStrategy_SQLDodgy_SqlReturnsNull() var ex = Assert.Throws(() => updateInfo.AddAppropriateDisposeStep(_job, GetCleanedServer(FAnsi.DatabaseType.MicrosoftSQLServer))); - Assert.IsTrue(ex.Message.Contains("ExecuteScalarSQL")); - Assert.IsTrue(ex.Message.Contains("returned null")); + Assert.That(ex.Message, Does.Contain("ExecuteScalarSQL")); + Assert.That(ex.Message, Does.Contain("returned null")); } [Test] @@ -132,10 +135,12 @@ public void AddRAWSQLStrategy_SQLDodgy_SqlReturnsNonDate() var ex = Assert.Throws(() => updateInfo.AddAppropriateDisposeStep(_job, GetCleanedServer(FAnsi.DatabaseType.MicrosoftSQLServer))); - Assert.AreEqual( - "ExecuteScalarSQL specified for determining the maximum date of data loaded returned a value that was not a Date:fishfish", - ex.Message); - Assert.IsInstanceOf(ex.InnerException); + Assert.Multiple(() => + { + Assert.That( + ex.Message, Is.EqualTo("ExecuteScalarSQL specified for determining the maximum date of data loaded returned a value that was not a Date:fishfish")); + Assert.That(ex.InnerException, Is.InstanceOf()); + }); } [Test] @@ -157,7 +162,7 @@ public void AddRAWSQLStrategy_SQLCorrect() var added = (UpdateProgressIfLoadsuccessful)updateInfo.AddAppropriateDisposeStep(_job, GetCleanedServer(FAnsi.DatabaseType.MicrosoftSQLServer)); - Assert.AreEqual(new DateTime(2001, 1, 7), added.DateToSetProgressTo); + Assert.That(added.DateToSetProgressTo, Is.EqualTo(new DateTime(2001, 1, 7))); _job.DatesToRetrieve.Clear(); } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataTableUploadDestinationTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataTableUploadDestinationTests.cs index ec66d9e732..17a8f8d52c 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataTableUploadDestinationTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DataTableUploadDestinationTests.cs @@ -49,8 +49,8 @@ public void DataTableChangesLengths_NoReAlter() var expectedText = "BulkInsert failed on data row 1 the complaint was about source column <> which had value <> destination data type was <>"; - Assert.IsNotNull(ex.InnerException); - StringAssert.Contains(expectedText, ex.InnerException.Message); + Assert.That(ex.InnerException, Is.Not.Null); + Assert.That(ex.InnerException.Message, Does.Contain(expectedText)); destination.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, ex); } @@ -150,7 +150,7 @@ public void DataTableChangesLengths_RandomColumnOrder(bool createIdentity, int n var expectedErrorMessage = $"<<{errorColumn}>> which had value <<{dt1.Rows[0][errorColumn]}>> destination data type was <>"; - StringAssert.Contains(expectedErrorMessage, interestingBit); + Assert.That(interestingBit, Does.Contain(expectedErrorMessage)); destination.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, ex); tbl.Drop(); @@ -209,7 +209,7 @@ ALTER TABLE DroppedColumnsTable add color varchar(1) const string expectedErrorMessage = "<> which had value <> destination data type was <>"; - StringAssert.Contains(expectedErrorMessage, interestingBit); + Assert.That(interestingBit, Does.Contain(expectedErrorMessage)); destination.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, ex); @@ -235,7 +235,7 @@ public void DataTableEmpty_ThrowHelpfulException() destination.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, ex); - Assert.AreEqual("DataTable 'MyEmptyTable' had no Columns!", ex.Message); + Assert.That(ex.Message, Is.EqualTo("DataTable 'MyEmptyTable' had no Columns!")); } [Test] @@ -255,7 +255,7 @@ public void DataTableNoRows_ThrowHelpfulException() destination.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, ex); - Assert.AreEqual("DataTable 'MyEmptyTable' had no Rows!", ex.Message); + Assert.That(ex.Message, Is.EqualTo("DataTable 'MyEmptyTable' had no Rows!")); } [Test] @@ -283,11 +283,14 @@ public void DataTableChangesLengths_AllowAlter() destination.ProcessPipelineData(dt1, toConsole, token); Assert.DoesNotThrow(() => destination.ProcessPipelineData(dt2, toMemory, token)); - Assert.IsTrue(toMemory.EventsReceivedBySender[destination].Any(msg => msg.Message.Contains("Resizing column"))); + Assert.That(toMemory.EventsReceivedBySender[destination].Any(msg => msg.Message.Contains("Resizing column"))); destination.Dispose(toConsole, null); - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - Assert.AreEqual(2, db.ExpectTable("DataTableUploadDestinationTests").GetRowCount()); + Assert.Multiple(() => + { + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").GetRowCount(), Is.EqualTo(2)); + }); } [Test] @@ -314,10 +317,12 @@ public void DoubleResizingBetweenIntAndDouble() destination.ProcessPipelineData(dt1, toConsole, token); destination.Dispose(toConsole, null); - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - Assert.AreEqual(5, db.ExpectTable("DataTableUploadDestinationTests").GetRowCount()); - Assert.AreEqual("decimal(3,1)", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mynum").DataType.SQLType); + Assert.Multiple(() => + { + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").GetRowCount(), Is.EqualTo(5)); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mynum").DataType.SQLType, Is.EqualTo("decimal(3,1)")); + }); } @@ -355,8 +360,7 @@ public void BatchResizing(string expectedDatatypeInDatabase, object batch1Value, throw; } - Assert.AreEqual(expectedDatatypeInDatabase, - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mycol").DataType.SQLType); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mycol").DataType.SQLType, Is.EqualTo(expectedDatatypeInDatabase)); } [TestCase("varchar(24)", "2", "987styb4ih0r9h4322938476", "tinyint")] @@ -394,8 +398,7 @@ public void BatchResizing_WithExplicitWriteTypes(string expectedDatatypeInDataba throw; } - Assert.AreEqual(expectedDatatypeInDatabase, - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mycol").DataType.SQLType); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mycol").DataType.SQLType, Is.EqualTo(expectedDatatypeInDatabase)); } [Test] @@ -425,10 +428,12 @@ public void VeryLongStringIsVarcharMax() destination.ProcessPipelineData(dt1, toConsole, token); destination.Dispose(toConsole, null); - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - Assert.AreEqual(1, db.ExpectTable("DataTableUploadDestinationTests").GetRowCount()); - Assert.AreEqual("varchar(max)", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("myText").DataType.SQLType); + Assert.Multiple(() => + { + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").GetRowCount(), Is.EqualTo(1)); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("myText").DataType.SQLType, Is.EqualTo("varchar(max)")); + }); } [Test] @@ -463,14 +468,16 @@ public void DecimalResizing(bool negative) destination.ProcessPipelineData(dt1, toConsole, token); destination.ProcessPipelineData(dt2, toMemory, token); - Assert.IsTrue(toMemory.EventsReceivedBySender[destination] + Assert.That(toMemory.EventsReceivedBySender[destination] .Any(msg => msg.Message.Contains("Resizing column "))); destination.Dispose(toConsole, null); - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - Assert.AreEqual(7, db.ExpectTable("DataTableUploadDestinationTests").GetRowCount()); - Assert.AreEqual("decimal(5,2)", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mynum").DataType.SQLType); + Assert.Multiple(() => + { + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").GetRowCount(), Is.EqualTo(7)); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mynum").DataType.SQLType, Is.EqualTo("decimal(5,2)")); + }); } private static object[] _sourceLists = @@ -520,9 +527,11 @@ public void DataTypeEstimation(string expectedDatatypeInDatabase, object[] rowVa destination.ProcessPipelineData(dt1, toConsole, token); destination.Dispose(toConsole, null); - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - Assert.AreEqual(expectedDatatypeInDatabase, - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("myCol").DataType.SQLType); + Assert.Multiple(() => + { + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("myCol").DataType.SQLType, Is.EqualTo(expectedDatatypeInDatabase)); + }); using var con = db.Server.GetConnection(); con.Open(); @@ -530,8 +539,11 @@ public void DataTypeEstimation(string expectedDatatypeInDatabase, object[] rowVa using var r = cmd.ExecuteReader(); foreach (var e in expectedValuesReadFromDatabase) { - Assert.IsTrue(r.Read()); - Assert.AreEqual(e, r["myCol"]); + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["myCol"], Is.EqualTo(e)); + }); } } @@ -561,16 +573,18 @@ public void DecimalZeros(bool sendTheZero) destination.ProcessPipelineData(dt1, toConsole, token); destination.Dispose(toConsole, null); - //table should exist - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.Multiple(() => + { + //table should exist + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - //should have 2 rows - Assert.AreEqual(sendTheZero ? 2 : 1, db.ExpectTable("DataTableUploadDestinationTests").GetRowCount()); + //should have 2 rows + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").GetRowCount(), Is.EqualTo(sendTheZero ? 2 : 1)); - //should be decimal + //should be decimal - Assert.AreEqual(sendTheZero ? "decimal(19,18)" : "decimal(18,18)", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mynum").DataType.SQLType); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mynum").DataType.SQLType, Is.EqualTo(sendTheZero ? "decimal(19,18)" : "decimal(18,18)")); + }); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -594,37 +608,45 @@ public void TestResizing(DatabaseType dbType) con.Open(); //should not allow nulls before - Assert.AreEqual(false, table.DiscoverColumn("StringNotNull").AllowNulls); + Assert.That(table.DiscoverColumn("StringNotNull").AllowNulls, Is.EqualTo(false)); //do resize table.DiscoverColumn("StringNotNull").DataType.Resize(500); //rediscover it to get the new state in database (it should now be 500 and still shouldn't allow nulls) AssertIsStringWithLength(table.DiscoverColumn("StringNotNull"), 500); + Assert.Multiple(() => + { + Assert.That(table.DiscoverColumn("StringNotNull").AllowNulls, Is.EqualTo(false)); - Assert.AreEqual(false, table.DiscoverColumn("StringNotNull").AllowNulls); - - //do the same with the one that allows nulls - Assert.AreEqual(true, table.DiscoverColumn("StringAllowNull").AllowNulls); + //do the same with the one that allows nulls + Assert.That(table.DiscoverColumn("StringAllowNull").AllowNulls, Is.EqualTo(true)); + }); table.DiscoverColumn("StringAllowNull").DataType.Resize(101); table.DiscoverColumn("StringAllowNull").DataType.Resize(103); table.DiscoverColumn("StringAllowNull").DataType.Resize(105); AssertIsStringWithLength(table.DiscoverColumn("StringAllowNull"), 105); - Assert.AreEqual(true, table.DiscoverColumn("StringAllowNull").AllowNulls); + Assert.That(table.DiscoverColumn("StringAllowNull").AllowNulls, Is.EqualTo(true)); //we should have correct understanding prior to resize AssertIsStringWithLength(table.DiscoverColumn("StringPk"), 50); - Assert.AreEqual(true, table.DiscoverColumn("StringPk").IsPrimaryKey); - Assert.AreEqual(false, table.DiscoverColumn("StringPk").AllowNulls); + Assert.Multiple(() => + { + Assert.That(table.DiscoverColumn("StringPk").IsPrimaryKey, Is.EqualTo(true)); + Assert.That(table.DiscoverColumn("StringPk").AllowNulls, Is.EqualTo(false)); + }); //now we execute the resize table.DiscoverColumn("StringPk").DataType.Resize(500); AssertIsStringWithLength(table.DiscoverColumn("StringPk"), 500); - Assert.AreEqual(true, table.DiscoverColumn("StringPk").IsPrimaryKey); - Assert.AreEqual(false, table.DiscoverColumn("StringPk").AllowNulls); + Assert.Multiple(() => + { + Assert.That(table.DiscoverColumn("StringPk").IsPrimaryKey, Is.EqualTo(true)); + Assert.That(table.DiscoverColumn("StringPk").AllowNulls, Is.EqualTo(false)); + }); con.Close(); } @@ -635,13 +657,13 @@ private static void AssertIsStringWithLength(DiscoveredColumn col, int expectedL { case DatabaseType.MicrosoftSQLServer: case DatabaseType.MySql: - Assert.AreEqual($"varchar({expectedLength})", col.DataType.SQLType); + Assert.That(col.DataType.SQLType, Is.EqualTo($"varchar({expectedLength})")); break; case DatabaseType.Oracle: - Assert.AreEqual($"varchar2({expectedLength})", col.DataType.SQLType); + Assert.That(col.DataType.SQLType, Is.EqualTo($"varchar2({expectedLength})")); break; case DatabaseType.PostgreSql: - Assert.AreEqual($"character varying({expectedLength})", col.DataType.SQLType); + Assert.That(col.DataType.SQLType, Is.EqualTo($"character varying({expectedLength})")); break; default: throw new ArgumentOutOfRangeException(nameof(col.Table.Database.Server.DatabaseType), @@ -665,7 +687,7 @@ public void TestResizing_WithDetection(DatabaseType dbType) new("StringPk", new DatabaseTypeRequest(typeof(string), 50), true) { IsPrimaryKey = true } }); - Assert.AreEqual(10, table.DiscoverColumn("StringNotNull").DataType.GetLengthIfString()); + Assert.That(table.DiscoverColumn("StringNotNull").DataType.GetLengthIfString(), Is.EqualTo(10)); var dt = new DataTable("TestResizing"); dt.Columns.Add("MyInteger"); @@ -704,7 +726,7 @@ public void TestResizing_WithDetection(DatabaseType dbType) dest.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, null); //it should have resized us. - Assert.AreEqual(14, table.DiscoverColumn("StringNotNull").DataType.GetLengthIfString()); + Assert.That(table.DiscoverColumn("StringNotNull").DataType.GetLengthIfString(), Is.EqualTo(14)); } [TestCase(DatabaseType.MicrosoftSQLServer, "didn�t")] @@ -730,8 +752,11 @@ public void Test_SingleQuote_InText(DatabaseType dbType, string testValue) dest.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, null); var tbl = db.ExpectTable("TestFreeText"); - Assert.IsTrue(tbl.Exists()); - Assert.AreEqual(1, tbl.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(tbl.Exists()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(1)); + }); } [Test] @@ -760,24 +785,22 @@ public void DodgyTypes() destination.ProcessPipelineData(dt1, toConsole, token); destination.Dispose(toConsole, null); - //table should exist - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.Multiple(() => + { + //table should exist + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - //should have 2 rows - Assert.AreEqual(1, db.ExpectTable("DataTableUploadDestinationTests").GetRowCount()); + //should have 2 rows + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").GetRowCount(), Is.EqualTo(1)); - //should be decimal - Assert.AreEqual("decimal(3,3)", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("col1").DataType.SQLType); - Assert.AreEqual("decimal(3,3)", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("col2").DataType.SQLType); - Assert.AreEqual("bit", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("col3").DataType.SQLType); - Assert.AreEqual("tinyint", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("col4").DataType.SQLType); + //should be decimal + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("col1").DataType.SQLType, Is.EqualTo("decimal(3,3)")); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("col2").DataType.SQLType, Is.EqualTo("decimal(3,3)")); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("col3").DataType.SQLType, Is.EqualTo("bit")); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("col4").DataType.SQLType, Is.EqualTo("tinyint")); - Assert.AreEqual("varbinary(max)", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("col5").DataType.SQLType); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("col5").DataType.SQLType, Is.EqualTo("varbinary(max)")); + }); } @@ -806,14 +829,16 @@ public void TypeAlteringlResizing() destination.ProcessPipelineData(dt1, toConsole, token); destination.ProcessPipelineData(dt2, toMemory, token); - Assert.IsTrue(toMemory.EventsReceivedBySender[destination] + Assert.That(toMemory.EventsReceivedBySender[destination] .Any(msg => msg.Message.Contains("Resizing column 'mynum' from 'bit' to 'int'"))); destination.Dispose(toConsole, null); - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - Assert.AreEqual(2, db.ExpectTable("DataTableUploadDestinationTests").GetRowCount()); - Assert.AreEqual("int", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mynum").DataType.SQLType); + Assert.Multiple(() => + { + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").GetRowCount(), Is.EqualTo(2)); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("mynum").DataType.SQLType, Is.EqualTo("int")); + }); } [Test] @@ -848,21 +873,27 @@ public void MySqlTest_Simple() destination.Dispose(toConsole, null); var tbl = db.ExpectTable("DataTableUploadDestinationTests"); - Assert.IsTrue(tbl.Exists()); - Assert.AreEqual(1, tbl.GetRowCount()); - Assert.AreEqual("int", tbl.DiscoverColumn("mynum").DataType.SQLType); + Assert.Multiple(() => + { + Assert.That(tbl.Exists()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(1)); + Assert.That(tbl.DiscoverColumn("mynum").DataType.SQLType, Is.EqualTo("int")); + }); using (var con = db.Server.GetConnection()) { con.Open(); var r = db.Server.GetCommand(tbl.GetTopXSql(10), con).ExecuteReader(); - Assert.IsTrue(r.Read()); - Assert.AreEqual("Anhoy there \"mates\"", (string)r["mystringcol"]); - Assert.AreEqual(999, (int)r["mynum"]); - Assert.AreEqual(new DateTime(2001, 1, 1), (DateTime)r["mydate"]); - Assert.AreEqual(now, (DateTime)r["myLegitDateTime"]); - Assert.AreEqual(DBNull.Value, r["mynullcol"]); + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That((string)r["mystringcol"], Is.EqualTo("Anhoy there \"mates\"")); + Assert.That((int)r["mynum"], Is.EqualTo(999)); + Assert.That((DateTime)r["mydate"], Is.EqualTo(new DateTime(2001, 1, 1))); + Assert.That((DateTime)r["myLegitDateTime"], Is.EqualTo(now)); + Assert.That(r["mynullcol"], Is.EqualTo(DBNull.Value)); + }); } db.Drop(); @@ -897,9 +928,12 @@ public void MySqlTest_Resize() destination.Dispose(toConsole, null); var tbl = db.ExpectTable("DataTableUploadDestinationTests"); - Assert.IsTrue(tbl.Exists()); - Assert.AreEqual(2, tbl.GetRowCount()); - Assert.AreEqual("int", tbl.DiscoverColumn("mynum").DataType.SQLType); + Assert.Multiple(() => + { + Assert.That(tbl.Exists()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(2)); + Assert.That(tbl.DiscoverColumn("mynum").DataType.SQLType, Is.EqualTo("int")); + }); using var con = db.Server.GetConnection(); con.Open(); @@ -907,14 +941,17 @@ public void MySqlTest_Resize() //technically these can come out in a random order var numbersRead = new List(); - Assert.IsTrue(r.Read()); + Assert.That(r.Read()); numbersRead.Add((int)r["mynum"]); - Assert.IsTrue(r.Read()); + Assert.That(r.Read()); numbersRead.Add((int)r["mynum"]); - Assert.IsFalse(r.Read()); - Assert.IsTrue(numbersRead.Contains(1)); - Assert.IsTrue(numbersRead.Contains(999)); + Assert.Multiple(() => + { + Assert.That(r.Read(), Is.False); + Assert.That(numbersRead, Does.Contain(1)); + }); + Assert.That(numbersRead, Does.Contain(999)); } [TestCase(false)] @@ -961,7 +998,7 @@ public void TestDestinationAlreadyExistingIsOk(bool targetTableIsEmpty) destinationComponent.ProcessPipelineData(dt, listener, new GracefulCancellationToken()); destinationComponent.Dispose(listener, null); - Assert.AreEqual(targetTableIsEmpty ? 3 : 4, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(targetTableIsEmpty ? 3 : 4)); } finally { @@ -1011,8 +1048,11 @@ public void DataTableUploadDestinationTests_PrimaryKeyDataTableWithAlterSizeLate var tbl = db.ExpectTable("MyTable"); - Assert.AreEqual(2, tbl.GetRowCount()); - Assert.IsTrue(tbl.DiscoverColumns().Single().IsPrimaryKey); + Assert.Multiple(() => + { + Assert.That(tbl.GetRowCount(), Is.EqualTo(2)); + Assert.That(tbl.DiscoverColumns().Single().IsPrimaryKey); + }); } [Test] @@ -1063,7 +1103,7 @@ public void TestDestinationAlreadyExisting_ColumnSubset() destinationComponent.ProcessPipelineData(dt, listener, new GracefulCancellationToken()); destinationComponent.Dispose(listener, null); - Assert.AreEqual(4, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(4)); } finally { @@ -1095,11 +1135,11 @@ public void Test_DataTableUploadDestination_ScientificNotation(DatabaseType dbTy } //in the database it should be typed - Assert.AreEqual(typeof(decimal), db.ExpectTable("ff").DiscoverColumn("mycol").DataType.GetCSharpDataType()); + Assert.That(db.ExpectTable("ff").DiscoverColumn("mycol").DataType.GetCSharpDataType(), Is.EqualTo(typeof(decimal))); var dt2 = db.ExpectTable("ff").GetDataTable(); - Assert.IsTrue((decimal)dt2.Rows[0][0] == (decimal)-0.0000410235746055587); + Assert.That((decimal)dt2.Rows[0][0], Is.EqualTo((decimal)-0.0000410235746055587)); } private class AdjustColumnDelegater : IDatabaseColumnRequestAdjuster @@ -1138,7 +1178,7 @@ public void Test_DataTableUploadDestination_ForceBool(DatabaseType dbType) var col = s.Single(c => c.ColumnName.Equals("hb_extract")); //Guesser would normally make it a string - Assert.AreEqual(typeof(string), col.TypeRequested.CSharpType); + Assert.That(col.TypeRequested.CSharpType, Is.EqualTo(typeof(string))); //we demand a boolean interpretation instead! col.TypeRequested.CSharpType = typeof(bool); @@ -1160,20 +1200,20 @@ public void Test_DataTableUploadDestination_ForceBool(DatabaseType dbType) if (dbType == DatabaseType.Oracle) { //in the database it should be typed as string - Assert.AreEqual(typeof(string), tbl.DiscoverColumn("hb_extract").DataType.GetCSharpDataType()); + Assert.That(tbl.DiscoverColumn("hb_extract").DataType.GetCSharpDataType(), Is.EqualTo(typeof(string))); var dt2 = tbl.GetDataTable(); - Assert.Contains("T", dt2.Rows.Cast().Select(r => r[0]).ToArray()); - Assert.Contains("F", dt2.Rows.Cast().Select(r => r[0]).ToArray()); + Assert.That(dt2.Rows.Cast().Select(r => r[0]).ToArray(), Does.Contain("T")); + Assert.That(dt2.Rows.Cast().Select(r => r[0]).ToArray(), Does.Contain("F")); } else { //in the database it should be typed as bool - Assert.AreEqual(typeof(bool), tbl.DiscoverColumn("hb_extract").DataType.GetCSharpDataType()); + Assert.That(tbl.DiscoverColumn("hb_extract").DataType.GetCSharpDataType(), Is.EqualTo(typeof(bool))); var dt2 = tbl.GetDataTable(); - Assert.Contains(true, dt2.Rows.Cast().Select(r => r[0]).ToArray()); - Assert.Contains(false, dt2.Rows.Cast().Select(r => r[0]).ToArray()); + Assert.That(dt2.Rows.Cast().Select(r => r[0]).ToArray(), Does.Contain(true)); + Assert.That(dt2.Rows.Cast().Select(r => r[0]).ToArray(), Does.Contain(false)); } } @@ -1211,25 +1251,27 @@ public void TwoBatch_BooleanResizingTest(DatabaseType dbType, bool giveNullValue destination.ProcessPipelineData(dt1, toConsole, token); - Assert.AreEqual("bit", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("TestedCol").DataType.SQLType); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("TestedCol").DataType.SQLType, Is.EqualTo("bit")); destination.ProcessPipelineData(dt2, toMemory, token); - Assert.IsTrue(toMemory.EventsReceivedBySender[destination] + Assert.That(toMemory.EventsReceivedBySender[destination] .Any(msg => msg.Message.Contains("Resizing column "))); destination.Dispose(toConsole, null); - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - Assert.AreEqual(2, db.ExpectTable("DataTableUploadDestinationTests").GetRowCount()); + Assert.Multiple(() => + { + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").GetRowCount(), Is.EqualTo(2)); + }); var tt = db.Server.GetQuerySyntaxHelper().TypeTranslater; - Assert.AreEqual( - //if all we got are nulls we should have a DateTime otherwise we had 1/true so the only usable data type is string - giveNullValuesOnly ? typeof(DateTime) : typeof(string), + Assert.That( tt.GetCSharpTypeForSQLDBType(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("TestedCol") - .DataType.SQLType)); + .DataType.SQLType), Is.EqualTo( + //if all we got are nulls we should have a DateTime otherwise we had 1/true so the only usable data type is string + giveNullValuesOnly ? typeof(DateTime) : typeof(string))); } /// @@ -1286,8 +1328,7 @@ public void TwoBatch_MiscellaneousTest(DatabaseType dbType, string v1, string v2 try { destination.ProcessPipelineData(dt1, toConsole, token); - Assert.AreEqual(expectedTypeForBatch1, - tt.GetCSharpTypeForSQLDBType(tbl.DiscoverColumn("TestedCol").DataType.SQLType)); + Assert.That(tt.GetCSharpTypeForSQLDBType(tbl.DiscoverColumn("TestedCol").DataType.SQLType), Is.EqualTo(expectedTypeForBatch1)); destination.ProcessPipelineData(dt2, toMemory, token); destination.Dispose(toConsole, null); @@ -1298,14 +1339,20 @@ public void TwoBatch_MiscellaneousTest(DatabaseType dbType, string v1, string v2 throw; } - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - Assert.AreEqual(2, db.ExpectTable("DataTableUploadDestinationTests").GetRowCount()); + Assert.Multiple(() => + { + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").GetRowCount(), Is.EqualTo(2)); + }); var colAfter = tbl.DiscoverColumn("TestedCol"); - Assert.AreEqual(v1 != null && v2 != null, colAfter.IsPrimaryKey); + Assert.Multiple(() => + { + Assert.That(colAfter.IsPrimaryKey, Is.EqualTo(v1 != null && v2 != null)); - Assert.AreEqual(expectedTypeForBatch2, tt.GetCSharpTypeForSQLDBType(colAfter.DataType.SQLType)); + Assert.That(tt.GetCSharpTypeForSQLDBType(colAfter.DataType.SQLType), Is.EqualTo(expectedTypeForBatch2)); + }); } @@ -1336,19 +1383,20 @@ public void TwoBatch_ExplicitRealDataType() destination.ProcessPipelineData(dt1, toConsole, token); - Assert.AreEqual("real", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("FloatCol").DataType.SQLType); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("FloatCol").DataType.SQLType, Is.EqualTo("real")); destination.ProcessPipelineData(dt2, toMemory, token); destination.Dispose(toConsole, null); - Assert.IsTrue(db.ExpectTable("DataTableUploadDestinationTests").Exists()); - Assert.AreEqual(2, db.ExpectTable("DataTableUploadDestinationTests").GetRowCount()); + Assert.Multiple(() => + { + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").Exists()); + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").GetRowCount(), Is.EqualTo(2)); - // should still be real - Assert.AreEqual("real", - db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("FloatCol").DataType.SQLType); + // should still be real + Assert.That(db.ExpectTable("DataTableUploadDestinationTests").DiscoverColumn("FloatCol").DataType.SQLType, Is.EqualTo("real")); + }); } #endregion diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DatabaseOperationTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DatabaseOperationTests.cs index 96ad2c84d3..d966f52ff6 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DatabaseOperationTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DatabaseOperationTests.cs @@ -45,7 +45,7 @@ public void CloneDatabaseAndTable() } DiscoveredServerICanCreateRandomDatabasesAndTablesOn.CreateDatabase(testLiveDatabaseName); - Assert.IsTrue(testDb.Exists()); + Assert.That(testDb.Exists()); testDb.CreateTable("Table_1", new[] { new DatabaseColumnRequest("Id", "int") }); @@ -66,7 +66,7 @@ public void CloneDatabaseAndTable() var cloneDb = cloner.CreateDatabaseForStage(LoadBubble.Raw); //confirm database appeared - Assert.IsTrue(DiscoveredServerICanCreateRandomDatabasesAndTablesOn.ExpectDatabase( + Assert.That(DiscoveredServerICanCreateRandomDatabasesAndTablesOn.ExpectDatabase( $"{testLiveDatabaseName}_RAW").Exists()); //now create a catalogue and wire it SetUp to the table TEST on the test database server @@ -77,8 +77,11 @@ public void CloneDatabaseAndTable() cloner.CreateTablesInDatabaseFromCatalogueInfo(ThrowImmediatelyDataLoadEventListener.Quiet, tableInfo, LoadBubble.Raw); - Assert.IsTrue(raw.Exists()); - Assert.IsTrue(raw.ExpectTable("Table_1").Exists()); + Assert.Multiple(() => + { + Assert.That(raw.Exists()); + Assert.That(raw.ExpectTable("Table_1").Exists()); + }); } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DilutionTests/DilutionOperationFactoryTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DilutionTests/DilutionOperationFactoryTests.cs index 3b624e6120..598cad4198 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DilutionTests/DilutionOperationFactoryTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DilutionTests/DilutionOperationFactoryTests.cs @@ -51,7 +51,7 @@ public void ExpectedType_Created() col.Repository.Returns(CatalogueRepository); var factory = new DilutionOperationFactory(col); var i = factory.Create(typeof(ExcludeRight3OfUKPostcodes)); - Assert.IsNotNull(i); - Assert.IsInstanceOf(i); + Assert.That(i, Is.Not.Null); + Assert.That(i, Is.InstanceOf()); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DilutionTests/DilutionOperationTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DilutionTests/DilutionOperationTests.cs index d5b6297e4d..9e6ef3f2a2 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DilutionTests/DilutionOperationTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DilutionTests/DilutionOperationTests.cs @@ -57,9 +57,9 @@ public void TestRoundDateToMiddleOfQuarter(string input, string expectedDilute) var result = server.GetCommand("SELECT * from DateRoundingTests", con).ExecuteScalar(); if (expectedDilute == null) - Assert.AreEqual(DBNull.Value, result); + Assert.That(result, Is.EqualTo(DBNull.Value)); else - Assert.AreEqual(DateTime.Parse(expectedDilute), result); + Assert.That(result, Is.EqualTo(DateTime.Parse(expectedDilute))); } finally { @@ -118,9 +118,9 @@ public void TestExcludeRight3OfUKPostcodes(string input, string expectedDilute) var result = server.GetCommand("SELECT * from ExcludeRight3OfPostcodes", con).ExecuteScalar(); if (expectedDilute == null) - Assert.AreEqual(DBNull.Value, result); + Assert.That(result, Is.EqualTo(DBNull.Value)); else - Assert.AreEqual(expectedDilute, result); + Assert.That(result, Is.EqualTo(expectedDilute)); } finally { @@ -162,7 +162,7 @@ public void DiluteToBitFlag(string input, string inputDataType, bool expectedDil var result = server.GetCommand("SELECT * from DiluteToBitFlagTests", con).ExecuteScalar(); - Assert.AreEqual(expectedDilute, Convert.ToBoolean(result)); + Assert.That(Convert.ToBoolean(result), Is.EqualTo(expectedDilute)); } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DistincterTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DistincterTests.cs index 995a8023bd..6c91b0905f 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/DistincterTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/DistincterTests.cs @@ -78,7 +78,7 @@ public void TestDistincter_Duplicates(DatabaseType type) var rowsAfter = tbl.GetRowCount(); - Assert.AreEqual(rowsBefore / 2, rowsAfter); + Assert.That(rowsAfter, Is.EqualTo(rowsBefore / 2)); db.Drop(); } @@ -137,7 +137,7 @@ public void TestDistincter_NoDuplicates(DatabaseType type) var rowsAfter = tbl.GetRowCount(); - Assert.AreEqual(rowsBefore, rowsAfter); + Assert.That(rowsAfter, Is.EqualTo(rowsBefore)); db.Drop(); } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExcelConversionTest.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExcelConversionTest.cs index 30e90a939b..48a28a32ac 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExcelConversionTest.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExcelConversionTest.cs @@ -9,6 +9,7 @@ using System.IO; using System.Text.RegularExpressions; using NUnit.Framework; +using NUnit.Framework.Legacy; using Rdmp.Core.Curation; using Rdmp.Core.DataFlowPipeline; using Rdmp.Core.DataLoad.Engine.Job; @@ -89,7 +90,7 @@ public void TestExcelFunctionality_DodgyFileExtension() var ex = Assert.Throws(() => TestConversionFor(targetFile, "*.fish", 1, LoadDirectory)); - Assert.IsTrue(ex.Message.StartsWith("Did not find any files matching Pattern '*.fish' in directory")); + Assert.That(ex.Message, Does.StartWith("Did not find any files matching Pattern '*.fish' in directory")); } private static void TestConversionFor(string targetFile, string fileExtensionToConvert, int expectedNumberOfSheets, @@ -99,8 +100,11 @@ private static void TestConversionFor(string targetFile, string fileExtensionToC try { - Assert.IsTrue(f.Exists); - Assert.IsTrue(f.Length > 100); + Assert.Multiple(() => + { + Assert.That(f.Exists); + Assert.That(f.Length, Is.GreaterThan(100)); + }); var converter = new ExcelToCSVFilesConverter(); @@ -114,12 +118,15 @@ private static void TestConversionFor(string targetFile, string fileExtensionToC var filesCreated = directory.ForLoading.GetFiles("*.csv"); - Assert.AreEqual(expectedNumberOfSheets, filesCreated.Length); + Assert.That(filesCreated, Has.Length.EqualTo(expectedNumberOfSheets)); foreach (var fileCreated in filesCreated) { - Assert.IsTrue(Regex.IsMatch(fileCreated.Name, "Sheet[0-9].csv")); - Assert.GreaterOrEqual(fileCreated.Length, 100); + Assert.Multiple(() => + { + Assert.That(Regex.IsMatch(fileCreated.Name, "Sheet[0-9].csv")); + Assert.That(fileCreated.Length, Is.GreaterThanOrEqualTo(100)); + }); fileCreated.Delete(); } } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExcelDatabaseTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExcelDatabaseTests.cs index 1374b12b07..1262621d25 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExcelDatabaseTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExcelDatabaseTests.cs @@ -11,6 +11,7 @@ using Rdmp.Core.Curation.Data.Pipelines; using System.IO; using System.Linq; +using NUnit.Framework.Legacy; using Tests.Common; namespace Rdmp.Core.Tests.DataLoad.Engine.Integration; @@ -43,13 +44,16 @@ public void TestLoadingFileWithTrailingDotsInHeader() cmd.Execute(); var tbl = db.ExpectTable("TrailingDots"); - Assert.IsTrue(tbl.Exists()); + Assert.That(tbl.Exists()); var cols = tbl.DiscoverColumns(); - Assert.AreEqual(2, cols.Length); - Assert.AreEqual("Field1", cols[0].GetRuntimeName()); - Assert.AreEqual("Field2", cols[1].GetRuntimeName()); - - Assert.AreEqual(2, tbl.GetRowCount()); + Assert.That(cols, Has.Length.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(cols[0].GetRuntimeName(), Is.EqualTo("Field1")); + Assert.That(cols[1].GetRuntimeName(), Is.EqualTo("Field2")); + + Assert.That(tbl.GetRowCount(), Is.EqualTo(2)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExecutableProcessTaskTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExecutableProcessTaskTests.cs index e402a338fb..c3403ca0fe 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExecutableProcessTaskTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExecutableProcessTaskTests.cs @@ -41,14 +41,17 @@ public void TestConstructionFromProcessTaskUsingDatabase() new RuntimeArgumentCollection(processTask.ProcessTaskArguments.Cast().ToArray(), null); var runtimeTask = new ExecutableRuntimeTask(processTask, args); - Assert.AreEqual(expectedPath, runtimeTask.ExeFilepath); + Assert.Multiple(() => + { + Assert.That(runtimeTask.ExeFilepath, Is.EqualTo(expectedPath)); - Assert.AreEqual(1, runtimeTask.RuntimeArguments.GetAllArgumentsOfType().Count()); + Assert.That(runtimeTask.RuntimeArguments.GetAllArgumentsOfType().Count(), Is.EqualTo(1)); + }); var dictionaryOfStringArguments = runtimeTask.RuntimeArguments.GetAllArgumentsOfType() .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); - Assert.IsNotNull(dictionaryOfStringArguments["DatabaseName"]); - Assert.AreEqual("Foo_STAGING", dictionaryOfStringArguments["DatabaseName"]); + Assert.That(dictionaryOfStringArguments["DatabaseName"], Is.Not.Null); + Assert.That(dictionaryOfStringArguments["DatabaseName"], Is.EqualTo("Foo_STAGING")); } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExecuteSqlFileRuntimeTaskTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExecuteSqlFileRuntimeTaskTests.cs index d0e76eaa40..35c01cd343 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExecuteSqlFileRuntimeTaskTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/ExecuteSqlFileRuntimeTaskTests.cs @@ -60,7 +60,7 @@ public void ExecuteSqlFileRuntimeTask_BasicScript(DatabaseType dbType) task.Run(job, new GracefulCancellationToken()); - Assert.AreEqual(1, tbl.GetDataTable().Rows[0][0]); + Assert.That(tbl.GetDataTable().Rows[0][0], Is.EqualTo(1)); tbl.Drop(); } @@ -103,7 +103,7 @@ public void ExecuteSqlFileRuntimeTask_InvalidID(DatabaseType dbType) var ex = Assert.Throws(() => task.Run(job, new GracefulCancellationToken())); - StringAssert.Contains("Failed to find a TableInfo in the load with ID 0", ex.Message); + Assert.That(ex.Message, Does.Contain("Failed to find a TableInfo in the load with ID 0")); task.LoadCompletedSoDispose(Core.DataLoad.ExitCodeType.Success, ThrowImmediatelyDataLoadEventListener.Quiet); } @@ -126,8 +126,6 @@ public void ExecuteSqlRuntimeTask_InvalidID(DatabaseType dbType) var dir = LoadDirectory.CreateDirectoryStructure(new DirectoryInfo(TestContext.CurrentContext.TestDirectory), "ExecuteSqlFileRuntimeTaskTests", true); - -#pragma warning disable CS0252, CS0253 // Spurious warning 'Possible unintended reference comparison; left hand side needs cast' since VS doesn't grok Moq fully var _arg = Substitute.For(); _arg.Name.Returns("Sql"); _arg.Value.Returns(sql); @@ -136,8 +134,6 @@ public void ExecuteSqlRuntimeTask_InvalidID(DatabaseType dbType) { _arg }; -#pragma warning restore CS0252, CS0253 - var args = new RuntimeArgumentCollection(sqlArg, new StageArgs(LoadStage.AdjustRaw, db, dir)); var pt = Substitute.For(); @@ -158,8 +154,11 @@ public void ExecuteSqlRuntimeTask_InvalidID(DatabaseType dbType) var ex = Assert.Throws(() => task.Run(job, new GracefulCancellationToken())); - StringAssert.Contains("Mutilate failed", ex.Message); - StringAssert.Contains("Failed to find a TableInfo in the load with ID 0", ex.InnerException.Message); + Assert.Multiple(() => + { + Assert.That(ex.Message, Does.Contain("Mutilate failed")); + Assert.That(ex.InnerException.Message, Does.Contain("Failed to find a TableInfo in the load with ID 0")); + }); task.LoadCompletedSoDispose(Core.DataLoad.ExitCodeType.Success, ThrowImmediatelyDataLoadEventListener.Quiet); } @@ -187,7 +186,7 @@ public void ExecuteSqlFileRuntimeTask_ValidID_CustomNamer(DatabaseType dbType) tbl.Rename(tableName); //we renamed the table to simulate RAW, confirm TableInfo doesn't think it exists - Assert.IsFalse(ti.Discover(DataAccessContext.InternalDataProcessing).Exists()); + Assert.That(ti.Discover(DataAccessContext.InternalDataProcessing).Exists(), Is.False); var pt = Substitute.For(); pt.Path.Returns(f.FullName); @@ -211,7 +210,7 @@ public void ExecuteSqlFileRuntimeTask_ValidID_CustomNamer(DatabaseType dbType) task.Run(job, new GracefulCancellationToken()); - Assert.AreEqual(1, tbl.GetDataTable().Rows[0][0]); + Assert.That(tbl.GetDataTable().Rows[0][0], Is.EqualTo(1)); tbl.Drop(); } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/FixedWidthTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/FixedWidthTests.cs index da8d39e156..4bf61f62bb 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/FixedWidthTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/FixedWidthTests.cs @@ -26,7 +26,7 @@ private static FixedWidthFormatFile CreateFormatFile() File.WriteAllText(fileInfo.FullName, LoadDirectory.ExampleFixedWidthFormatFileContents); - Assert.IsTrue(fileInfo.Exists); + Assert.That(fileInfo.Exists); return new FixedWidthFormatFile(fileInfo); } @@ -36,65 +36,84 @@ public void TestLoadingFormat() { var formatFile = CreateFormatFile(); - Assert.AreEqual(8, formatFile.FormatColumns.Length); - - Assert.AreEqual("gmc", formatFile.FormatColumns[0].Field); - Assert.AreEqual(1, formatFile.FormatColumns[0].From); - Assert.AreEqual(7, formatFile.FormatColumns[0].To); - Assert.AreEqual(1 + formatFile.FormatColumns[0].To - formatFile.FormatColumns[0].From, - formatFile.FormatColumns[0].Size); - Assert.AreEqual(7, formatFile.FormatColumns[0].Size); - - Assert.AreEqual("gp_code", formatFile.FormatColumns[1].Field); - Assert.AreEqual(8, formatFile.FormatColumns[1].From); - Assert.AreEqual(12, formatFile.FormatColumns[1].To); - Assert.AreEqual(1 + formatFile.FormatColumns[1].To - formatFile.FormatColumns[1].From, - formatFile.FormatColumns[1].Size); - Assert.AreEqual(5, formatFile.FormatColumns[1].Size); - - Assert.AreEqual("surname", formatFile.FormatColumns[2].Field); - Assert.AreEqual(13, formatFile.FormatColumns[2].From); - Assert.AreEqual(32, formatFile.FormatColumns[2].To); - Assert.AreEqual(1 + formatFile.FormatColumns[2].To - formatFile.FormatColumns[2].From, - formatFile.FormatColumns[2].Size); - Assert.AreEqual(20, formatFile.FormatColumns[2].Size); - - Assert.AreEqual("forename", formatFile.FormatColumns[3].Field); - Assert.AreEqual(33, formatFile.FormatColumns[3].From); - Assert.AreEqual(52, formatFile.FormatColumns[3].To); - Assert.AreEqual(1 + formatFile.FormatColumns[3].To - formatFile.FormatColumns[3].From, - formatFile.FormatColumns[3].Size); - Assert.AreEqual(20, formatFile.FormatColumns[3].Size); - - Assert.AreEqual("initials", formatFile.FormatColumns[4].Field); - Assert.AreEqual(53, formatFile.FormatColumns[4].From); - Assert.AreEqual(55, formatFile.FormatColumns[4].To); - Assert.AreEqual(1 + formatFile.FormatColumns[4].To - formatFile.FormatColumns[4].From, - formatFile.FormatColumns[4].Size); - Assert.AreEqual(3, formatFile.FormatColumns[4].Size); - - Assert.AreEqual("practice_code", formatFile.FormatColumns[5].Field); - Assert.AreEqual(56, formatFile.FormatColumns[5].From); - Assert.AreEqual(60, formatFile.FormatColumns[5].To); - Assert.AreEqual(1 + formatFile.FormatColumns[5].To - formatFile.FormatColumns[5].From, - formatFile.FormatColumns[5].Size); - Assert.AreEqual(5, formatFile.FormatColumns[5].Size); - - Assert.AreEqual("date_into_practice", formatFile.FormatColumns[6].Field); - Assert.AreEqual(61, formatFile.FormatColumns[6].From); - Assert.AreEqual(68, formatFile.FormatColumns[6].To); - Assert.AreEqual(1 + formatFile.FormatColumns[6].To - formatFile.FormatColumns[6].From, - formatFile.FormatColumns[6].Size); - Assert.AreEqual(8, formatFile.FormatColumns[6].Size); - Assert.AreEqual("yyyyMMdd", formatFile.FormatColumns[6].DateFormat); - - Assert.AreEqual("date_out_of_practice", formatFile.FormatColumns[7].Field); - Assert.AreEqual(69, formatFile.FormatColumns[7].From); - Assert.AreEqual(76, formatFile.FormatColumns[7].To); - Assert.AreEqual(1 + formatFile.FormatColumns[7].To - formatFile.FormatColumns[7].From, - formatFile.FormatColumns[7].Size); - Assert.AreEqual(8, formatFile.FormatColumns[7].Size); - Assert.AreEqual("yyyyMMdd", formatFile.FormatColumns[7].DateFormat); + Assert.That(formatFile.FormatColumns, Has.Length.EqualTo(8)); + + Assert.Multiple(() => + { + Assert.That(formatFile.FormatColumns[0].Field, Is.EqualTo("gmc")); + Assert.That(formatFile.FormatColumns[0].From, Is.EqualTo(1)); + Assert.That(formatFile.FormatColumns[0].To, Is.EqualTo(7)); + Assert.That(formatFile.FormatColumns[0].Size, Is.EqualTo(1 + formatFile.FormatColumns[0].To - formatFile.FormatColumns[0].From)); + }); + Assert.Multiple(() => + { + Assert.That(formatFile.FormatColumns[0].Size, Is.EqualTo(7)); + + Assert.That(formatFile.FormatColumns[1].Field, Is.EqualTo("gp_code")); + Assert.That(formatFile.FormatColumns[1].From, Is.EqualTo(8)); + Assert.That(formatFile.FormatColumns[1].To, Is.EqualTo(12)); + Assert.That(formatFile.FormatColumns[1].Size, Is.EqualTo(1 + formatFile.FormatColumns[1].To - formatFile.FormatColumns[1].From)); + }); + Assert.Multiple(() => + { + Assert.That(formatFile.FormatColumns[1].Size, Is.EqualTo(5)); + + Assert.That(formatFile.FormatColumns[2].Field, Is.EqualTo("surname")); + Assert.That(formatFile.FormatColumns[2].From, Is.EqualTo(13)); + Assert.That(formatFile.FormatColumns[2].To, Is.EqualTo(32)); + Assert.That(formatFile.FormatColumns[2].Size, Is.EqualTo(1 + formatFile.FormatColumns[2].To - formatFile.FormatColumns[2].From)); + }); + Assert.Multiple(() => + { + Assert.That(formatFile.FormatColumns[2].Size, Is.EqualTo(20)); + + Assert.That(formatFile.FormatColumns[3].Field, Is.EqualTo("forename")); + Assert.That(formatFile.FormatColumns[3].From, Is.EqualTo(33)); + Assert.That(formatFile.FormatColumns[3].To, Is.EqualTo(52)); + Assert.That(formatFile.FormatColumns[3].Size, Is.EqualTo(1 + formatFile.FormatColumns[3].To - formatFile.FormatColumns[3].From)); + }); + Assert.Multiple(() => + { + Assert.That(formatFile.FormatColumns[3].Size, Is.EqualTo(20)); + + Assert.That(formatFile.FormatColumns[4].Field, Is.EqualTo("initials")); + Assert.That(formatFile.FormatColumns[4].From, Is.EqualTo(53)); + Assert.That(formatFile.FormatColumns[4].To, Is.EqualTo(55)); + Assert.That(formatFile.FormatColumns[4].Size, Is.EqualTo(1 + formatFile.FormatColumns[4].To - formatFile.FormatColumns[4].From)); + }); + Assert.Multiple(() => + { + Assert.That(formatFile.FormatColumns[4].Size, Is.EqualTo(3)); + + Assert.That(formatFile.FormatColumns[5].Field, Is.EqualTo("practice_code")); + Assert.That(formatFile.FormatColumns[5].From, Is.EqualTo(56)); + Assert.That(formatFile.FormatColumns[5].To, Is.EqualTo(60)); + Assert.That(formatFile.FormatColumns[5].Size, Is.EqualTo(1 + formatFile.FormatColumns[5].To - formatFile.FormatColumns[5].From)); + }); + Assert.Multiple(() => + { + Assert.That(formatFile.FormatColumns[5].Size, Is.EqualTo(5)); + + Assert.That(formatFile.FormatColumns[6].Field, Is.EqualTo("date_into_practice")); + Assert.That(formatFile.FormatColumns[6].From, Is.EqualTo(61)); + Assert.That(formatFile.FormatColumns[6].To, Is.EqualTo(68)); + Assert.That(formatFile.FormatColumns[6].Size, Is.EqualTo(1 + formatFile.FormatColumns[6].To - formatFile.FormatColumns[6].From)); + }); + Assert.Multiple(() => + { + Assert.That(formatFile.FormatColumns[6].Size, Is.EqualTo(8)); + Assert.That(formatFile.FormatColumns[6].DateFormat, Is.EqualTo("yyyyMMdd")); + + Assert.That(formatFile.FormatColumns[7].Field, Is.EqualTo("date_out_of_practice")); + Assert.That(formatFile.FormatColumns[7].From, Is.EqualTo(69)); + Assert.That(formatFile.FormatColumns[7].To, Is.EqualTo(76)); + Assert.That(formatFile.FormatColumns[7].Size, Is.EqualTo(1 + formatFile.FormatColumns[7].To - formatFile.FormatColumns[7].From)); + }); + Assert.Multiple(() => + { + Assert.That(formatFile.FormatColumns[7].Size, Is.EqualTo(8)); + Assert.That(formatFile.FormatColumns[7].DateFormat, Is.EqualTo("yyyyMMdd")); + }); } [Test] @@ -113,15 +132,18 @@ public void TestLoadingFormatThenFile() streamWriter.Close(); var dataTable = formatFile.GetDataTableFromFlatFile(new FileInfo(tempFileToCreate)); - Assert.AreEqual(dataTable.Rows.Count, 2); - Assert.AreEqual("0026440", dataTable.Rows[0]["gmc"]); - Assert.AreEqual("99999", dataTable.Rows[0]["gp_code"]); - Assert.AreEqual("Akerman", dataTable.Rows[0]["surname"]); - Assert.AreEqual("Frank", dataTable.Rows[0]["forename"]); - Assert.AreEqual("FM", dataTable.Rows[0]["initials"]); - Assert.AreEqual("38051", dataTable.Rows[0]["practice_code"]); - Assert.AreEqual(new DateTime(2004, 4, 1), dataTable.Rows[0]["date_into_practice"]); - Assert.AreEqual(new DateTime(2009, 5, 1), dataTable.Rows[0]["date_out_of_practice"]); + Assert.That(dataTable.Rows, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(dataTable.Rows[0]["gmc"], Is.EqualTo("0026440")); + Assert.That(dataTable.Rows[0]["gp_code"], Is.EqualTo("99999")); + Assert.That(dataTable.Rows[0]["surname"], Is.EqualTo("Akerman")); + Assert.That(dataTable.Rows[0]["forename"], Is.EqualTo("Frank")); + Assert.That(dataTable.Rows[0]["initials"], Is.EqualTo("FM")); + Assert.That(dataTable.Rows[0]["practice_code"], Is.EqualTo("38051")); + Assert.That(dataTable.Rows[0]["date_into_practice"], Is.EqualTo(new DateTime(2004, 4, 1))); + Assert.That(dataTable.Rows[0]["date_out_of_practice"], Is.EqualTo(new DateTime(2009, 5, 1))); + }); } finally { @@ -187,8 +209,11 @@ public void TestHeaderMatching(FixedWidthTestCase testCase) var table = db.ExpectTable("TestHeaderMatching_Compatible"); - Assert.IsTrue(table.Exists()); - Assert.AreEqual(0, table.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(table.Exists()); + Assert.That(table.GetRowCount(), Is.EqualTo(0)); + }); try { Regex errorRegex; @@ -199,7 +224,7 @@ public void TestHeaderMatching(FixedWidthTestCase testCase) //Success Case case FixedWidthTestCase.CompatibleHeaders: attacher.Attach(new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken()); - Assert.AreEqual(2, table.GetRowCount()); + Assert.That(table.GetRowCount(), Is.EqualTo(2)); return; //Return @@ -221,7 +246,7 @@ public void TestHeaderMatching(FixedWidthTestCase testCase) } //Assert the expected error result is the real one - Assert.IsTrue(errorRegex.IsMatch(ex.Message)); + Assert.That(errorRegex.IsMatch(ex.Message)); } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/FlatFileAttacherTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/FlatFileAttacherTests.cs index df66271a0a..ca868ed482 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/FlatFileAttacherTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/FlatFileAttacherTests.cs @@ -108,10 +108,9 @@ public void Test_CSV_Attachment(string separator, bool overrideHeaders) var ex = Assert.Throws(() => attacher.Attach(new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken())); - Assert.IsNotNull(ex.InnerException); - StringAssert.StartsWith( - "Your separator does not appear in the headers line of your file (bob.csv) but the separator ',' does", - ex.InnerException.Message); + Assert.That(ex.InnerException, Is.Not.Null); + Assert.That( + ex.InnerException.Message, Does.StartWith("Your separator does not appear in the headers line of your file (bob.csv) but the separator ',' does")); return; } @@ -119,7 +118,7 @@ public void Test_CSV_Attachment(string separator, bool overrideHeaders) attacher.Attach(new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken()); var table = _database.ExpectTable("Bob"); - Assert.IsTrue(table.Exists()); + Assert.That(table.Exists()); table.DiscoverColumn("name"); table.DiscoverColumn("name2"); @@ -128,17 +127,26 @@ public void Test_CSV_Attachment(string separator, bool overrideHeaders) { con.Open(); var r = _database.Server.GetCommand("Select * from Bob", con).ExecuteReader(); - Assert.IsTrue(r.Read()); - Assert.AreEqual("Bob", r["name"]); - Assert.AreEqual("Munchousain", r["name2"]); - - Assert.IsTrue(r.Read()); - Assert.AreEqual("Franky", r["name"]); - Assert.AreEqual("Hollyw9ood", r["name2"]); - - Assert.IsTrue(r.Read()); - Assert.AreEqual("Manny2", r["name"]); - Assert.AreEqual("Ok", r["name2"]); + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Bob")); + Assert.That(r["name2"], Is.EqualTo("Munchousain")); + }); + + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Franky")); + Assert.That(r["name2"], Is.EqualTo("Hollyw9ood")); + }); + + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Manny2")); + Assert.That(r["name2"], Is.EqualTo("Ok")); + }); } attacher.LoadCompletedSoDispose(ExitCodeType.Success, ThrowImmediatelyDataLoadEventListener.Quiet); @@ -172,7 +180,7 @@ public void Test_ExplicitDateTimeFormat_Attachment() var table = _database.ExpectTable("Bob"); table.Truncate(); - Assert.IsTrue(table.Exists()); + Assert.That(table.Exists()); table.DiscoverColumn("name"); var name2 = table.DiscoverColumn("name2"); name2.DataType.AlterTypeTo("datetime2"); @@ -184,13 +192,19 @@ public void Test_ExplicitDateTimeFormat_Attachment() { con.Open(); var r = _database.Server.GetCommand("Select * from Bob", con).ExecuteReader(); - Assert.IsTrue(r.Read()); - Assert.AreEqual("Bob", r["name"]); - Assert.AreEqual(new DateTime(2001, 01, 13), r["name2"]); - - Assert.IsTrue(r.Read()); - Assert.AreEqual("Franky", r["name"]); - Assert.AreEqual(new DateTime(2002, 01, 13), r["name2"]); + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Bob")); + Assert.That(r["name2"], Is.EqualTo(new DateTime(2001, 01, 13))); + }); + + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Franky")); + Assert.That(r["name2"], Is.EqualTo(new DateTime(2002, 01, 13))); + }); } attacher.LoadCompletedSoDispose(ExitCodeType.Success, ThrowImmediatelyDataLoadEventListener.Quiet); @@ -219,19 +233,25 @@ public void TabTestWithOverrideHeaders() attacher.ForceHeaders = "name\tname2"; var exitCode = attacher.Attach(new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken()); - Assert.AreEqual(ExitCodeType.Success, exitCode); + Assert.That(exitCode, Is.EqualTo(ExitCodeType.Success)); using (var con = _database.Server.GetConnection()) { con.Open(); var r = _database.Server.GetCommand("Select name,name2 from Bob", con).ExecuteReader(); - Assert.IsTrue(r.Read()); - Assert.AreEqual("Face", r["name"]); - Assert.AreEqual("Basher", r["name2"]); - - Assert.IsTrue(r.Read()); - Assert.AreEqual("Candy", r["name"]); - Assert.AreEqual("Crusher", r["name2"]); + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Face")); + Assert.That(r["name2"], Is.EqualTo("Basher")); + }); + + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Candy")); + Assert.That(r["name2"], Is.EqualTo("Crusher")); + }); } attacher.LoadCompletedSoDispose(ExitCodeType.Success, ThrowImmediatelyDataLoadEventListener.Quiet); @@ -268,27 +288,32 @@ public void TabTestWithOverrideHeaders_IncludePath(bool columnExistsInRaw) { var ex = Assert.Throws(() => attacher.Attach(new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken())); - Assert.AreEqual("AddFilenameColumnNamed is set to 'FilePath' but the column did not exist in RAW", - ex.InnerException.Message); + Assert.That(ex.InnerException.Message, Is.EqualTo("AddFilenameColumnNamed is set to 'FilePath' but the column did not exist in RAW")); return; } var exitCode = attacher.Attach(new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken()); - Assert.AreEqual(ExitCodeType.Success, exitCode); + Assert.That(exitCode, Is.EqualTo(ExitCodeType.Success)); using (var con = _database.Server.GetConnection()) { con.Open(); var r = _database.Server.GetCommand("Select name,name2,FilePath from Bob", con).ExecuteReader(); - Assert.IsTrue(r.Read()); - Assert.AreEqual("Face", r["name"]); - Assert.AreEqual("Basher", r["name2"]); - Assert.AreEqual(filename, r["FilePath"]); - - Assert.IsTrue(r.Read()); - Assert.AreEqual("Candy", r["name"]); - Assert.AreEqual("Crusher", r["name2"]); + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Face")); + Assert.That(r["name2"], Is.EqualTo("Basher")); + Assert.That(r["FilePath"], Is.EqualTo(filename)); + }); + + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Candy")); + Assert.That(r["name2"], Is.EqualTo("Crusher")); + }); } attacher.LoadCompletedSoDispose(ExitCodeType.Success, ThrowImmediatelyDataLoadEventListener.Quiet); @@ -331,20 +356,26 @@ public void TestTableInfo(bool usenamer) var job = new ThrowImmediatelyDataLoadJob(new HICDatabaseConfiguration(_database.Server, namer), ti); var exitCode = attacher.Attach(job, new GracefulCancellationToken()); - Assert.AreEqual(ExitCodeType.Success, exitCode); + Assert.That(exitCode, Is.EqualTo(ExitCodeType.Success)); using (var con = _database.Server.GetConnection()) { con.Open(); var r = _database.Server.GetCommand($"Select name,name2 from {_table.GetRuntimeName()}", con) .ExecuteReader(); - Assert.IsTrue(r.Read()); - Assert.AreEqual("Bob", r["name"]); - Assert.AreEqual("Munchousain", r["name2"]); - - Assert.IsTrue(r.Read()); - Assert.AreEqual("Franky", r["name"]); - Assert.AreEqual("Hollyw9ood", r["name2"]); + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Bob")); + Assert.That(r["name2"], Is.EqualTo("Munchousain")); + }); + + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Franky")); + Assert.That(r["name2"], Is.EqualTo("Hollyw9ood")); + }); } attacher.LoadCompletedSoDispose(ExitCodeType.Success, ThrowImmediatelyDataLoadEventListener.Quiet); @@ -380,20 +411,26 @@ public void Test_FlatFileAttacher_IgnoreColumns() var job = new ThrowImmediatelyDataLoadJob(new HICDatabaseConfiguration(_database.Server, null), ti); var exitCode = attacher.Attach(job, new GracefulCancellationToken()); - Assert.AreEqual(ExitCodeType.Success, exitCode); + Assert.That(exitCode, Is.EqualTo(ExitCodeType.Success)); using (var con = _database.Server.GetConnection()) { con.Open(); var r = _database.Server.GetCommand($"Select name,name2 from {_table.GetRuntimeName()}", con) .ExecuteReader(); - Assert.IsTrue(r.Read()); - Assert.AreEqual("Bob", r["name"]); - Assert.AreEqual("Munchousain", r["name2"]); - - Assert.IsTrue(r.Read()); - Assert.AreEqual("Franky", r["name"]); - Assert.AreEqual("Hollyw9ood", r["name2"]); + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Bob")); + Assert.That(r["name2"], Is.EqualTo("Munchousain")); + }); + + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["name"], Is.EqualTo("Franky")); + Assert.That(r["name2"], Is.EqualTo("Hollyw9ood")); + }); } attacher.LoadCompletedSoDispose(ExitCodeType.Success, ThrowImmediatelyDataLoadEventListener.Quiet); @@ -449,11 +486,11 @@ public void Test_FlatFileAttacher_AmbiguousDates(DatabaseType type, string val, var job = new ThrowImmediatelyDataLoadJob(new HICDatabaseConfiguration(_database.Server, null), ti); var exitCode = attacher.Attach(job, new GracefulCancellationToken()); - Assert.AreEqual(ExitCodeType.Success, exitCode); + Assert.That(exitCode, Is.EqualTo(ExitCodeType.Success)); attacher.LoadCompletedSoDispose(ExitCodeType.Success, ThrowImmediatelyDataLoadEventListener.Quiet); - Assert.AreEqual(new DateTime(2001, 1, 27), tbl.GetDataTable().Rows[0][0]); + Assert.That(tbl.GetDataTable().Rows[0][0], Is.EqualTo(new DateTime(2001, 1, 27))); File.Delete(filename); tbl.Drop(); @@ -477,8 +514,7 @@ public void Test_TableToLoad_IDNotInLoadMetadata() var ex = Assert.Throws(() => source.Attach(job, new GracefulCancellationToken())); - StringAssert.IsMatch( - "FlatFileAttacher TableToLoad was 'TableNotInLoad' \\(ID=\\d+\\) but that table was not one of the tables in the load:'TableInLoad'", - ex.Message); + Assert.That( + ex.Message, Does.Match("FlatFileAttacher TableToLoad was 'TableNotInLoad' \\(ID=\\d+\\) but that table was not one of the tables in the load:'TableInLoad'")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/HICPipelineTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/HICPipelineTests.cs index 1693be3bd4..d8e8979aa1 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/HICPipelineTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/HICPipelineTests.cs @@ -190,7 +190,7 @@ public void SetUp(DiscoveredServer server) // Ensure the dataset table has been created var datasetTable = DatabaseToLoad.ExpectTable("TestData"); - Assert.IsTrue(datasetTable.Exists()); + Assert.That(datasetTable.Exists()); } public void Dispose() @@ -279,7 +279,7 @@ public void TestSingleJob(bool overrideRAW, bool sendDodgyCredentials) var ex = Assert.Throws(() => runner.Run(RepositoryLocator, ThrowImmediatelyDataLoadEventListener.Quiet, new AcceptAllCheckNotifier(), new GracefulCancellationToken())); - Assert.IsTrue(ex.InnerException.Message.Contains("Login failed for user 'IveGotaLovely'"), + Assert.That(ex.InnerException.Message, Does.Contain("Login failed for user 'IveGotaLovely'"), "Error message did not contain expected text"); return; } @@ -291,8 +291,11 @@ public void TestSingleJob(bool overrideRAW, bool sendDodgyCredentials) var archiveFile = loadDirectory.ForArchiving.EnumerateFiles("*.zip").MaxBy(f => f.FullName); - Assert.NotNull(archiveFile, "Archive file has not been created by the load."); - Assert.IsFalse(loadDirectory.ForLoading.EnumerateFileSystemInfos().Any()); + Assert.Multiple(() => + { + Assert.That(archiveFile, Is.Not.Null, "Archive file has not been created by the load."); + Assert.That(loadDirectory.ForLoading.EnumerateFileSystemInfos().Any(), Is.False); + }); } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/HousekeepingTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/HousekeepingTests.cs index 17fc0322df..22ea11d993 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/HousekeepingTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/HousekeepingTests.cs @@ -42,7 +42,7 @@ public void TestCheckUpdateTrigger() var triggerImplementer = factory.Create(table); var isEnabled = triggerImplementer.GetTriggerStatus(); - Assert.AreEqual(TriggerStatus.Enabled, isEnabled); + Assert.That(isEnabled, Is.EqualTo(TriggerStatus.Enabled)); // disable the trigger and test correct reporting @@ -57,6 +57,6 @@ public void TestCheckUpdateTrigger() } isEnabled = triggerImplementer.GetTriggerStatus(); - Assert.AreEqual(TriggerStatus.Disabled, isEnabled); + Assert.That(isEnabled, Is.EqualTo(TriggerStatus.Disabled)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/ImportFilesDataProviderTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/ImportFilesDataProviderTests.cs index 405a1902bb..3538e9b021 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/ImportFilesDataProviderTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/ImportFilesDataProviderTests.cs @@ -7,7 +7,6 @@ using System; using System.IO; -using System.Linq; using NSubstitute; using NUnit.Framework; using Rdmp.Core.Curation; @@ -64,7 +63,7 @@ public void CopyFiles() provider.Fetch(job, new GracefulCancellationToken()); //destination is empty because nothing matched - Assert.IsEmpty(targetDir.GetFiles()); + Assert.That(targetDir.GetFiles(), Is.Empty); //give it correct pattern provider.FilePattern = "*.txt"; @@ -72,23 +71,32 @@ public void CopyFiles() //execute the provider provider.Fetch(job, new GracefulCancellationToken()); - //both files should exist - Assert.AreEqual(1, targetDir.GetFiles().Length); - Assert.AreEqual(1, sourceDir.GetFiles().Length); + Assert.Multiple(() => + { + //both files should exist + Assert.That(targetDir.GetFiles(), Has.Length.EqualTo(1)); + Assert.That(sourceDir.GetFiles(), Has.Length.EqualTo(1)); + }); //simulate load failure provider.LoadCompletedSoDispose(ExitCodeType.Abort, new ThrowImmediatelyDataLoadJob()); - //both files should exist - Assert.AreEqual(1, targetDir.GetFiles().Length); - Assert.AreEqual(1, sourceDir.GetFiles().Length); + Assert.Multiple(() => + { + //both files should exist + Assert.That(targetDir.GetFiles(), Has.Length.EqualTo(1)); + Assert.That(sourceDir.GetFiles(), Has.Length.EqualTo(1)); + }); //simulate load success provider.LoadCompletedSoDispose(ExitCodeType.Success, new ThrowImmediatelyDataLoadJob()); - //both files should exist because Delete on success is false - Assert.AreEqual(1, targetDir.GetFiles().Length); - Assert.AreEqual(1, sourceDir.GetFiles().Length); + Assert.Multiple(() => + { + //both files should exist because Delete on success is false + Assert.That(targetDir.GetFiles(), Has.Length.EqualTo(1)); + Assert.That(sourceDir.GetFiles(), Has.Length.EqualTo(1)); + }); //change behaviour to delete on successful data loads provider.DeleteFilesOnsuccessfulLoad = true; @@ -96,15 +104,21 @@ public void CopyFiles() //simulate load failure provider.LoadCompletedSoDispose(ExitCodeType.Error, new ThrowImmediatelyDataLoadJob()); - //both files should exist - Assert.AreEqual(1, targetDir.GetFiles().Length); - Assert.AreEqual(1, sourceDir.GetFiles().Length); + Assert.Multiple(() => + { + //both files should exist + Assert.That(targetDir.GetFiles(), Has.Length.EqualTo(1)); + Assert.That(sourceDir.GetFiles(), Has.Length.EqualTo(1)); + }); //simulate load success provider.LoadCompletedSoDispose(ExitCodeType.Success, new ThrowImmediatelyDataLoadJob()); - //only forLoading file should exist (in real life that one would be handled by archivng already) - Assert.AreEqual(1, targetDir.GetFiles().Length); - Assert.AreEqual(0, sourceDir.GetFiles().Length); + Assert.Multiple(() => + { + //only forLoading file should exist (in real life that one would be handled by archivng already) + Assert.That(targetDir.GetFiles(), Has.Length.EqualTo(1)); + Assert.That(sourceDir.GetFiles(), Is.Empty); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/JobDateGenerationStrategyFactoryTestsIntegration.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/JobDateGenerationStrategyFactoryTestsIntegration.cs index fcc1afcfd8..712ce5eda9 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/JobDateGenerationStrategyFactoryTestsIntegration.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/JobDateGenerationStrategyFactoryTestsIntegration.cs @@ -61,8 +61,7 @@ public void CacheProvider_None() { var ex = Assert.Throws(() => _factory.Create(_lp, ThrowImmediatelyDataLoadEventListener.Quiet)); - Assert.IsTrue(ex.Message.StartsWith( - "LoadMetadata JobDateGenerationStrategyFactoryTestsIntegration does not have ANY process tasks of type ProcessTaskType.DataProvider")); + Assert.That(ex.Message, Does.StartWith("LoadMetadata JobDateGenerationStrategyFactoryTestsIntegration does not have ANY process tasks of type ProcessTaskType.DataProvider")); } @@ -79,8 +78,7 @@ public void CacheProvider_NonCachingOne() var ex = Assert.Throws(() => _factory.Create(_lp, ThrowImmediatelyDataLoadEventListener.Quiet)); - Assert.IsTrue(ex.Message.StartsWith( - "LoadMetadata JobDateGenerationStrategyFactoryTestsIntegration has some DataProviders tasks but none of them wrap classes that implement ICachedDataProvider")); + Assert.That(ex.Message, Does.StartWith("LoadMetadata JobDateGenerationStrategyFactoryTestsIntegration has some DataProviders tasks but none of them wrap classes that implement ICachedDataProvider")); } @@ -105,9 +103,8 @@ public void CacheProvider_TwoCachingOnes() var ex = Assert.Throws(() => _factory.Create(_lp, ThrowImmediatelyDataLoadEventListener.Quiet)); - Assert.AreEqual( - "LoadMetadata JobDateGenerationStrategyFactoryTestsIntegration has multiple cache DataProviders tasks (Cache1,Cache2), you are only allowed 1", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("LoadMetadata JobDateGenerationStrategyFactoryTestsIntegration has multiple cache DataProviders tasks (Cache1,Cache2), you are only allowed 1")); } [Test] @@ -135,7 +132,7 @@ public void CacheProvider_NoPipeline() try { var ex = Assert.Throws(() => _factory.Create(_lp, ThrowImmediatelyDataLoadEventListener.Quiet)); - Assert.AreEqual("CacheProgress MyTestCp does not have a Pipeline configured on it", ex.Message); + Assert.That(ex.Message, Is.EqualTo("CacheProgress MyTestCp does not have a Pipeline configured on it")); } finally { @@ -167,9 +164,8 @@ public void CacheProvider_NoCacheProgress() { var ex = Assert.Throws(() => _factory.Create(_lp, ThrowImmediatelyDataLoadEventListener.Quiet)); - Assert.AreEqual( - $"Caching has not begun for this CacheProgress ({_cp.ID}), so there is nothing to load and this strategy should not be used.", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo($"Caching has not begun for this CacheProgress ({_cp.ID}), so there is nothing to load and this strategy should not be used.")); } finally { @@ -205,10 +201,10 @@ public void CacheProvider_Normal() try { var strategy = _factory.Create(_lp, ThrowImmediatelyDataLoadEventListener.Quiet); - Assert.AreEqual(typeof(SingleScheduleCacheDateTrackingStrategy), strategy.GetType()); + Assert.That(strategy.GetType(), Is.EqualTo(typeof(SingleScheduleCacheDateTrackingStrategy))); var dates = strategy.GetDates(10, false); - Assert.AreEqual(0, dates.Count); //zero dates to load because no files in cache + Assert.That(dates, Is.Empty); //zero dates to load because no files in cache File.WriteAllText(Path.Combine(projDir.Cache.FullName, "2001-01-02.zip"), "bobbobbobyobyobyobbzzztproprietarybitztreamzippy"); @@ -218,9 +214,9 @@ public void CacheProvider_Normal() "bobbobbobyobyobyobbzzztproprietarybitztreamzippy"); strategy = _factory.Create(_lp, ThrowImmediatelyDataLoadEventListener.Quiet); - Assert.AreEqual(typeof(SingleScheduleCacheDateTrackingStrategy), strategy.GetType()); + Assert.That(strategy.GetType(), Is.EqualTo(typeof(SingleScheduleCacheDateTrackingStrategy))); dates = strategy.GetDates(10, false); - Assert.AreEqual(3, dates.Count); //zero dates to load because no files in cache + Assert.That(dates, Has.Count.EqualTo(3)); //zero dates to load because no files in cache } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/KVPAttacherTest.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/KVPAttacherTest.cs index 8dbed8328a..09c41eba34 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/KVPAttacherTest.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/KVPAttacherTest.cs @@ -136,7 +136,7 @@ public void KVPAttacherTest_Attach(KVPAttacherTestCase testCase) if (testCase == KVPAttacherTestCase.TwoFilesWithPrimaryKey) expectedRows += 54; - Assert.AreEqual(expectedRows, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(expectedRows)); } finally { @@ -150,9 +150,8 @@ public void KVPAttacherTest_Attach(KVPAttacherTestCase testCase) public void KVPAttacherCheckTest_TableNameMissing() { var ex = Assert.Throws(() => new KVPAttacher().Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual( - "Either argument TableName or TableToLoad must be set Rdmp.Core.DataLoad.Modules.Attachers.KVPAttacher, you should specify this value.", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Either argument TableName or TableToLoad must be set Rdmp.Core.DataLoad.Modules.Attachers.KVPAttacher, you should specify this value.")); } [Test] @@ -164,7 +163,7 @@ public void KVPAttacherCheckTest_FilePathMissing() }; var ex = Assert.Throws(() => kvp.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.IsTrue(ex.Message.StartsWith("Argument FilePattern has not been set")); + Assert.That(ex.Message, Does.StartWith("Argument FilePattern has not been set")); } @@ -190,7 +189,7 @@ public void KVPAttacherCheckTest_BasicArgumentMissing(string missingField) kvp.TargetDataTableValueColumnName = "smith"; var ex = Assert.Throws(() => kvp.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.IsTrue(ex.Message.StartsWith($"Argument {missingField} has not been set")); + Assert.That(ex.Message, Does.StartWith($"Argument {missingField} has not been set")); } [Test] @@ -208,9 +207,8 @@ public void KVPAttacherCheckTest_Crossover(bool isKeyColumnDuplicate) }; var ex = Assert.Throws(() => kvp.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual( - "Field 'dave' is both a PrimaryKeyColumn and a TargetDataTable column, this is not allowed. Your fields Pk1,Pk2,Pketc,Key,Value must all be mutually exclusive", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Field 'dave' is both a PrimaryKeyColumn and a TargetDataTable column, this is not allowed. Your fields Pk1,Pk2,Pketc,Key,Value must all be mutually exclusive")); } [Test] @@ -226,15 +224,14 @@ public void KVPAttacherCheckTest_CrossoverKeyAndValue() }; var ex = Assert.Throws(() => kvp.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("TargetDataTableKeyColumnName cannot be the same as TargetDataTableValueColumnName", - ex.Message); + Assert.That(ex.Message, Is.EqualTo("TargetDataTableKeyColumnName cannot be the same as TargetDataTableValueColumnName")); } private static void CopyToBin(LoadDirectory projDir, string file) { var testFileLocation = Path.Combine(TestContext.CurrentContext.TestDirectory, "DataLoad", "Engine", "Resources", file); - Assert.IsTrue(File.Exists(testFileLocation)); + Assert.That(File.Exists(testFileLocation)); File.Copy(testFileLocation, projDir.ForLoading.FullName + Path.DirectorySeparatorChar + file, true); } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/MigrationStrategyTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/MigrationStrategyTests.cs index e10701c77d..fe1a752a27 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/MigrationStrategyTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/MigrationStrategyTests.cs @@ -9,7 +9,6 @@ using FAnsi.Discovery; using NSubstitute; using NUnit.Framework; -using Rdmp.Core.DataLoad.Engine.Job; using Rdmp.Core.DataLoad.Engine.Migration; using Rdmp.Core.DataLoad.Engine.Migration.QueryBuilding; using Tests.Common; @@ -32,6 +31,6 @@ public void OverwriteMigrationStrategy_NoPrimaryKey() var migrationFieldProcessor = Substitute.For(); var ex = Assert.Throws(() => new MigrationColumnSet(from, to, migrationFieldProcessor)); - Assert.AreEqual("There are no primary keys declared in table Bob", ex.Message); + Assert.That(ex.Message, Is.EqualTo("There are no primary keys declared in table Bob")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PayloadTest.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PayloadTest.cs index e59b4cce06..5ce2ff215a 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PayloadTest.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PayloadTest.cs @@ -70,7 +70,7 @@ public void TestPayloadInjection() procedure.Run(new GracefulCancellationToken(), payload); - Assert.IsTrue(Success, "Expected IAttacher to detect Payload and set this property to true"); + Assert.That(Success, "Expected IAttacher to detect Payload and set this property to true"); } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/ArchiveFilesTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/ArchiveFilesTests.cs index 31bada0452..12deb99e8f 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/ArchiveFilesTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/ArchiveFilesTests.cs @@ -57,14 +57,17 @@ public void TestAllFilesAreArchived() // first we expect a file in forArchiving called 1.zip var zipFilename = Path.Combine(forArchiving.FullName, "1.zip"); - Assert.True(File.Exists(zipFilename)); + Assert.That(File.Exists(zipFilename)); // there should be two entries using var archive = ZipFile.Open(zipFilename, ZipArchiveMode.Read); - Assert.AreEqual(2, archive.Entries.Count, + Assert.That(archive.Entries, Has.Count.EqualTo(2), "There should be two entries in this archive: one from the root and one from the subdirectory"); - Assert.IsTrue(archive.Entries.Any(entry => entry.FullName.Equals(@"subdir/subdir.txt"))); - Assert.IsTrue(archive.Entries.Any(entry => entry.FullName.Equals(@"test.txt"))); + Assert.Multiple(() => + { + Assert.That(archive.Entries.Any(static entry => entry.FullName.Equals(@"subdir/subdir.txt"))); + Assert.That(archive.Entries.Any(static entry => entry.FullName.Equals(@"test.txt"))); + }); } finally { @@ -94,7 +97,7 @@ public void CreateArchiveWithNoFiles_ShouldThrow() foreach (var fileInfo in loadDirectory.ForArchiving.GetFiles("*.zip")) Console.WriteLine($"About to throw SetUp because of zip file:{fileInfo.FullName}"); - Assert.IsFalse(loadDirectory.ForArchiving.GetFiles("*.zip").Any(), + Assert.That(loadDirectory.ForArchiving.GetFiles("*.zip").Any(), Is.False, "There should not be any zip files in the archive directory!"); } finally diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/ComponentCompatibilityTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/ComponentCompatibilityTests.cs index fbf27cfa90..12eddb0b5d 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/ComponentCompatibilityTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/ComponentCompatibilityTests.cs @@ -18,6 +18,6 @@ public class ComponentCompatibilityTests : UnitTests [Test] public void GetComponentsCompatibleWithBulkInsertContext() { - Assert.True(MEF.GetTypes>().Any()); + Assert.That(MEF.GetTypes>().Any()); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/AliasHandlerTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/AliasHandlerTests.cs index a7deaf37ce..009bbb3a6c 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/AliasHandlerTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/AliasHandlerTests.cs @@ -78,9 +78,8 @@ public void ThrowBecause_ColumnNotInInputDataTable() _handler.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.AreEqual( - "You asked to resolve aliases on a column called 'input' but no column by that name appeared in the DataTable being processed. Columns in that table were:cannonballer", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("You asked to resolve aliases on a column called 'input' but no column by that name appeared in the DataTable being processed. Columns in that table were:cannonballer")); } [Test] @@ -100,7 +99,7 @@ public void ThrowBecause_NameAndAliasSameValue() var ex = Assert.Throws(() => _handler.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.IsTrue(ex.Message.StartsWith("Alias table SQL should only return aliases not exact matches")); + Assert.That(ex.Message, Does.StartWith("Alias table SQL should only return aliases not exact matches")); } [Test] @@ -124,7 +123,7 @@ public void ThrowBecause_ThreeColumnAliasTable() _handler.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.IsTrue(ex.Message.Contains("Alias table SQL resulted in 3 fields being returned")); + Assert.That(ex.Message, Does.Contain("Alias table SQL resulted in 3 fields being returned")); } [Test] @@ -140,7 +139,7 @@ public void NoAliases() var result = _handler.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(2, result.Rows.Count); + Assert.That(result.Rows, Has.Count.EqualTo(2)); } @@ -174,16 +173,18 @@ public void ResolveTwoNameAlias() var result = _handler.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(4, result.Rows.Count); + Assert.That(result.Rows, Has.Count.EqualTo(4)); - Assert.AreEqual(299, result.Rows[2][0]); - Assert.AreEqual("freddie", result.Rows[2][1]); //the original input row which had an alias on it - Assert.AreEqual(300, result.Rows[2][2]); - - Assert.AreEqual(299, result.Rows[3][0]); - Assert.AreEqual("craig", - result.Rows[3][1]); //The new row that should have appeared to resolve the freddie=craig alias - Assert.AreEqual(300, result.Rows[3][2]); //value should match the input array + Assert.Multiple(() => + { + Assert.That(result.Rows[2][0], Is.EqualTo(299)); + Assert.That(result.Rows[2][1], Is.EqualTo("freddie")); //the original input row which had an alias on it + Assert.That(result.Rows[2][2], Is.EqualTo(300)); + + Assert.That(result.Rows[3][0], Is.EqualTo(299)); + Assert.That(result.Rows[3][1], Is.EqualTo("craig")); //The new row that should have appeared to resolve the freddie=craig alias + Assert.That(result.Rows[3][2], Is.EqualTo(300)); //value should match the input array + }); } [Test] @@ -203,22 +204,23 @@ public void ResolveThreeNameAlias() var result = _handler.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(5, result.Rows.Count); + Assert.That(result.Rows, Has.Count.EqualTo(5)); - Assert.AreEqual(99, result.Rows[0][0]); - Assert.AreEqual("pepey", result.Rows[0][1]); //the original input row which had an alias on it - Assert.AreEqual(100, result.Rows[0][2]); + Assert.Multiple(() => + { + Assert.That(result.Rows[0][0], Is.EqualTo(99)); + Assert.That(result.Rows[0][1], Is.EqualTo("pepey")); //the original input row which had an alias on it + Assert.That(result.Rows[0][2], Is.EqualTo(100)); - //new rows are added at the end of the DataTable - Assert.AreEqual(99, result.Rows[3][0]); - Assert.AreEqual("paul", - result.Rows[3][1]); //The new row that should have appeared to resolve the pepey=paul=peter alias - Assert.AreEqual(100, result.Rows[3][2]); //value should match the input array + //new rows are added at the end of the DataTable + Assert.That(result.Rows[3][0], Is.EqualTo(99)); + Assert.That(result.Rows[3][1], Is.EqualTo("paul")); //The new row that should have appeared to resolve the pepey=paul=peter alias + Assert.That(result.Rows[3][2], Is.EqualTo(100)); //value should match the input array - Assert.AreEqual(99, result.Rows[4][0]); - Assert.AreEqual("peter", - result.Rows[4][1]); //The new row that should have appeared to resolve the pepey=paul=peter alias - Assert.AreEqual(100, result.Rows[4][2]); //value should match the input array + Assert.That(result.Rows[4][0], Is.EqualTo(99)); + Assert.That(result.Rows[4][1], Is.EqualTo("peter")); //The new row that should have appeared to resolve the pepey=paul=peter alias + Assert.That(result.Rows[4][2], Is.EqualTo(100)); //value should match the input array + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/ColumnSwapperTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/ColumnSwapperTests.cs index bfa3b10f9d..16c8d02948 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/ColumnSwapperTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/ColumnSwapperTests.cs @@ -69,22 +69,25 @@ public void TestColumnSwapper_NormalUseCase(bool keepInputColumnToo) new GracefulCancellationToken()); //in should be there or not depending on the setting KeepInputColumnToo - Assert.AreEqual(keepInputColumnToo, resultDt.Columns.Contains("In")); + Assert.That(resultDt.Columns.Contains("In"), Is.EqualTo(keepInputColumnToo)); AreBasicallyEquals(1, resultDt.Rows[0]["Out"]); - Assert.AreEqual("Dave", resultDt.Rows[0]["Name"]); + Assert.That(resultDt.Rows[0]["Name"], Is.EqualTo("Dave")); AreBasicallyEquals(1, resultDt.Rows[1]["Out"]); - Assert.AreEqual("Dave", resultDt.Rows[1]["Name"]); + Assert.That(resultDt.Rows[1]["Name"], Is.EqualTo("Dave")); AreBasicallyEquals(2, resultDt.Rows[2]["Out"]); - Assert.AreEqual("Frank", resultDt.Rows[2]["Name"]); + Assert.That(resultDt.Rows[2]["Name"], Is.EqualTo("Frank")); if (keepInputColumnToo) { - Assert.AreEqual("A", resultDt.Rows[0]["In"]); - Assert.AreEqual("A", resultDt.Rows[1]["In"]); - Assert.AreEqual("B", resultDt.Rows[2]["In"]); + Assert.Multiple(() => + { + Assert.That(resultDt.Rows[0]["In"], Is.EqualTo("A")); + Assert.That(resultDt.Rows[1]["In"], Is.EqualTo("A")); + Assert.That(resultDt.Rows[2]["In"], Is.EqualTo("B")); + }); } } @@ -129,7 +132,7 @@ public void TestColumnSwapper_AlternateColumnNames(bool keepInputColumnToo) // Our pipeline data does not have a column called In but instead it is called In2 var ex = Assert.Throws(() => swapper.ProcessPipelineData(dtToSwap, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.AreEqual("DataTable did not contain a field called 'In'", ex.Message); + Assert.That(ex.Message, Is.EqualTo("DataTable did not contain a field called 'In'")); // Tell the swapper about the new name swapper.InputFromColumn = "In2"; @@ -139,22 +142,25 @@ public void TestColumnSwapper_AlternateColumnNames(bool keepInputColumnToo) new GracefulCancellationToken()); //in should be there or not depending on the setting KeepInputColumnToo - Assert.AreEqual(keepInputColumnToo, resultDt.Columns.Contains("In2")); + Assert.That(resultDt.Columns.Contains("In2"), Is.EqualTo(keepInputColumnToo)); AreBasicallyEquals(1, resultDt.Rows[0]["Out2"]); - Assert.AreEqual("Dave", resultDt.Rows[0]["Name"]); + Assert.That(resultDt.Rows[0]["Name"], Is.EqualTo("Dave")); AreBasicallyEquals(1, resultDt.Rows[1]["Out2"]); - Assert.AreEqual("Dave", resultDt.Rows[1]["Name"]); + Assert.That(resultDt.Rows[1]["Name"], Is.EqualTo("Dave")); AreBasicallyEquals(2, resultDt.Rows[2]["Out2"]); - Assert.AreEqual("Frank", resultDt.Rows[2]["Name"]); + Assert.That(resultDt.Rows[2]["Name"], Is.EqualTo("Frank")); if (keepInputColumnToo) { - Assert.AreEqual("A", resultDt.Rows[0]["In2"]); - Assert.AreEqual("A", resultDt.Rows[1]["In2"]); - Assert.AreEqual("B", resultDt.Rows[2]["In2"]); + Assert.Multiple(() => + { + Assert.That(resultDt.Rows[0]["In2"], Is.EqualTo("A")); + Assert.That(resultDt.Rows[1]["In2"], Is.EqualTo("A")); + Assert.That(resultDt.Rows[2]["In2"], Is.EqualTo("B")); + }); } } @@ -205,16 +211,16 @@ public void TestColumnSwapper_InPlaceSwapNoNewCols(bool keepInputColumnToo) new GracefulCancellationToken()); // in ALWAYS be there, because it is an in place update - ignore KeepInputColumnToo - Assert.True(resultDt.Columns.Contains("In2")); + Assert.That(resultDt.Columns.Contains("In2")); AreBasicallyEquals(1, resultDt.Rows[0]["In2"]); - Assert.AreEqual("Dave", resultDt.Rows[0]["Name"]); + Assert.That(resultDt.Rows[0]["Name"], Is.EqualTo("Dave")); AreBasicallyEquals(1, resultDt.Rows[1]["In2"]); - Assert.AreEqual("Dave", resultDt.Rows[1]["Name"]); + Assert.That(resultDt.Rows[1]["Name"], Is.EqualTo("Dave")); AreBasicallyEquals(2, resultDt.Rows[2]["In2"]); - Assert.AreEqual("Frank", resultDt.Rows[2]["Name"]); + Assert.That(resultDt.Rows[2]["Name"], Is.EqualTo("Frank")); } [TestCase(AliasResolutionStrategy.CrashIfAliasesFound)] @@ -266,16 +272,16 @@ public void TestColumnSwapper_Aliases(AliasResolutionStrategy strategy) new GracefulCancellationToken()); AreBasicallyEquals(1, resultDt.Rows[0]["Out"]); - Assert.AreEqual("Dave", resultDt.Rows[0]["Name"]); + Assert.That(resultDt.Rows[0]["Name"], Is.EqualTo("Dave")); //we get the first alias (4) AreBasicallyEquals(4, resultDt.Rows[1]["Out"]); - Assert.AreEqual("Dandy", resultDt.Rows[1]["Name"]); + Assert.That(resultDt.Rows[1]["Name"], Is.EqualTo("Dandy")); AreBasicallyEquals(60, resultDt.Rows[1]["Age"]); //and the second alias (5) AreBasicallyEquals(5, resultDt.Rows[2]["Out"]); - Assert.AreEqual("Dandy", resultDt.Rows[2]["Name"]); + Assert.That(resultDt.Rows[2]["Name"], Is.EqualTo("Dandy")); AreBasicallyEquals(60, resultDt.Rows[1]["Age"]); break; default: @@ -331,9 +337,9 @@ public void TestColumnSwapper_MissingMappings(bool crashIfNoMappingsFound) var resultDt = swapper.ProcessPipelineData(dtToSwap, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(1, resultDt.Rows.Count); + Assert.That(resultDt.Rows, Has.Count.EqualTo(1)); AreBasicallyEquals(1, resultDt.Rows[0]["Out"]); - Assert.AreEqual("Dave", resultDt.Rows[0]["Name"]); + Assert.That(resultDt.Rows[0]["Name"], Is.EqualTo("Dave")); } } @@ -379,13 +385,13 @@ public void TestColumnSwapper_ProjectSpecificMappings() using var resultDt = swapper.ProcessPipelineData(dtToSwap, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(2, resultDt.Rows.Count); + Assert.That(resultDt.Rows, Has.Count.EqualTo(2)); // Should have project specific results for A of 1 and for B of 3 because the ProjectNumber is 1 AreBasicallyEquals(1, resultDt.Rows[0]["Out"]); - Assert.AreEqual("Dave", resultDt.Rows[0]["Name"]); + Assert.That(resultDt.Rows[0]["Name"], Is.EqualTo("Dave")); AreBasicallyEquals(3, resultDt.Rows[1]["Out"]); - Assert.AreEqual("Frank", resultDt.Rows[1]["Name"]); + Assert.That(resultDt.Rows[1]["Name"], Is.EqualTo("Frank")); } /// @@ -425,12 +431,12 @@ public void TestColumnSwapper_InputTableNulls() var resultDt = swapper.ProcessPipelineData(dtToSwap, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(2, resultDt.Rows.Count); + Assert.That(resultDt.Rows, Has.Count.EqualTo(2)); AreBasicallyEquals(1, resultDt.Rows[0]["Out"]); - Assert.AreEqual("Dave", resultDt.Rows[0]["Name"]); + Assert.That(resultDt.Rows[0]["Name"], Is.EqualTo("Dave")); AreBasicallyEquals(DBNull.Value, resultDt.Rows[1]["Out"]); - Assert.AreEqual("Bob", resultDt.Rows[1]["Name"]); + Assert.That(resultDt.Rows[1]["Name"], Is.EqualTo("Bob")); } /// @@ -472,16 +478,18 @@ public void TestColumnSwapper_MappingTableNulls() var resultDt = swapper.ProcessPipelineData(dtToSwap, toMem, new GracefulCancellationToken()); - //this is the primary thing we are testing here - Assert.Contains("Discarded 1 Null key values read from mapping table", - toMem.GetAllMessagesByProgressEventType()[ProgressEventType.Warning].Select(m => m.Message).ToArray()); + Assert.Multiple(() => + { + //this is the primary thing we are testing here + Assert.That(toMem.GetAllMessagesByProgressEventType()[ProgressEventType.Warning].Select(m => m.Message).ToArray(), Does.Contain("Discarded 1 Null key values read from mapping table")); - Assert.AreEqual(2, resultDt.Rows.Count); + Assert.That(resultDt.Rows, Has.Count.EqualTo(2)); + }); AreBasicallyEquals(1, resultDt.Rows[0]["Out"]); - Assert.AreEqual("Dave", resultDt.Rows[0]["Name"]); + Assert.That(resultDt.Rows[0]["Name"], Is.EqualTo("Dave")); AreBasicallyEquals(DBNull.Value, resultDt.Rows[1]["Out"]); - Assert.AreEqual("Bob", resultDt.Rows[1]["Name"]); + Assert.That(resultDt.Rows[1]["Name"], Is.EqualTo("Bob")); } /// @@ -505,7 +513,7 @@ public void TestColumnSwapper_MixedDatatypes_StringInDatabase() Import(mapTbl = db.CreateTable("Map", dt), out var map, out var mapCols); - Assert.AreEqual(typeof(string), mapTbl.DiscoverColumn("In").DataType.GetCSharpDataType(), + Assert.That(mapTbl.DiscoverColumn("In").DataType.GetCSharpDataType(), Is.EqualTo(typeof(string)), "Expected map to be of string datatype"); var swapper = new ColumnSwapper @@ -525,9 +533,9 @@ public void TestColumnSwapper_MixedDatatypes_StringInDatabase() var resultDt = swapper.ProcessPipelineData(dtToSwap, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(1, resultDt.Rows.Count); + Assert.That(resultDt.Rows, Has.Count.EqualTo(1)); AreBasicallyEquals(2, resultDt.Rows[0]["Out"]); - Assert.AreEqual("Dave", resultDt.Rows[0]["Name"]); + Assert.That(resultDt.Rows[0]["Name"], Is.EqualTo("Dave")); } @@ -551,7 +559,7 @@ public void TestColumnSwapper_MixedDatatypes_IntegerInDatabase() Import(mapTbl = db.CreateTable("Map", dt), out var map, out var mapCols); - Assert.AreEqual(typeof(int), mapTbl.DiscoverColumn("In").DataType.GetCSharpDataType(), + Assert.That(mapTbl.DiscoverColumn("In").DataType.GetCSharpDataType(), Is.EqualTo(typeof(int)), "Expected map to be of int datatype"); var swapper = new ColumnSwapper @@ -571,9 +579,9 @@ public void TestColumnSwapper_MixedDatatypes_IntegerInDatabase() var resultDt = swapper.ProcessPipelineData(dtToSwap, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(1, resultDt.Rows.Count); + Assert.That(resultDt.Rows, Has.Count.EqualTo(1)); AreBasicallyEquals(2, resultDt.Rows[0]["Out"]); - Assert.AreEqual("Dave", resultDt.Rows[0]["Name"]); + Assert.That(resultDt.Rows[0]["Name"], Is.EqualTo("Dave")); } private static IExtractDatasetCommand GetMockExtractDatasetCommand() diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/RemoveDuplicatesTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/RemoveDuplicatesTests.cs index 6ebbc6e522..309119e194 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/RemoveDuplicatesTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/RemoveDuplicatesTests.cs @@ -18,7 +18,7 @@ public class RemoveDuplicatesTests [Test] public void TestRemovingDuplicatesFromDataTable() { - var dt = new DataTable(); + using var dt = new DataTable(); dt.Columns.Add("Col1"); dt.Columns.Add("Col2", typeof(int)); @@ -26,38 +26,44 @@ public void TestRemovingDuplicatesFromDataTable() dt.Rows.Add("Fish", 123); dt.Rows.Add("Fish", 123); - Assert.AreEqual(3, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(3)); - Assert.AreEqual(123, dt.Rows[0]["Col2"]); + Assert.That(dt.Rows[0]["Col2"], Is.EqualTo(123)); var receiver = new ToMemoryDataLoadEventListener(true); var result = new RemoveDuplicates().ProcessPipelineData(dt, receiver, new GracefulCancellationToken()); - //should have told us that it processed 3 rows - Assert.AreEqual(3, receiver.LastProgressRecieivedByTaskName["Evaluating For Duplicates"].Progress.Value); - - //and discarded 2 of them as duplicates - Assert.AreEqual(2, receiver.LastProgressRecieivedByTaskName["Discarding Duplicates"].Progress.Value); - - Assert.AreEqual(1, result.Rows.Count); - Assert.AreEqual("Fish", result.Rows[0]["Col1"]); - Assert.AreEqual(123, result.Rows[0]["Col2"]); + Assert.Multiple(() => + { + //should have told us that it processed 3 rows + Assert.That(receiver.LastProgressRecieivedByTaskName["Evaluating For Duplicates"].Progress.Value, Is.EqualTo(3)); + + //and discarded 2 of them as duplicates + Assert.That(receiver.LastProgressRecieivedByTaskName["Discarding Duplicates"].Progress.Value, Is.EqualTo(2)); + + Assert.That(result.Rows, Has.Count.EqualTo(1)); + }); + Assert.Multiple(() => + { + Assert.That(result.Rows[0]["Col1"], Is.EqualTo("Fish")); + Assert.That(result.Rows[0]["Col2"], Is.EqualTo(123)); + }); } [Test] public void TestEmptyDataTable() { - Assert.AreEqual(0, - new RemoveDuplicates().ProcessPipelineData(new DataTable(), ThrowImmediatelyDataLoadEventListener.Quiet, - new GracefulCancellationToken()).Rows.Count); + using var dt = new DataTable(); + Assert.That(new RemoveDuplicates().ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, + new GracefulCancellationToken()).Rows, Is.Empty); } [Test] public void TestMultipleBatches() { - var dt = new DataTable(); + using var dt = new DataTable(); dt.Columns.Add("Col1"); dt.Columns.Add("Col2", typeof(int)); @@ -75,15 +81,16 @@ public void TestMultipleBatches() var remover = new RemoveDuplicates(); - //send it the batch with the duplication it will return 1 row - Assert.AreEqual(1, - remover.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, - new GracefulCancellationToken()).Rows.Count); + Assert.Multiple(() => + { + //send it the batch with the duplication it will return 1 row + Assert.That(remover.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, + new GracefulCancellationToken()).Rows, Has.Count.EqualTo(1)); - //now send it the second batch which contains 2 records, one duplication against first batch and one new one, expect only 1 row to come back - Assert.AreEqual(1, - remover.ProcessPipelineData(dt2, ThrowImmediatelyDataLoadEventListener.Quiet, - new GracefulCancellationToken()).Rows.Count); + //now send it the second batch which contains 2 records, one duplication against first batch and one new one, expect only 1 row to come back + Assert.That(remover.ProcessPipelineData(dt2, ThrowImmediatelyDataLoadEventListener.Quiet, + new GracefulCancellationToken()).Rows, Has.Count.EqualTo(1)); + }); } [Test] @@ -102,11 +109,13 @@ public void TestNulls() var remover = new RemoveDuplicates(); - Assert.AreEqual(6, dt.Rows.Count); + Assert.Multiple(() => + { + Assert.That(dt.Rows, Has.Count.EqualTo(6)); - //send it the batch with the duplication it will return 5 rows (the only duplicate is the double null) - Assert.AreEqual(5, - remover.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, - new GracefulCancellationToken()).Rows.Count); + //send it the batch with the duplication it will return 5 rows (the only duplicate is the double null) + Assert.That(remover.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, + new GracefulCancellationToken()).Rows, Has.Count.EqualTo(5)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/TransposerTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/TransposerTests.cs index c310515340..5548aadeec 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/TransposerTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Components/TransposerTests.cs @@ -39,9 +39,8 @@ public void TransposerTest_ThrowOnDualBatches() transposer.ProcessPipelineData(dt, new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken()); var ex = Assert.Throws(() => transposer.ProcessPipelineData(dt, new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken())); - Assert.AreEqual( - "Error, we received multiple batches, Transposer only works when all the data arrives in a single DataTable", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Error, we received multiple batches, Transposer only works when all the data arrives in a single DataTable")); } [Test] @@ -51,7 +50,7 @@ public void TransposerTest_ThrowOnEmptyDataTable() var ex = Assert.Throws(() => transposer.ProcessPipelineData(new DataTable(), new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken())); - Assert.AreEqual("DataTable toProcess had 0 rows and 0 columns, thus it cannot be transposed", ex.Message); + Assert.That(ex.Message, Is.EqualTo("DataTable toProcess had 0 rows and 0 columns, thus it cannot be transposed")); } @@ -74,11 +73,11 @@ public void TransposerTest_TableTransposed() expectedResult.Rows.Add("Gateau", "40", "33", "5"); for (var i = 0; i < actual.Columns.Count; i++) - Assert.AreEqual(expectedResult.Columns[i].ColumnName, actual.Columns[i].ColumnName); + Assert.That(actual.Columns[i].ColumnName, Is.EqualTo(expectedResult.Columns[i].ColumnName)); for (var i = 0; i < expectedResult.Rows.Count; i++) for (var j = 0; j < actual.Columns.Count; j++) - Assert.AreEqual(expectedResult.Rows[i][j], actual.Rows[i][j]); + Assert.That(actual.Rows[i][j], Is.EqualTo(expectedResult.Rows[i][j])); } [Test] @@ -93,7 +92,7 @@ public void TestTransposerDodgyHeaders() var actual = transposer.ProcessPipelineData(dt, new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken()); - Assert.IsTrue(actual.Columns.Contains("_32GramMax")); + Assert.That(actual.Columns.Contains("_32GramMax")); dt.Rows.Remove(dr); } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/PipelineArgumentTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/PipelineArgumentTests.cs index d55c7d4eb0..6d09abd6df 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/PipelineArgumentTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/PipelineArgumentTests.cs @@ -41,8 +41,11 @@ public void TestIArgumentsForNullableTypes(Type nullableType, object value) arg.SetType(nullableType); arg.SetValue(value); - Assert.AreEqual(nullableType, arg.GetSystemType()); - Assert.AreEqual(value, arg.GetValueAsSystemType()); + Assert.Multiple(() => + { + Assert.That(arg.GetSystemType(), Is.EqualTo(nullableType)); + Assert.That(arg.GetValueAsSystemType(), Is.EqualTo(value)); + }); } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/PipelineReadPerformanceTest.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/PipelineReadPerformanceTest.cs index 5a1e3c75a1..576bb58d5b 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/PipelineReadPerformanceTest.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/PipelineReadPerformanceTest.cs @@ -35,7 +35,7 @@ public void BulkTestDataContainsExpectedNumberOfRows() var manualCount = Convert.ToInt32(cmd.ExecuteScalar()); //manual count matches expected - Assert.AreEqual(_bulkTestData.ExpectedNumberOfRowsInTestData, manualCount); + Assert.That(manualCount, Is.EqualTo(_bulkTestData.ExpectedNumberOfRowsInTestData)); //now get the fast approximate rowcount var fastRowcount = _bulkTestData.BulkDataDatabase @@ -43,6 +43,6 @@ public void BulkTestDataContainsExpectedNumberOfRows() .GetRowCount(); //it should also match - Assert.AreEqual(_bulkTestData.ExpectedNumberOfRowsInTestData, fastRowcount); + Assert.That(fastRowcount, Is.EqualTo(_bulkTestData.ExpectedNumberOfRowsInTestData)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests.cs index 28a10e8485..7c631c6b67 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests.cs @@ -47,7 +47,7 @@ public void FileToLoadNotSet_Throws() var source = new DelimitedFlatFileDataFlowSource(); var ex = Assert.Throws(() => source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - StringAssert.Contains("_fileToLoad was not set", ex.Message); + Assert.That(ex.Message, Does.Contain("_fileToLoad was not set")); } [Test] @@ -58,7 +58,7 @@ public void SeparatorNotSet_Throws() source.PreInitialize(new FlatFileToLoad(testFile), ThrowImmediatelyDataLoadEventListener.Quiet); var ex = Assert.Throws(() => source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - StringAssert.Contains("Separator has not been set", ex.Message); + Assert.That(ex.Message, Does.Contain("Separator has not been set")); } [Test] @@ -78,17 +78,22 @@ public void LoadCSVWithCorrectDatatypes_ForceHeadersWhitespace() Console.WriteLine( $"Resulting columns were:{string.Join(",", chunk.Columns.Cast().Select(c => c.ColumnName))}"); - Assert.IsTrue(chunk.Columns.Contains("chi")); //notice the lack of whitespace! - Assert.IsTrue( - chunk.Columns - .Contains("study ID")); //whitespace is allowed in the middle though... because we like a challenge! - - Assert.AreEqual(3, chunk.Columns.Count); - Assert.AreEqual(1, chunk.Rows.Count); - Assert.AreEqual("0101010101", chunk.Rows[0][0]); - Assert.AreEqual(5, chunk.Rows[0][1]); - Assert.AreEqual(new DateTime(2001, 1, 5), - chunk.Rows[0][2]); //notice the strong typing (we are not looking for strings here) + Assert.Multiple(() => + { + Assert.That(chunk.Columns.Contains("chi")); //notice the lack of whitespace! + Assert.That( + chunk.Columns + .Contains("study ID")); //whitespace is allowed in the middle though... because we like a challenge! + + Assert.That(chunk.Columns, Has.Count.EqualTo(3)); + Assert.That(chunk.Rows, Has.Count.EqualTo(1)); + }); + Assert.Multiple(() => + { + Assert.That(chunk.Rows[0][0], Is.EqualTo("0101010101")); + Assert.That(chunk.Rows[0][1], Is.EqualTo(5)); + Assert.That(chunk.Rows[0][2], Is.EqualTo(new DateTime(2001, 1, 5))); //notice the strong typing (we are not looking for strings here) + }); source.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, null); } @@ -104,12 +109,17 @@ public void LoadCSVWithCorrectDatatypes_DatatypesAreCorrect() var chunk = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(3, chunk.Columns.Count); - Assert.AreEqual(1, chunk.Rows.Count); - Assert.AreEqual("0101010101", chunk.Rows[0][0]); - Assert.AreEqual(5, chunk.Rows[0][1]); - Assert.AreEqual(new DateTime(2001, 1, 5), - chunk.Rows[0][2]); //notice the strong typing (we are not looking for strings here) + Assert.Multiple(() => + { + Assert.That(chunk.Columns, Has.Count.EqualTo(3)); + Assert.That(chunk.Rows, Has.Count.EqualTo(1)); + }); + Assert.Multiple(() => + { + Assert.That(chunk.Rows[0][0], Is.EqualTo("0101010101")); + Assert.That(chunk.Rows[0][1], Is.EqualTo(5)); + Assert.That(chunk.Rows[0][2], Is.EqualTo(new DateTime(2001, 1, 5))); //notice the strong typing (we are not looking for strings here) + }); source.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, null); } @@ -128,13 +138,19 @@ public void OverrideDatatypes_ForcedFreakyTypesCorrect() //preview should be correct var preview = source.TryGetPreview(); - Assert.AreEqual(typeof(string), preview.Columns["StudyID"].DataType); - Assert.AreEqual("5", preview.Rows[0]["StudyID"]); + Assert.Multiple(() => + { + Assert.That(preview.Columns["StudyID"].DataType, Is.EqualTo(typeof(string))); + Assert.That(preview.Rows[0]["StudyID"], Is.EqualTo("5")); + }); //as should live run var chunk = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(typeof(string), chunk.Columns["StudyID"].DataType); - Assert.AreEqual("5", chunk.Rows[0]["StudyID"]); + Assert.Multiple(() => + { + Assert.That(chunk.Columns["StudyID"].DataType, Is.EqualTo(typeof(string))); + Assert.That(chunk.Rows[0]["StudyID"], Is.EqualTo("5")); + }); source.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, null); } @@ -163,10 +179,13 @@ public void TestIgnoreQuotes() source.MaxBatchSize = 10000; source.StronglyTypeInput = true; //makes the source interpret the file types properly var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual("\"Sick\" headaches", dt.Rows[0][1]); - Assert.AreEqual("2\" length of wood", dt.Rows[1][1]); - Assert.AreEqual("\"\"The bends\"\"", dt.Rows[2][1]); + Assert.That(dt.Rows, Has.Count.EqualTo(3)); + Assert.Multiple(() => + { + Assert.That(dt.Rows[0][1], Is.EqualTo("\"Sick\" headaches")); + Assert.That(dt.Rows[1][1], Is.EqualTo("2\" length of wood")); + Assert.That(dt.Rows[2][1], Is.EqualTo("\"\"The bends\"\"")); + }); source.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, null); } @@ -207,24 +226,23 @@ public void BadDataTestExtraColumns(BadDataHandlingStrategy strategy) case BadDataHandlingStrategy.ThrowException: var ex = Assert.Throws(() => source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - StringAssert.Contains("line 4", ex.Message); + Assert.That(ex.Message, Does.Contain("line 4")); break; case BadDataHandlingStrategy.IgnoreRows: var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.IsNotNull(dt); + Assert.That(dt, Is.Not.Null); - Assert.AreEqual(4, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(4)); break; case BadDataHandlingStrategy.DivertRows: var dt2 = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(4, dt2.Rows.Count); + Assert.That(dt2.Rows, Has.Count.EqualTo(4)); - Assert.IsNotNull(source.EventHandlers.DivertErrorsFile); + Assert.That(source.EventHandlers.DivertErrorsFile, Is.Not.Null); - Assert.AreEqual($"0101010101,5,2001-01-05,fish,watafak{Environment.NewLine}", - File.ReadAllText(source.EventHandlers.DivertErrorsFile.FullName)); + Assert.That(File.ReadAllText(source.EventHandlers.DivertErrorsFile.FullName), Is.EqualTo($"0101010101,5,2001-01-05,fish,watafak{Environment.NewLine}")); break; default: @@ -265,8 +283,8 @@ public void DelimitedFlatFileDataFlowSource_ProperQuoteEscaping() try { var chunk = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(2, chunk.Rows.Count); - Assert.AreEqual("Dave is \"over\" 1000 years old", chunk.Rows[1][2]); + Assert.That(chunk.Rows, Has.Count.EqualTo(2)); + Assert.That(chunk.Rows[1][2], Is.EqualTo("Dave is \"over\" 1000 years old")); } finally { @@ -311,11 +329,13 @@ public void DelimitedFlatFileDataFlowSource_LoadDataWithQuotesInMiddle_IgnoreBad try { var chunk = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(5, chunk.Rows.Count); - Assert.AreEqual("Dave is \"over\" 1000 years old", chunk.Rows[1][2]); - Assert.AreEqual($"Dave is {Environment.NewLine}over 1000 years old", chunk.Rows[2][2]); - Assert.AreEqual("Dave is over\" 1000 years old\"", - chunk.Rows[3][2]); //notice this line drops some of the quotes, we just have to live with that + Assert.That(chunk.Rows, Has.Count.EqualTo(5)); + Assert.Multiple(() => + { + Assert.That(chunk.Rows[1][2], Is.EqualTo("Dave is \"over\" 1000 years old")); + Assert.That(chunk.Rows[2][2], Is.EqualTo($"Dave is {Environment.NewLine}over 1000 years old")); + Assert.That(chunk.Rows[3][2], Is.EqualTo("Dave is over\" 1000 years old\"")); //notice this line drops some of the quotes, we just have to live with that + }); } finally { @@ -357,7 +377,7 @@ public void DelimitedFlatFileDataFlowSource_TrashFile_IgnoreBadReads() { var ex = Assert.Throws(() => source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.AreEqual("Bad data found on line 3", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Bad data found on line 3")); } finally { @@ -396,7 +416,7 @@ public void DelimitedFlatFileDataFlowSource_LoadDataWithQuotesInMiddle_WithMulti { var ex = Assert.Throws(() => source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.AreEqual("Bad data found on line 3", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Bad data found on line 3")); } finally { @@ -441,24 +461,23 @@ public void BadDataTestExtraColumns_ErrorIsOnLastLine(BadDataHandlingStrategy st case BadDataHandlingStrategy.ThrowException: var ex = Assert.Throws(() => source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - StringAssert.Contains("line 6", ex.Message); + Assert.That(ex.Message, Does.Contain("line 6")); break; case BadDataHandlingStrategy.IgnoreRows: var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.IsNotNull(dt); + Assert.That(dt, Is.Not.Null); - Assert.AreEqual(4, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(4)); break; case BadDataHandlingStrategy.DivertRows: var dt2 = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(4, dt2.Rows.Count); + Assert.That(dt2.Rows, Has.Count.EqualTo(4)); - Assert.IsNotNull(source.EventHandlers.DivertErrorsFile); + Assert.That(source.EventHandlers.DivertErrorsFile, Is.Not.Null); - Assert.AreEqual($"0101010101,5,2001-01-05,fish,watafak{Environment.NewLine}", - File.ReadAllText(source.EventHandlers.DivertErrorsFile.FullName)); + Assert.That(File.ReadAllText(source.EventHandlers.DivertErrorsFile.FullName), Is.EqualTo($"0101010101,5,2001-01-05,fish,watafak{Environment.NewLine}")); break; default: @@ -500,10 +519,10 @@ public void NewLinesInConstantString_EscapedCorrectly() try { var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.IsNotNull(dt); - Assert.AreEqual(5, dt.Rows.Count); - Assert.AreEqual(@"5 - The first", dt.Rows[0][1]); + Assert.That(dt, Is.Not.Null); + Assert.That(dt.Rows, Has.Count.EqualTo(5)); + Assert.That(dt.Rows[0][1], Is.EqualTo(@"5 + The first")); } finally { @@ -546,25 +565,25 @@ public void NewLinesInConstantString_NotEscaped(BadDataHandlingStrategy strategy case BadDataHandlingStrategy.ThrowException: var ex = Assert.Throws(() => source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - StringAssert.Contains("line 2", ex.Message); + Assert.That(ex.Message, Does.Contain("line 2")); break; case BadDataHandlingStrategy.IgnoreRows: var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.IsNotNull(dt); + Assert.That(dt, Is.Not.Null); - Assert.AreEqual(4, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(4)); break; case BadDataHandlingStrategy.DivertRows: var dt2 = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(4, dt2.Rows.Count); + Assert.That(dt2.Rows, Has.Count.EqualTo(4)); - Assert.IsNotNull(source.EventHandlers.DivertErrorsFile); + Assert.That(source.EventHandlers.DivertErrorsFile, Is.Not.Null); - Assert.AreEqual(@"0101010101,5 + Assert.That(File.ReadAllText(source.EventHandlers.DivertErrorsFile.FullName), Is.EqualTo(@"0101010101,5 The first,2001-01-05 -", File.ReadAllText(source.EventHandlers.DivertErrorsFile.FullName)); +")); break; default: @@ -601,15 +620,18 @@ public void OverrideHeadersAndTab() var dt = source.GetChunk(new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken()); - Assert.NotNull(dt); + Assert.That(dt, Is.Not.Null); - Assert.AreEqual(3, dt.Columns.Count); + Assert.That(dt.Columns, Has.Count.EqualTo(3)); - Assert.AreEqual("CHI", dt.Columns[0].ColumnName); - Assert.AreEqual("StudyID", dt.Columns[1].ColumnName); - Assert.AreEqual("Date", dt.Columns[2].ColumnName); + Assert.Multiple(() => + { + Assert.That(dt.Columns[0].ColumnName, Is.EqualTo("CHI")); + Assert.That(dt.Columns[1].ColumnName, Is.EqualTo("StudyID")); + Assert.That(dt.Columns[2].ColumnName, Is.EqualTo("Date")); - Assert.AreEqual(2, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); + }); source.Dispose(new ThrowImmediatelyDataLoadJob(), null); @@ -639,14 +661,17 @@ public void Test_IgnoreColumns() var dt = source.GetChunk(new ThrowImmediatelyDataLoadJob(), new GracefulCancellationToken()); - Assert.NotNull(dt); + Assert.That(dt, Is.Not.Null); //should only be one column (chi since we ignore study and date) - Assert.AreEqual(2, dt.Columns.Count); - Assert.AreEqual("CHI", dt.Columns[0].ColumnName); - Assert.AreEqual("SomeText", dt.Columns[1].ColumnName); + Assert.That(dt.Columns, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(dt.Columns[0].ColumnName, Is.EqualTo("CHI")); + Assert.That(dt.Columns[1].ColumnName, Is.EqualTo("SomeText")); - Assert.AreEqual(2, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); + }); source.Dispose(new ThrowImmediatelyDataLoadJob(), null); @@ -665,7 +690,7 @@ public void Test_IgnoreColumns() "onceUpon")] //Dodgy characters are stripped before cammel casing after spaces so 'u' gets cammeled even though it has a symbol before it. public void TestMakingHeaderNamesSane(string bad, string expectedGood) { - Assert.AreEqual(expectedGood, QuerySyntaxHelper.MakeHeaderNameSensible(bad)); + Assert.That(QuerySyntaxHelper.MakeHeaderNameSensible(bad), Is.EqualTo(expectedGood)); } @@ -698,16 +723,22 @@ public void Test_ScientificNotation_StronglyTyped() source.StronglyTypeInput = true; var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(typeof(decimal), dt.Columns.Cast().Single().DataType); - Assert.AreEqual(DelimitedFlatFileDataFlowSource.MinimumStronglyTypeInputBatchSize, dt.Rows.Count); + Assert.Multiple(() => + { + Assert.That(dt.Columns.Cast().Single().DataType, Is.EqualTo(typeof(decimal))); + Assert.That(dt.Rows, Has.Count.EqualTo(DelimitedFlatFileDataFlowSource.MinimumStronglyTypeInputBatchSize)); + }); dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(typeof(decimal), dt.Columns.Cast().Single().DataType); - Assert.AreEqual(2, dt.Rows.Count); + Assert.Multiple(() => + { + Assert.That(dt.Columns.Cast().Single().DataType, Is.EqualTo(typeof(decimal))); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); + }); dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.IsNull(dt); + Assert.That(dt, Is.Null); } /// @@ -731,7 +762,7 @@ public void Test_IgnoreQuotes() var toMem = new ToMemoryDataLoadEventListener(true); var ex = Assert.Throws(() => source.GetChunk(toMem, new GracefulCancellationToken())); - Assert.AreEqual("Bad data found on line 2", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Bad data found on line 2")); source.Dispose(ThrowImmediatelyDataLoadEventListener.Quiet, null); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTestsBase.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTestsBase.cs index aef541170b..c28a5a5594 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTestsBase.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTestsBase.cs @@ -38,7 +38,7 @@ protected static void AssertDivertFileIsExactly(string expectedContents) Assert.Fail($"No Divert file was generated at expected path {filename}"); var contents = File.ReadAllText(filename); - Assert.AreEqual(expectedContents, contents); + Assert.That(contents, Is.EqualTo(expectedContents)); } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_AutomaticallyResolved.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_AutomaticallyResolved.cs index 9a997c7db9..7fda6f8b2f 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_AutomaticallyResolved.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_AutomaticallyResolved.cs @@ -23,23 +23,26 @@ public void Test_ValuesSpradAcrossMultipleRows() ); var dt = RunGetChunk(file); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual(true, dt.Rows[0]["A"]); - Assert.AreEqual(17, dt.Rows[0]["B"]); - Assert.AreEqual("Beginning of a long", dt.Rows[0]["C"]); - Assert.AreEqual(37, dt.Rows[0]["D"]); - - - Assert.AreEqual(DBNull.Value, dt.Rows[1]["A"]); - Assert.AreEqual(DBNull.Value, dt.Rows[1]["B"]); - Assert.AreEqual("description of something", dt.Rows[1]["C"]); - Assert.AreEqual(DBNull.Value, dt.Rows[1]["D"]); - - - Assert.AreEqual(DBNull.Value, dt.Rows[2]["A"]); - Assert.AreEqual(DBNull.Value, dt.Rows[2]["B"]); - Assert.AreEqual("really boring", dt.Rows[2]["C"]); - Assert.AreEqual(DBNull.Value, dt.Rows[2]["D"]); + Assert.That(dt.Rows, Has.Count.EqualTo(3)); + Assert.Multiple(() => + { + Assert.That(dt.Rows[0]["A"], Is.EqualTo(true)); + Assert.That(dt.Rows[0]["B"], Is.EqualTo(17)); + Assert.That(dt.Rows[0]["C"], Is.EqualTo("Beginning of a long")); + Assert.That(dt.Rows[0]["D"], Is.EqualTo(37)); + + + Assert.That(dt.Rows[1]["A"], Is.EqualTo(DBNull.Value)); + Assert.That(dt.Rows[1]["B"], Is.EqualTo(DBNull.Value)); + Assert.That(dt.Rows[1]["C"], Is.EqualTo("description of something")); + Assert.That(dt.Rows[1]["D"], Is.EqualTo(DBNull.Value)); + + + Assert.That(dt.Rows[2]["A"], Is.EqualTo(DBNull.Value)); + Assert.That(dt.Rows[2]["B"], Is.EqualTo(DBNull.Value)); + Assert.That(dt.Rows[2]["C"], Is.EqualTo("really boring")); + Assert.That(dt.Rows[2]["D"], Is.EqualTo(DBNull.Value)); + }); } [Test] @@ -53,9 +56,12 @@ public void NewLineInFile_Ignored() ); var dt = RunGetChunk(file); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual("Frank", dt.Rows[0]["Name"]); - Assert.AreEqual("Herbert", dt.Rows[1]["Name"]); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(dt.Rows[0]["Name"], Is.EqualTo("Frank")); + Assert.That(dt.Rows[1]["Name"], Is.EqualTo("Herbert")); + }); } [Test] @@ -70,12 +76,15 @@ the best ever"" ); var dt = RunGetChunk(file); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual("Frank", dt.Rows[0]["Name"]); - Assert.AreEqual(@"Frank is - -the best ever", dt.Rows[0]["Description"]); - Assert.AreEqual("Herbert", dt.Rows[1]["Name"]); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(dt.Rows[0]["Name"], Is.EqualTo("Frank")); + Assert.That(dt.Rows[0]["Description"], Is.EqualTo(@"Frank is + +the best ever")); + Assert.That(dt.Rows[1]["Name"], Is.EqualTo("Herbert")); + }); } [TestCase("")] @@ -93,10 +102,13 @@ public void NullCellValues_ToDbNull(string nullstring) ); var dt = RunGetChunk(file); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual(DBNull.Value, dt.Rows[0]["Name"]); - Assert.AreEqual("Herbert", dt.Rows[1]["Name"]); - Assert.AreEqual(DBNull.Value, dt.Rows[1]["Dob"]); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(dt.Rows[0]["Name"], Is.EqualTo(DBNull.Value)); + Assert.That(dt.Rows[1]["Name"], Is.EqualTo("Herbert")); + Assert.That(dt.Rows[1]["Dob"], Is.EqualTo(DBNull.Value)); + }); } @@ -114,8 +126,11 @@ public void TrailingNulls_InRows(string nullSuffix) "0101010101,5,2001-01-05"); var dt = RunGetChunk(file); - Assert.AreEqual(4, dt.Rows.Count); - Assert.AreEqual(3, dt.Columns.Count); + Assert.Multiple(() => + { + Assert.That(dt.Rows, Has.Count.EqualTo(4)); + Assert.That(dt.Columns, Has.Count.EqualTo(3)); + }); } [Test] @@ -130,12 +145,18 @@ public void TrailingNulls_InHeader() "0101010101,5,2001-01-05"); var dt = RunGetChunk(file); - Assert.IsNotNull(dt); - Assert.AreEqual(4, dt.Rows.Count); - Assert.AreEqual(3, dt.Columns.Count); //and therefore do not appear in the output table - Assert.AreEqual("CHI", dt.Columns[0].ColumnName); - Assert.AreEqual("StudyID", dt.Columns[1].ColumnName); - Assert.AreEqual("Date", dt.Columns[2].ColumnName); + Assert.That(dt, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(dt.Rows, Has.Count.EqualTo(4)); + Assert.That(dt.Columns, Has.Count.EqualTo(3)); //and therefore do not appear in the output table + }); + Assert.Multiple(() => + { + Assert.That(dt.Columns[0].ColumnName, Is.EqualTo("CHI")); + Assert.That(dt.Columns[1].ColumnName, Is.EqualTo("StudyID")); + Assert.That(dt.Columns[2].ColumnName, Is.EqualTo("Date")); + }); } [TestCase(true)] @@ -161,11 +182,17 @@ public void NullHeader_InMiddleOfColumns(bool forceHeaders) else dt = RunGetChunk(file); - Assert.IsNotNull(dt); - Assert.AreEqual(4, dt.Rows.Count); - Assert.AreEqual(3, dt.Columns.Count); - Assert.AreEqual("CHI", dt.Columns[0].ColumnName); - Assert.AreEqual("StudyID", dt.Columns[1].ColumnName); - Assert.AreEqual("Date", dt.Columns[2].ColumnName); + Assert.That(dt, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(dt.Rows, Has.Count.EqualTo(4)); + Assert.That(dt.Columns, Has.Count.EqualTo(3)); + }); + Assert.Multiple(() => + { + Assert.That(dt.Columns[0].ColumnName, Is.EqualTo("CHI")); + Assert.That(dt.Columns[1].ColumnName, Is.EqualTo("StudyID")); + Assert.That(dt.Columns[2].ColumnName, Is.EqualTo("Date")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_ResolvedAccordingToStrategy.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_ResolvedAccordingToStrategy.cs index a047af9c02..d4f307b3b4 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_ResolvedAccordingToStrategy.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_ResolvedAccordingToStrategy.cs @@ -23,11 +23,11 @@ public void EmptyFile_TotallyEmpty(bool throwOnEmpty) { var ex = Assert.Throws(() => RunGetChunk(file, BadDataHandlingStrategy.ThrowException, true)); - Assert.AreEqual("File DelimitedFileSourceTests.txt is empty", ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("File DelimitedFileSourceTests.txt is empty")); } else { - Assert.IsNull(RunGetChunk(file, BadDataHandlingStrategy.ThrowException, false)); + Assert.That(RunGetChunk(file, BadDataHandlingStrategy.ThrowException, false), Is.Null); } } @@ -43,11 +43,11 @@ public void EmptyFile_AllWhitespace(bool throwOnEmpty) { var ex = Assert.Throws(() => RunGetChunk(file, BadDataHandlingStrategy.ThrowException, true)); - StringAssert.StartsWith("File DelimitedFileSourceTests.txt is empty", ex?.Message); + Assert.That(ex?.Message, Does.StartWith("File DelimitedFileSourceTests.txt is empty")); } else { - Assert.IsNull(RunGetChunk(file, BadDataHandlingStrategy.ThrowException, false)); + Assert.That(RunGetChunk(file, BadDataHandlingStrategy.ThrowException, false), Is.Null); } } @@ -65,11 +65,11 @@ public void EmptyFile_HeaderOnly(bool throwOnEmpty) if (throwOnEmpty) { var ex = Assert.Throws(() => RunGetChunk(file, s => s.ThrowOnEmptyFiles = true)); - Assert.AreEqual("File DelimitedFileSourceTests.txt is empty", ex.Message); + Assert.That(ex.Message, Is.EqualTo("File DelimitedFileSourceTests.txt is empty")); } else { - Assert.IsNull(RunGetChunk(file, s => s.ThrowOnEmptyFiles = false)); + Assert.That(RunGetChunk(file, s => s.ThrowOnEmptyFiles = false), Is.Null); } } @@ -92,17 +92,17 @@ public void EmptyFile_ForceHeader(bool throwOnEmpty) s.ForceHeaders = "Name,Address"; s.ForceHeadersReplacesFirstLineInFile = true; })); - Assert.AreEqual("File DelimitedFileSourceTests.txt is empty", ex.Message); + Assert.That(ex.Message, Is.EqualTo("File DelimitedFileSourceTests.txt is empty")); } else { - Assert.IsNull(RunGetChunk(file, + Assert.That(RunGetChunk(file, s => { s.ThrowOnEmptyFiles = false; s.ForceHeaders = "Name,Address"; s.ForceHeadersReplacesFirstLineInFile = true; - })); + }), Is.Null); } } @@ -121,15 +121,15 @@ public void BadCSV_TooManyCellsInRow(BadDataHandlingStrategy strategy) { case BadDataHandlingStrategy.ThrowException: var ex = Assert.Throws(() => RunGetChunk(file, strategy, true)); - StringAssert.StartsWith("Bad data found on line 3", ex.Message); + Assert.That(ex.Message, Does.StartWith("Bad data found on line 3")); break; case BadDataHandlingStrategy.IgnoreRows: var dt = RunGetChunk(file, strategy, true); - Assert.AreEqual(2, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); break; case BadDataHandlingStrategy.DivertRows: var dt2 = RunGetChunk(file, strategy, true); - Assert.AreEqual(2, dt2.Rows.Count); + Assert.That(dt2.Rows, Has.Count.EqualTo(2)); AssertDivertFileIsExactly( $"Bob,He's also dynamite, seen him do a lot of good work,30{Environment.NewLine}"); @@ -157,15 +157,15 @@ public void BadCSV_TooManyCellsInRow_TwoBadRows(BadDataHandlingStrategy strategy { case BadDataHandlingStrategy.ThrowException: var ex = Assert.Throws(() => RunGetChunk(file, strategy, true)); - StringAssert.StartsWith("Bad data found on line 3", ex.Message); + Assert.That(ex.Message, Does.StartWith("Bad data found on line 3")); break; case BadDataHandlingStrategy.IgnoreRows: var dt = RunGetChunk(file, strategy, true); - Assert.AreEqual(2, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); break; case BadDataHandlingStrategy.DivertRows: var dt2 = RunGetChunk(file, strategy, true); - Assert.AreEqual(2, dt2.Rows.Count); + Assert.That(dt2.Rows, Has.Count.EqualTo(2)); AssertDivertFileIsExactly( $"Frank,Is the greatest,100,Frank,Is the greatest,100{Environment.NewLine}Bob,He's also dynamite, seen him do a lot of good work,30{Environment.NewLine}Bob2,He's also dynamite2, seen him do a lot of good work2,30{Environment.NewLine}"); @@ -200,15 +200,15 @@ void Adjust(DelimitedFlatFileDataFlowSource a) { case BadDataHandlingStrategy.ThrowException: var ex = Assert.Throws(() => RunGetChunk(file, Adjust)); - StringAssert.StartsWith("Bad data found on line 4", ex.Message); + Assert.That(ex.Message, Does.StartWith("Bad data found on line 4")); break; case BadDataHandlingStrategy.IgnoreRows: var dt = RunGetChunk(file, Adjust); - Assert.AreEqual(2, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(2)); break; case BadDataHandlingStrategy.DivertRows: var dt2 = RunGetChunk(file, Adjust); - Assert.AreEqual(2, dt2.Rows.Count); + Assert.That(dt2.Rows, Has.Count.EqualTo(2)); AssertDivertFileIsExactly($"Other People To Investigate{Environment.NewLine}"); @@ -240,15 +240,15 @@ void Adjust(DelimitedFlatFileDataFlowSource a) { case BadDataHandlingStrategy.ThrowException: var ex = Assert.Throws(() => RunGetChunk(file, Adjust)); - StringAssert.StartsWith("Bad data found on line 3", ex.Message); + Assert.That(ex.Message, Does.StartWith("Bad data found on line 3")); break; case BadDataHandlingStrategy.IgnoreRows: var dt = RunGetChunk(file, Adjust); - Assert.AreEqual(1, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(1)); break; case BadDataHandlingStrategy.DivertRows: var dt2 = RunGetChunk(file, Adjust); - Assert.AreEqual(1, dt2.Rows.Count); + Assert.That(dt2.Rows, Has.Count.EqualTo(1)); AssertDivertFileIsExactly($"Bob{Environment.NewLine}"); @@ -271,8 +271,8 @@ not too bad "Dennis,Hes ok,35"); var dt = RunGetChunk(file, s => { s.AttemptToResolveNewLinesInRecords = true; }); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual($"He's{Environment.NewLine}not too bad{Environment.NewLine}to be honest", dt.Rows[1][1]); + Assert.That(dt.Rows, Has.Count.EqualTo(3)); + Assert.That(dt.Rows[1][1], Is.EqualTo($"He's{Environment.NewLine}not too bad{Environment.NewLine}to be honest")); } [Test] @@ -288,7 +288,7 @@ not too bad var ex = Assert.Throws(() => RunGetChunk(file, s => { s.AttemptToResolveNewLinesInRecords = true; })); - Assert.AreEqual("Bad data found on line 3", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Bad data found on line 3")); //looks like a good record followed by 2 bad records var dt = RunGetChunk(file, s => @@ -296,10 +296,13 @@ not too bad s.AttemptToResolveNewLinesInRecords = true; s.BadDataHandlingStrategy = BadDataHandlingStrategy.IgnoreRows; }); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual("to be honest", dt.Rows[1][0]); - Assert.AreEqual("Bob", dt.Rows[1][1]); - Assert.AreEqual(20, dt.Rows[1][2]); + Assert.That(dt.Rows, Has.Count.EqualTo(3)); + Assert.Multiple(() => + { + Assert.That(dt.Rows[1][0], Is.EqualTo("to be honest")); + Assert.That(dt.Rows[1][1], Is.EqualTo("Bob")); + Assert.That(dt.Rows[1][2], Is.EqualTo(20)); + }); } [Test] @@ -315,7 +318,7 @@ not too bad var ex = Assert.Throws(() => RunGetChunk(file, s => { s.AttemptToResolveNewLinesInRecords = true; })); - Assert.AreEqual("Bad data found on line 4", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Bad data found on line 4")); //looks like a good record followed by 2 bad records var dt = RunGetChunk(file, s => @@ -323,8 +326,8 @@ not too bad s.AttemptToResolveNewLinesInRecords = true; s.BadDataHandlingStrategy = BadDataHandlingStrategy.IgnoreRows; }); - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual("He's", dt.Rows[1][2]); + Assert.That(dt.Rows, Has.Count.EqualTo(3)); + Assert.That(dt.Rows[1][2], Is.EqualTo("He's")); } [Test] @@ -337,7 +340,7 @@ public void BadCSV_ForceHeaders() var ex = Assert.Throws(() => RunGetChunk(file, s => { s.AttemptToResolveNewLinesInRecords = false; })); - Assert.AreEqual("Bad data found on line 2", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Bad data found on line 2")); var dt = RunGetChunk(file, s => @@ -347,10 +350,16 @@ public void BadCSV_ForceHeaders() s.ForceHeadersReplacesFirstLineInFile = true; }); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual(2, dt.Columns.Count); - Assert.AreEqual("Thomas", dt.Rows[0]["Name"]); - Assert.AreEqual(100, dt.Rows[0]["BloodGlucose"]); + Assert.Multiple(() => + { + Assert.That(dt.Rows, Has.Count.EqualTo(2)); + Assert.That(dt.Columns, Has.Count.EqualTo(2)); + }); + Assert.Multiple(() => + { + Assert.That(dt.Rows[0]["Name"], Is.EqualTo("Thomas")); + Assert.That(dt.Rows[0]["BloodGlucose"], Is.EqualTo(100)); + }); } [Test] @@ -366,9 +375,15 @@ public void BadCSV_ForceHeaders_NoReplace() s.ForceHeaders = "Name,BloodGlucose"; }); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual(2, dt.Columns.Count); - Assert.AreEqual("Thomas", dt.Rows[0]["Name"]); - Assert.AreEqual(100, dt.Rows[0]["BloodGlucose"]); + Assert.Multiple(() => + { + Assert.That(dt.Rows, Has.Count.EqualTo(2)); + Assert.That(dt.Columns, Has.Count.EqualTo(2)); + }); + Assert.Multiple(() => + { + Assert.That(dt.Rows[0]["Name"], Is.EqualTo("Thomas")); + Assert.That(dt.Rows[0]["BloodGlucose"], Is.EqualTo(100)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_Unresolveable.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_Unresolveable.cs index 547f0e985c..84dd2c34bf 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_Unresolveable.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/DelimitedFileSourceTests_Unresolveable.cs @@ -39,17 +39,17 @@ void Adjust(DelimitedFlatFileDataFlowSource a) { case BadDataHandlingStrategy.ThrowException: var ex = Assert.Throws(() => RunGetChunk(file, Adjust)); - Assert.AreEqual("Bad data found on line 9", ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("Bad data found on line 9")); break; case BadDataHandlingStrategy.IgnoreRows: var dt = RunGetChunk(file, Adjust); - Assert.AreEqual(2, dt.Rows.Count); //reads first 2 rows and chucks the rest! + Assert.That(dt.Rows, Has.Count.EqualTo(2)); //reads first 2 rows and chucks the rest! break; case BadDataHandlingStrategy.DivertRows: //read 2 rows and rejected the rest var dt2 = RunGetChunk(file, Adjust); - Assert.AreEqual(2, dt2.Rows.Count); + Assert.That(dt2.Rows, Has.Count.EqualTo(2)); AssertDivertFileIsExactly( $"Frank,\"Is the greatest,100{Environment.NewLine}Frank,Is the greatest,100{Environment.NewLine}Frank,Is the greatest,100{Environment.NewLine}Frank,Is the greatest,100{Environment.NewLine}Frank,Is the greatest,100{Environment.NewLine}"); @@ -78,7 +78,7 @@ static void Adjust(DelimitedFlatFileDataFlowSource a) } var dt2 = RunGetChunk(file, Adjust); - Assert.AreEqual(5, dt2.Rows.Count); - Assert.AreEqual("\"Is the greatest", dt2.Rows[1]["Description"]); + Assert.That(dt2.Rows, Has.Count.EqualTo(5)); + Assert.That(dt2.Rows[1]["Description"], Is.EqualTo("\"Is the greatest")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/SourceTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/SourceTests.cs index 39dc637579..73ba5099dc 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/SourceTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PipelineTests/Sources/SourceTests.cs @@ -29,8 +29,7 @@ public void RetrieveChunks() { var source = new DbDataCommandDataFlowSource("Select top 3 * from master.sys.tables", "Query Sys tables", DiscoveredServerICanCreateRandomDatabasesAndTablesOn.Builder, 30); - Assert.AreEqual(3, - source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()).Rows.Count); + Assert.That(source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()).Rows, Has.Count.EqualTo(3)); } @@ -44,7 +43,7 @@ public void TestPipelineContextInitialization() var ti = new TableInfo(CatalogueRepository, "TestTableInfo"); context.PreInitialize(ThrowImmediatelyDataLoadEventListener.Quiet, component, ti); - Assert.AreEqual(component.PreInitToThis, ti); + Assert.That(ti, Is.EqualTo(component.PreInitToThis)); ti.DeleteInDatabase(); } @@ -73,7 +72,7 @@ public void TestPipelineContextInitialization_UnexpectedType() var ex = Assert.Throws(() => context.PreInitialize(ThrowImmediatelyDataLoadEventListener.Quiet, component, ci)); - StringAssert.Contains("The following expected types were not passed to PreInitialize:TableInfo", ex.Message); + Assert.That(ex.Message, Does.Contain("The following expected types were not passed to PreInitialize:TableInfo")); } [Test] @@ -86,9 +85,8 @@ public void TestPipelineContextInitialization_ForbiddenType() var ti = new TableInfo(new MemoryCatalogueRepository(), "Foo"); var ex = Assert.Throws(() => context.PreInitialize(ThrowImmediatelyDataLoadEventListener.Quiet, component, ti)); - StringAssert.Contains( - "Type TableInfo is not an allowable PreInitialize parameters type under the current DataFlowPipelineContext (check which flags you passed to the DataFlowPipelineContextFactory and the interfaces IPipelineRequirement<> that your components implement) ", - ex.Message); + Assert.That( + ex.Message, Does.Contain("Type TableInfo is not an allowable PreInitialize parameters type under the current DataFlowPipelineContext (check which flags you passed to the DataFlowPipelineContextFactory and the interfaces IPipelineRequirement<> that your components implement) ")); } [Test] @@ -107,9 +105,8 @@ public void TestPipelineContextInitialization_UninitializedInterface() var ex = Assert.Throws(() => context.PreInitialize(ThrowImmediatelyDataLoadEventListener.Quiet, component, testTableInfo)); - StringAssert.Contains( - $"The following expected types were not passed to PreInitialize:LoadModuleAssembly{Environment.NewLine}The object types passed were:{Environment.NewLine}Rdmp.Core.Curation.Data.TableInfo:Test Table Info", - ex.Message); + Assert.That( + ex.Message, Does.Contain($"The following expected types were not passed to PreInitialize:LoadModuleAssembly{Environment.NewLine}The object types passed were:{Environment.NewLine}Rdmp.Core.Curation.Data.TableInfo:Test Table Info")); } [Test] @@ -122,7 +119,7 @@ public void TestPipelineContextIsAllowable() var pipeline = new Pipeline(CatalogueRepository, "DeleteMePipeline"); var component = new PipelineComponent(CatalogueRepository, pipeline, typeof(TestObject_RequiresTableInfo), 0); - Assert.IsTrue(context.IsAllowable(pipeline)); + Assert.That(context.IsAllowable(pipeline)); pipeline.DeleteInDatabase(); } @@ -145,11 +142,13 @@ public void TestPipelineContextIsNOTAllowable() Console.WriteLine(reason); - Assert.IsFalse(rejection, reason); + Assert.Multiple(() => + { + Assert.That(rejection, Is.False, reason); - Assert.AreEqual( - "Component TestPipeComponent implements a forbidden type (IPipelineRequirement) under the pipeline usage context", - reason); + Assert.That( + reason, Is.EqualTo("Component TestPipeComponent implements a forbidden type (IPipelineRequirement) under the pipeline usage context")); + }); pipeline.DeleteInDatabase(); } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PrematureLoadEnderTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PrematureLoadEnderTests.cs index 949a189e31..8bc2853c45 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PrematureLoadEnderTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PrematureLoadEnderTests.cs @@ -23,7 +23,7 @@ public void TestEndLoadBecause_NoTables(DatabaseType type) { var database = GetCleanedServer(type); - Assert.AreEqual(0, database.DiscoverTables(false).Length); + Assert.That(database.DiscoverTables(false), Is.Empty); var ender = new PrematureLoadEnder { @@ -33,7 +33,7 @@ public void TestEndLoadBecause_NoTables(DatabaseType type) ender.Initialize(database, LoadStage.AdjustRaw); - Assert.AreEqual(ExitCodeType.OperationNotRequired, ender.Mutilate(new ThrowImmediatelyDataLoadJob())); + Assert.That(ender.Mutilate(new ThrowImmediatelyDataLoadJob()), Is.EqualTo(ExitCodeType.OperationNotRequired)); } [TestCase(DatabaseType.MySql)] @@ -54,7 +54,7 @@ public void TestEndLoadBecause_NoRows(DatabaseType type) ender.Initialize(database, LoadStage.AdjustRaw); - Assert.AreEqual(ExitCodeType.OperationNotRequired, ender.Mutilate(new ThrowImmediatelyDataLoadJob())); + Assert.That(ender.Mutilate(new ThrowImmediatelyDataLoadJob()), Is.EqualTo(ExitCodeType.OperationNotRequired)); } [TestCase(DatabaseType.MySql)] @@ -76,6 +76,6 @@ public void TestNoEnd_BecauseRows(DatabaseType type) ender.Initialize(database, LoadStage.AdjustRaw); - Assert.AreEqual(ExitCodeType.Success, ender.Mutilate(new ThrowImmediatelyDataLoadJob())); + Assert.That(ender.Mutilate(new ThrowImmediatelyDataLoadJob()), Is.EqualTo(ExitCodeType.Success)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PrimaryKeyCollisionResolverTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PrimaryKeyCollisionResolverTests.cs index e2cefd89ee..30cbf76afb 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/PrimaryKeyCollisionResolverTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/PrimaryKeyCollisionResolverTests.cs @@ -64,11 +64,12 @@ public void PrimaryKeyCollisionResolverMultilation_Check_ThrowsBecauseNoColumnOr } catch (Exception e) { - Assert.AreEqual("Failed to check PrimaryKeyCollisionResolver on PrimaryKeyCollisionResolverTests", - e.Message); - Assert.AreEqual( - "TableInfo PrimaryKeyCollisionResolverTests does not have any primary keys defined so cannot resolve primary key collisions", - e.InnerException.Message); + Assert.Multiple(() => + { + Assert.That(e.Message, Is.EqualTo("Failed to check PrimaryKeyCollisionResolver on PrimaryKeyCollisionResolverTests")); + Assert.That( + e.InnerException.Message, Is.EqualTo("TableInfo PrimaryKeyCollisionResolverTests does not have any primary keys defined so cannot resolve primary key collisions")); + }); } } finally @@ -83,9 +84,8 @@ public void PrimaryKeyCollisionResolverMultilation_Check_ThrowsBecauseNotInitial var mutilation = new PrimaryKeyCollisionResolverMutilation(); var ex = Assert.Throws(() => mutilation.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.Contains( - "Target table is null, a table must be specified upon which to resolve primary key duplication (that TableInfo must have a primary key collision resolution order)", - ex.Message); + Assert.That( + ex.Message, Does.Contain("Target table is null, a table must be specified upon which to resolve primary key duplication (that TableInfo must have a primary key collision resolution order)")); } [Test] @@ -110,14 +110,14 @@ public void GenerateSQL_OrderCorrect() Console.WriteLine(sql); - Assert.IsTrue(sql.Contains(c2.Name)); - Assert.IsTrue(sql.Contains(c3.Name)); + Assert.That(sql, Does.Contain(c2.Name)); + Assert.That(sql, Does.Contain(c3.Name)); //column 2 has the following null substitute, is Ascending order and is the first of two - Assert.IsTrue(sql.Contains("ISNULL([col2],-9223372036854775808) ASC,")); + Assert.That(sql, Does.Contain("ISNULL([col2],-9223372036854775808) ASC,")); //column 3 has the following null substitute and is descending and is not followed by another column - Assert.IsTrue(sql.Contains("ISNULL([col3],-2147483648) DESC")); + Assert.That(sql, Does.Contain("ISNULL([col3],-2147483648) DESC")); } finally { @@ -136,9 +136,8 @@ public void NoColumnOrdersConfigured_ThrowsException() var resolver = new PrimaryKeyCollisionResolver(t); var ex = Assert.Throws(() => Console.WriteLine(resolver.GenerateSQL())); - StringAssert.Contains( - "The ColumnInfos of TableInfo PrimaryKeyCollisionResolverTests do not have primary key resolution orders configured (do not know which order to use non primary key column values in to resolve collisions). Fix this by right clicking a TableInfo in CatalogueManager and selecting 'Configure Primary Key Collision Resolution'.", - ex.Message); + Assert.That( + ex.Message, Does.Contain("The ColumnInfos of TableInfo PrimaryKeyCollisionResolverTests do not have primary key resolution orders configured (do not know which order to use non primary key column values in to resolve collisions). Fix this by right clicking a TableInfo in CatalogueManager and selecting 'Configure Primary Key Collision Resolution'.")); } finally { @@ -155,8 +154,7 @@ public void NoPrimaryKeys_ThrowsException() { var resolver = new PrimaryKeyCollisionResolver(t); var ex = Assert.Throws(() => Console.WriteLine(resolver.GenerateSQL())); - StringAssert.Contains("does not have any primary keys defined so cannot resolve primary key collisions", - ex.Message); + Assert.That(ex.Message, Does.Contain("does not have any primary keys defined so cannot resolve primary key collisions")); } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/RemoteDatabaseAttacherTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/RemoteDatabaseAttacherTests.cs index 6e79de5059..917f29e1a3 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/RemoteDatabaseAttacherTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/RemoteDatabaseAttacherTests.cs @@ -43,7 +43,7 @@ public void TestRemoteDatabaseAttach(DatabaseType dbType, Scenario scenario) var tbl = db.CreateTable("MyTable", dt); - Assert.AreEqual(1, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(1)); Import(tbl, out var ti, out _); //Create a virtual RAW column @@ -78,8 +78,7 @@ public void TestRemoteDatabaseAttach(DatabaseType dbType, Scenario scenario) var ex = Assert.Throws(() => attacher.Attach(job, new GracefulCancellationToken())); - Assert.AreEqual("Invalid column name 'MyMissingCol'.", - ex.InnerException.InnerException.InnerException.Message); + Assert.That(ex.InnerException.InnerException.InnerException.Message, Is.EqualTo("Invalid column name 'MyMissingCol'.")); return; case Scenario.MissingPreLoadDiscardedColumnButSelectStar: break; @@ -89,7 +88,7 @@ public void TestRemoteDatabaseAttach(DatabaseType dbType, Scenario scenario) attacher.Attach(job, new GracefulCancellationToken()); - Assert.AreEqual(2, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(2)); dt = tbl.GetDataTable(); diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/RuntimeTaskFactoryTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/RuntimeTaskFactoryTests.cs index 898c08d12a..f9fdc2d5a3 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/RuntimeTaskFactoryTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/RuntimeTaskFactoryTests.cs @@ -36,8 +36,7 @@ public void RuntimeTaskFactoryTest(string className) var ex = Assert.Throws(() => RuntimeTaskFactory.Create(task, new StageArgs(LoadStage.AdjustRaw, GetCleanedServer(FAnsi.DatabaseType.MicrosoftSQLServer), Substitute.For()))); - Assert.IsTrue(ex.InnerException.Message.Contains( - "marked with DemandsInitialization but no corresponding argument was provided in ArgumentCollection")); + Assert.That(ex.InnerException.Message, Does.Contain("marked with DemandsInitialization but no corresponding argument was provided in ArgumentCollection")); } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/SafePrimaryKeyCollisionResolverMutilationTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/SafePrimaryKeyCollisionResolverMutilationTests.cs index 2d642558ef..5deeba1635 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/SafePrimaryKeyCollisionResolverMutilationTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/SafePrimaryKeyCollisionResolverMutilationTests.cs @@ -58,7 +58,7 @@ public void SafePrimaryKeyCollisionResolverMutilationTests_NoDifference_NoRecord mutilation.Initialize(db, LoadStage.AdjustRaw); mutilation.Mutilate(new ThrowImmediatelyDataLoadJob(new HICDatabaseConfiguration(db.Server))); - Assert.AreEqual(4, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(4)); } [TestCase(DatabaseType.MicrosoftSQLServer, false)] @@ -100,18 +100,19 @@ public void SafePrimaryKeyCollisionResolverMutilationTests_PreferNull_RecordsDel mutilation.Initialize(db, LoadStage.AdjustRaw); mutilation.Mutilate(new ThrowImmediatelyDataLoadJob(new HICDatabaseConfiguration(db.Server))); - Assert.AreEqual(3, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(3)); var result = tbl.GetDataTable(); - //if you prefer nulls you shouldn't want this one - Assert.AreEqual(preferNulls ? 0 : 1, - result.Rows.Cast().Count(r => - (int)r["PK"] == 1 && r["ResolveOn"] as string == "fish" && r["AnotherCol"] as string == "flop")); - - //if you prefer nulls you should have this one - Assert.AreEqual(preferNulls ? 1 : 0, - result.Rows.Cast().Count(r => - (int)r["PK"] == 1 && r["ResolveOn"] == DBNull.Value && r["AnotherCol"] as string == "cat")); + Assert.Multiple(() => + { + //if you prefer nulls you shouldn't want this one + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK"] == 1 && r["ResolveOn"] as string == "fish" && r["AnotherCol"] as string == "flop"), Is.EqualTo(preferNulls ? 0 : 1)); + + //if you prefer nulls you should have this one + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK"] == 1 && r["ResolveOn"] == DBNull.Value && r["AnotherCol"] as string == "cat"), Is.EqualTo(preferNulls ? 1 : 0)); + }); } [TestCase(DatabaseType.MicrosoftSQLServer)] @@ -153,18 +154,19 @@ public void SafePrimaryKeyCollisionResolverMutilationTests_WithDatabaseNamer_Rec mutilation.Initialize(db, LoadStage.AdjustRaw); mutilation.Mutilate(new ThrowImmediatelyDataLoadJob(new HICDatabaseConfiguration(db.Server, namer), ti)); - Assert.AreEqual(3, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(3)); var result = tbl.GetDataTable(); - //if you prefer nulls you shouldn't want this one - Assert.AreEqual(0, - result.Rows.Cast().Count(r => - (int)r["PK"] == 1 && r["ResolveOn"] as string == "fish" && r["AnotherCol"] as string == "flop")); - - //if you prefer nulls you should have this one - Assert.AreEqual(1, - result.Rows.Cast().Count(r => - (int)r["PK"] == 1 && r["ResolveOn"] == DBNull.Value && r["AnotherCol"] as string == "cat")); + Assert.Multiple(() => + { + //if you prefer nulls you shouldn't want this one + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK"] == 1 && r["ResolveOn"] as string == "fish" && r["AnotherCol"] as string == "flop"), Is.EqualTo(0)); + + //if you prefer nulls you should have this one + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK"] == 1 && r["ResolveOn"] == DBNull.Value && r["AnotherCol"] as string == "cat"), Is.EqualTo(1)); + }); } @@ -208,21 +210,21 @@ public void SafePrimaryKeyCollisionResolverMutilationTests_PreferLarger_RecordsD mutilation.Initialize(db, LoadStage.AdjustRaw); mutilation.Mutilate(new ThrowImmediatelyDataLoadJob(new HICDatabaseConfiguration(db.Server))); - Assert.AreEqual(3, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(3)); var result = tbl.GetDataTable(); - //if you like larger values (alphabetically) then you want the 'b' - Assert.AreEqual(preferLarger ? 1 : 0, - result.Rows.Cast().Count(r => - (int)r["PK"] == 1 && r["ResolveOn"] as string == "b" && r["AnotherCol"] as string == "flop")); - Assert.AreEqual(preferLarger ? 0 : 1, - result.Rows.Cast().Count(r => - (int)r["PK"] == 1 && r["ResolveOn"] as string == "a" && r["AnotherCol"] as string == "flop")); - - //either way you shouldn't have the null one - Assert.AreEqual(0, - result.Rows.Cast().Count(r => - (int)r["PK"] == 1 && r["ResolveOn"] == DBNull.Value && r["AnotherCol"] as string == "cat")); + Assert.Multiple(() => + { + //if you like larger values (alphabetically) then you want the 'b' + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK"] == 1 && r["ResolveOn"] as string == "b" && r["AnotherCol"] as string == "flop"), Is.EqualTo(preferLarger ? 1 : 0)); + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK"] == 1 && r["ResolveOn"] as string == "a" && r["AnotherCol"] as string == "flop"), Is.EqualTo(preferLarger ? 0 : 1)); + + //either way you shouldn't have the null one + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK"] == 1 && r["ResolveOn"] == DBNull.Value && r["AnotherCol"] as string == "cat"), Is.EqualTo(0)); + }); } @@ -266,23 +268,23 @@ public void SafePrimaryKeyCollisionResolverMutilationTests_PreferLarger_Dates_Re mutilation.Initialize(db, LoadStage.AdjustRaw); mutilation.Mutilate(new ThrowImmediatelyDataLoadJob(new HICDatabaseConfiguration(db.Server))); - Assert.AreEqual(3, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(3)); var result = tbl.GetDataTable(); - //if you like larger values then you want 2002 thats larger than 2001 - Assert.AreEqual(preferLarger ? 1 : 0, - result.Rows.Cast().Count(r => - (int)r["PK"] == 1 && Equals(r["ResolveOn"], new DateTime(2002, 01, 01)) && - r["AnotherCol"] as string == "flop")); - Assert.AreEqual(preferLarger ? 0 : 1, - result.Rows.Cast().Count(r => - (int)r["PK"] == 1 && Equals(r["ResolveOn"], new DateTime(2001, 01, 01)) && - r["AnotherCol"] as string == "flop")); - - //either way you shouldn't have the null one - Assert.AreEqual(0, - result.Rows.Cast().Count(r => - (int)r["PK"] == 1 && r["ResolveOn"] == DBNull.Value && r["AnotherCol"] as string == "cat")); + Assert.Multiple(() => + { + //if you like larger values then you want 2002 thats larger than 2001 + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK"] == 1 && Equals(r["ResolveOn"], new DateTime(2002, 01, 01)) && + r["AnotherCol"] as string == "flop"), Is.EqualTo(preferLarger ? 1 : 0)); + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK"] == 1 && Equals(r["ResolveOn"], new DateTime(2001, 01, 01)) && + r["AnotherCol"] as string == "flop"), Is.EqualTo(preferLarger ? 0 : 1)); + + //either way you shouldn't have the null one + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK"] == 1 && r["ResolveOn"] == DBNull.Value && r["AnotherCol"] as string == "cat"), Is.EqualTo(0)); + }); } [TestCase(DatabaseType.MicrosoftSQLServer, false)] @@ -336,23 +338,23 @@ public void SafePrimaryKeyCollisionResolverMutilationTests_PreferLarger_ComboKey mutilation.Initialize(db, LoadStage.AdjustRaw); mutilation.Mutilate(new ThrowImmediatelyDataLoadJob(new HICDatabaseConfiguration(db.Server))); - Assert.AreEqual(7, tbl.GetRowCount()); + Assert.That(tbl.GetRowCount(), Is.EqualTo(7)); var result = tbl.GetDataTable(); - //if you like larger values then you want 2002 thats larger than 2001 - Assert.AreEqual(preferLarger ? 1 : 0, - result.Rows.Cast().Count(r => - (int)r["PK1"] == 1 && (int)r["PK2"] == 1 && Equals(r["ResolveOn"], new DateTime(2002, 01, 01)) && - r["AnotherCol"] as string == "flop")); - Assert.AreEqual(preferLarger ? 0 : 1, - result.Rows.Cast().Count(r => - (int)r["PK1"] == 1 && (int)r["PK2"] == 1 && Equals(r["ResolveOn"], new DateTime(2001, 01, 01)) && - r["AnotherCol"] as string == "flop")); - - //either way you shouldn't have the null one - Assert.AreEqual(0, - result.Rows.Cast().Count(r => - (int)r["PK1"] == 1 && (int)r["PK2"] == 1 && r["ResolveOn"] == DBNull.Value && - r["AnotherCol"] as string == "cat")); + Assert.Multiple(() => + { + //if you like larger values then you want 2002 thats larger than 2001 + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK1"] == 1 && (int)r["PK2"] == 1 && Equals(r["ResolveOn"], new DateTime(2002, 01, 01)) && + r["AnotherCol"] as string == "flop"), Is.EqualTo(preferLarger ? 1 : 0)); + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK1"] == 1 && (int)r["PK2"] == 1 && Equals(r["ResolveOn"], new DateTime(2001, 01, 01)) && + r["AnotherCol"] as string == "flop"), Is.EqualTo(preferLarger ? 0 : 1)); + + //either way you shouldn't have the null one + Assert.That(result.Rows.Cast().Count(r => + (int)r["PK1"] == 1 && (int)r["PK2"] == 1 && r["ResolveOn"] == DBNull.Value && + r["AnotherCol"] as string == "cat"), Is.EqualTo(0)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/TableInfoJoiningQueryBuilderTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/TableInfoJoiningQueryBuilderTests.cs index 04c0a2d295..dbc7532acd 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/TableInfoJoiningQueryBuilderTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/TableInfoJoiningQueryBuilderTests.cs @@ -45,8 +45,8 @@ public void OpportunisticJoinRequired() var tablesUsed = SqlQueryBuilderHelper.GetTablesUsedInQuery(queryBuilder, out _, null); - Assert.AreEqual(1, tablesUsed.Count); - Assert.AreEqual(head, tablesUsed[0]); + Assert.That(tablesUsed, Has.Count.EqualTo(1)); + Assert.That(tablesUsed[0], Is.EqualTo(head)); //CASE 2 : 2 columns used one from each table so join is needed queryBuilder = new QueryBuilder(null, null); @@ -60,15 +60,18 @@ public void OpportunisticJoinRequired() tablesUsed = SqlQueryBuilderHelper.GetTablesUsedInQuery(queryBuilder, out _, null); - Assert.AreEqual(2, tablesUsed.Count); - Assert.AreEqual(head, tablesUsed[0]); - Assert.AreEqual(result, tablesUsed[1]); + Assert.That(tablesUsed, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(tablesUsed[0], Is.EqualTo(head)); + Assert.That(tablesUsed[1], Is.EqualTo(result)); - Assert.AreEqual(CollapseWhitespace(@"SELECT + Assert.That(CollapseWhitespace(queryBuilder.SQL), Is.EqualTo(CollapseWhitespace(@"SELECT TestResultSetNumber, Code FROM -[biochemistry]..[Result] Right JOIN Head ON FK = PK"), CollapseWhitespace(queryBuilder.SQL)); +[biochemistry]..[Result] Right JOIN Head ON FK = PK"))); + }); var memoryRepository = new MemoryCatalogueRepository(); @@ -87,7 +90,7 @@ public void OpportunisticJoinRequired() //without the filter tablesUsed = SqlQueryBuilderHelper.GetTablesUsedInQuery(queryBuilder, out _, null); - Assert.AreEqual(1, tablesUsed.Count); + Assert.That(tablesUsed, Has.Count.EqualTo(1)); //set the filter queryBuilder.RootFilterContainer = spontContainer; @@ -98,6 +101,6 @@ public void OpportunisticJoinRequired() //with the filter tablesUsed = SqlQueryBuilderHelper.GetTablesUsedInQuery(queryBuilder, out _, null); - Assert.AreEqual(2, tablesUsed.Count); + Assert.That(tablesUsed, Has.Count.EqualTo(2)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/TableVarcharMaxerTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/TableVarcharMaxerTests.cs index f19750fb3f..b269511a9c 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/TableVarcharMaxerTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/TableVarcharMaxerTests.cs @@ -60,16 +60,16 @@ public void TestTableVarcharMaxer(DatabaseType dbType, bool allDataTypes) switch (dbType) { case DatabaseType.MicrosoftSQLServer: - Assert.AreEqual("varchar(max)", tbl.DiscoverColumn("Dave").DataType.SQLType); - Assert.AreEqual(allDataTypes ? "varchar(max)" : "int", tbl.DiscoverColumn("Frank").DataType.SQLType); + Assert.That(tbl.DiscoverColumn("Dave").DataType.SQLType, Is.EqualTo("varchar(max)")); + Assert.That(tbl.DiscoverColumn("Frank").DataType.SQLType, Is.EqualTo(allDataTypes ? "varchar(max)" : "int")); break; case DatabaseType.MySql: - Assert.AreEqual("longtext", tbl.DiscoverColumn("Dave").DataType.SQLType); - Assert.AreEqual(allDataTypes ? "longtext" : "int", tbl.DiscoverColumn("Frank").DataType.SQLType); + Assert.That(tbl.DiscoverColumn("Dave").DataType.SQLType, Is.EqualTo("longtext")); + Assert.That(tbl.DiscoverColumn("Frank").DataType.SQLType, Is.EqualTo(allDataTypes ? "longtext" : "int")); break; case DatabaseType.Oracle: - Assert.AreEqual("varchar(max)", tbl.DiscoverColumn("Dave").DataType.SQLType); - Assert.AreEqual(allDataTypes ? "varchar(max)" : "int", tbl.DiscoverColumn("Frank").DataType.SQLType); + Assert.That(tbl.DiscoverColumn("Dave").DataType.SQLType, Is.EqualTo("varchar(max)")); + Assert.That(tbl.DiscoverColumn("Frank").DataType.SQLType, Is.EqualTo(allDataTypes ? "varchar(max)" : "int")); break; default: throw new ArgumentOutOfRangeException(nameof(dbType)); @@ -111,13 +111,13 @@ public void VarcharMaxer_BadTableNames(DatabaseType dbType) switch (dbType) { case DatabaseType.MicrosoftSQLServer: - Assert.AreEqual("varchar(max)", tbl.DiscoverColumn("Da' ,,;ve").DataType.SQLType); + Assert.That(tbl.DiscoverColumn("Da' ,,;ve").DataType.SQLType, Is.EqualTo("varchar(max)")); break; case DatabaseType.MySql: - Assert.AreEqual("longtext", tbl.DiscoverColumn("Da' ,,;ve").DataType.SQLType); + Assert.That(tbl.DiscoverColumn("Da' ,,;ve").DataType.SQLType, Is.EqualTo("longtext")); break; case DatabaseType.Oracle: - Assert.AreEqual("varchar(max)", tbl.DiscoverColumn("Da' ,,;ve").DataType.SQLType); + Assert.That(tbl.DiscoverColumn("Da' ,,;ve").DataType.SQLType, Is.EqualTo("varchar(max)")); break; default: throw new ArgumentOutOfRangeException(nameof(dbType)); diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Integration/TestTemporalTables.cs b/Rdmp.Core.Tests/DataLoad/Engine/Integration/TestTemporalTables.cs index b67dacb672..49c4137e70 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Integration/TestTemporalTables.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Integration/TestTemporalTables.cs @@ -132,14 +132,20 @@ public void TestTemporalTable(bool ignoreWithGlobalPattern) ThrowImmediatelyDataLoadEventListener.Quiet, dbConfig), new GracefulCancellationToken()); - Assert.AreEqual(ExitCodeType.Success, exitCode); + Assert.Multiple(() => + { + Assert.That(exitCode, Is.EqualTo(ExitCodeType.Success)); - //frank should be updated to his new departement and role - Assert.AreEqual(2, tbl.GetRowCount()); + //frank should be updated to his new departement and role + Assert.That(tbl.GetRowCount(), Is.EqualTo(2)); + }); var result = tbl.GetDataTable(); var frank = result.Rows.Cast().Single(r => (string)r["Name"] == "Frank"); - Assert.AreEqual("Department of F'Tang", frank["Department"]); - Assert.AreEqual("Boss", frank["Position"]); + Assert.Multiple(() => + { + Assert.That(frank["Department"], Is.EqualTo("Department of F'Tang")); + Assert.That(frank["Position"], Is.EqualTo("Boss")); + }); //post test cleanup foreach (var regex in RepositoryLocator.CatalogueRepository.GetAllObjects()) diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Unit/CohortSamplerTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Unit/CohortSamplerTests.cs index b84438589e..ab3e46a9fb 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Unit/CohortSamplerTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Unit/CohortSamplerTests.cs @@ -32,9 +32,8 @@ public void TestCohortSampler_NoColumnFound() var ex = Assert.Throws(() => sampler.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.AreEqual( - "CohortSampler was unable to find a column called 'priv' in the data passed in. This is the expected private identifier column name of the cohort you are committing.", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("CohortSampler was unable to find a column called 'priv' in the data passed in. This is the expected private identifier column name of the cohort you are committing.")); } [Test] @@ -50,9 +49,8 @@ public void TestCohortSampler_NoColumnFoundExplicit() var ex = Assert.Throws(() => sampler.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.AreEqual( - "CohortSampler was unable to find a column called 'ddd' in the data passed in. This is the expected private identifier column name of the cohort you are committing.", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("CohortSampler was unable to find a column called 'ddd' in the data passed in. This is the expected private identifier column name of the cohort you are committing.")); } [Test] @@ -68,9 +66,8 @@ public void TestCohortSampler_NotEnoughIdentifiersInBatch() var ex = Assert.Throws(() => sampler.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.AreEqual( - "Cohort only contains 1 unique identifiers. This is less than the requested sample size of 100 and FailIfNotEnoughIdentifiers is true", - ex.Message); + Assert.That( + ex.Message, Is.EqualTo("Cohort only contains 1 unique identifiers. This is less than the requested sample size of 100 and FailIfNotEnoughIdentifiers is true")); } [Test] @@ -87,7 +84,7 @@ public void TestCohortSampler_NotEnoughIdentifiersInBatch_ButThatsOk() var result = sampler.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(1, result.Rows.Count); + Assert.That(result.Rows, Has.Count.EqualTo(1)); } [Test] @@ -125,11 +122,14 @@ public void TestCohortSampler_Repeatability() var result2 = sampler2.ProcessPipelineData(dt, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(5, result1.Rows.Count); - Assert.AreEqual(5, result2.Rows.Count); + Assert.Multiple(() => + { + Assert.That(result1.Rows, Has.Count.EqualTo(5)); + Assert.That(result2.Rows, Has.Count.EqualTo(5)); + }); - Assert.IsTrue(result1.Rows.Cast().Select(r => r[0]) + Assert.That(result1.Rows.Cast().Select(r => r[0]) .SequenceEqual(result2.Rows.Cast().Select(r => r[0])), "Expected both samplers to select the same random sample of input values because the project number is the seed"); } @@ -169,11 +169,14 @@ public void TestCohortSampler_Repeatability_OrderIrrelevant() var result2 = sampler2.ProcessPipelineData(dt2, ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(2, result1.Rows.Count); - Assert.AreEqual(2, result2.Rows.Count); + Assert.Multiple(() => + { + Assert.That(result1.Rows, Has.Count.EqualTo(2)); + Assert.That(result2.Rows, Has.Count.EqualTo(2)); + }); - Assert.IsTrue(result1.Rows.Cast().Select(r => r[0]) + Assert.That(result1.Rows.Cast().Select(r => r[0]) .SequenceEqual(result2.Rows.Cast().Select(r => r[0])), "Expected both samplers to select the same random sample of input values because the project number is the seed"); } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Unit/CommandLineHelperTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Unit/CommandLineHelperTests.cs index 17cfbeb96e..4487f04722 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Unit/CommandLineHelperTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Unit/CommandLineHelperTests.cs @@ -22,22 +22,21 @@ internal class CommandLineHelperTests public void TestGetValueString() { var date = new DateTime(2004, 1, 1); - Assert.AreEqual("\"2004-01-01\"", CommandLineHelper.GetValueString(date)); + Assert.That(CommandLineHelper.GetValueString(date), Is.EqualTo("\"2004-01-01\"")); var fi = new FileInfo(TestContext.CurrentContext.TestDirectory); - Assert.AreEqual($@"""{TestContext.CurrentContext.TestDirectory}""", CommandLineHelper.GetValueString(fi)); + Assert.That(CommandLineHelper.GetValueString(fi), Is.EqualTo($@"""{TestContext.CurrentContext.TestDirectory}""")); const string db = "db-name"; - Assert.AreEqual(db, CommandLineHelper.GetValueString(db)); + Assert.That(CommandLineHelper.GetValueString(db), Is.EqualTo(db)); ImplementationManager.Load(); //notice how server and db don't actually exist, thats cool they implement IMightNotExist var dbInfo = new DiscoveredServer(new SqlConnectionStringBuilder { DataSource = "server" }).ExpectDatabase("db"); - Assert.AreEqual("--database-name=db --database-server=server", - CommandLineHelper.CreateArgString("DbInfo", dbInfo)); + Assert.That(CommandLineHelper.CreateArgString("DbInfo", dbInfo), Is.EqualTo("--database-name=db --database-server=server")); } [Test] @@ -52,7 +51,7 @@ public void TestCreateArgString() { var date = new DateTime(2004, 1, 1); var argString = CommandLineHelper.CreateArgString("DateFrom", date); - Assert.AreEqual("--date-from=\"2004-01-01\"", argString); + Assert.That(argString, Is.EqualTo("--date-from=\"2004-01-01\"")); } [Test] @@ -60,7 +59,7 @@ public void TestDateTimeCreateArgString() { var date = new DateTime(2004, 1, 1, 12, 34, 56); var argString = CommandLineHelper.CreateArgString("DateFrom", date); - Assert.AreEqual("--date-from=\"2004-01-01 12:34:56\"", argString); + Assert.That(argString, Is.EqualTo("--date-from=\"2004-01-01 12:34:56\"")); } [Test] diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Unit/DataFlowComponentTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Unit/DataFlowComponentTests.cs index dfd6dc130d..8cda676662 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Unit/DataFlowComponentTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Unit/DataFlowComponentTests.cs @@ -33,7 +33,7 @@ public void ColumnRenamer_NoMatchingColumnAtRuntime() var ex = Assert.Throws(() => renamer.ProcessPipelineData(toProcess, ThrowImmediatelyDataLoadEventListener.Quiet, cts.Token)); - Assert.IsTrue(ex.Message.Contains("does not exist in the supplied data table")); + Assert.That(ex.Message, Does.Contain("does not exist in the supplied data table")); } [Test] @@ -51,8 +51,8 @@ public void ColumnRenamer_Successful() var processed = renamer.ProcessPipelineData(toProcess, ThrowImmediatelyDataLoadEventListener.Quiet, cts.Token); - Assert.AreEqual(1, processed.Columns.Count); - Assert.AreEqual("ReplacementName", processed.Columns[0].ColumnName); + Assert.That(processed.Columns, Has.Count.EqualTo(1)); + Assert.That(processed.Columns[0].ColumnName, Is.EqualTo("ReplacementName")); } [Test] @@ -69,7 +69,7 @@ public void ColumnDropper_NoMatchingColumnAtRuntime() var ex = Assert.Throws(() => dropper.ProcessPipelineData(toProcess, ThrowImmediatelyDataLoadEventListener.Quiet, cts.Token)); - Assert.IsTrue(ex.Message.Contains("does not exist in the supplied data table")); + Assert.That(ex.Message, Does.Contain("does not exist in the supplied data table")); } [Test] @@ -86,8 +86,8 @@ public void ColumnDropper_Successful() var processed = dropper.ProcessPipelineData(toProcess, ThrowImmediatelyDataLoadEventListener.Quiet, cts.Token); - Assert.AreEqual(0, processed.Columns.Count); - Assert.AreEqual(false, processed.Columns.Contains("ToDrop")); + Assert.That(processed.Columns, Is.Empty); + Assert.That(processed.Columns.Contains("ToDrop"), Is.EqualTo(false)); } } @@ -114,6 +114,6 @@ public void ColumnForbidderTest_MatchingColumn() forbidlister.Rationale = "kaleidoscope engage"; var ex = Assert.Throws(() => forbidlister.ProcessPipelineData(toProcess, new ThrowImmediatelyDataLoadJob(), null)); - Assert.IsTrue(ex.Message.Contains("kaleidoscope engage")); + Assert.That(ex.Message, Does.Contain("kaleidoscope engage")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Unit/ExcelTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Unit/ExcelTests.cs index 50183dcb14..5a97877254 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Unit/ExcelTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Unit/ExcelTests.cs @@ -54,8 +54,11 @@ public void SprayToDisk() [Test] public void TestFilesExists() { - Assert.IsTrue(_fileLocations[TestFile].Exists); - Assert.IsTrue(_fileLocations[FreakyTestFile].Exists); + Assert.Multiple(() => + { + Assert.That(_fileLocations[TestFile].Exists); + Assert.That(_fileLocations[FreakyTestFile].Exists); + }); } [Test] @@ -67,7 +70,7 @@ public void DontTryToOpenWithDelimited_ThrowsInvalidFileExtension() }; invalid.PreInitialize(new FlatFileToLoad(new FileInfo(TestFile)), ThrowImmediatelyDataLoadEventListener.Quiet); var ex = Assert.Throws(() => invalid.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.Contains("File Book1.xlsx has a prohibited file extension .xlsx", ex?.Message); + Assert.That(ex?.Message, Does.Contain("File Book1.xlsx has a prohibited file extension .xlsx")); } [Test] @@ -81,18 +84,21 @@ public void NormalBook_FirstRowCorrect(string versionOfTestFile) ThrowImmediatelyDataLoadEventListener.Quiet); var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(6, dt.Columns.Count); - Assert.AreEqual("Participant", dt.Columns[0].ColumnName); - Assert.AreEqual("Score", dt.Columns[1].ColumnName); - Assert.AreEqual("IsEvil", dt.Columns[2].ColumnName); - - Assert.AreEqual("DateField", dt.Columns[3].ColumnName); - Assert.AreEqual("DoubleField", dt.Columns[4].ColumnName); - Assert.AreEqual("MixedField", dt.Columns[5].ColumnName); - - Assert.AreEqual("Bob", dt.Rows[0][0]); - Assert.AreEqual("3", dt.Rows[0][1]); - Assert.AreEqual("yes", dt.Rows[0][2]); + Assert.That(dt.Columns, Has.Count.EqualTo(6)); + Assert.Multiple(() => + { + Assert.That(dt.Columns[0].ColumnName, Is.EqualTo("Participant")); + Assert.That(dt.Columns[1].ColumnName, Is.EqualTo("Score")); + Assert.That(dt.Columns[2].ColumnName, Is.EqualTo("IsEvil")); + + Assert.That(dt.Columns[3].ColumnName, Is.EqualTo("DateField")); + Assert.That(dt.Columns[4].ColumnName, Is.EqualTo("DoubleField")); + Assert.That(dt.Columns[5].ColumnName, Is.EqualTo("MixedField")); + + Assert.That(dt.Rows[0][0], Is.EqualTo("Bob")); + Assert.That(dt.Rows[0][1], Is.EqualTo("3")); + Assert.That(dt.Rows[0][2], Is.EqualTo("yes")); + }); } @@ -110,21 +116,24 @@ public void NormalBook_FirstRowCorrect_AddFilenameColumnNamed(string versionOfTe ThrowImmediatelyDataLoadEventListener.Quiet); var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - Assert.AreEqual(7, dt.Columns.Count); - Assert.AreEqual("Participant", dt.Columns[0].ColumnName); - Assert.AreEqual("Score", dt.Columns[1].ColumnName); - Assert.AreEqual("IsEvil", dt.Columns[2].ColumnName); + Assert.That(dt.Columns, Has.Count.EqualTo(7)); + Assert.Multiple(() => + { + Assert.That(dt.Columns[0].ColumnName, Is.EqualTo("Participant")); + Assert.That(dt.Columns[1].ColumnName, Is.EqualTo("Score")); + Assert.That(dt.Columns[2].ColumnName, Is.EqualTo("IsEvil")); - Assert.AreEqual("DateField", dt.Columns[3].ColumnName); - Assert.AreEqual("DoubleField", dt.Columns[4].ColumnName); - Assert.AreEqual("MixedField", dt.Columns[5].ColumnName); - Assert.AreEqual("Path", dt.Columns[6].ColumnName); + Assert.That(dt.Columns[3].ColumnName, Is.EqualTo("DateField")); + Assert.That(dt.Columns[4].ColumnName, Is.EqualTo("DoubleField")); + Assert.That(dt.Columns[5].ColumnName, Is.EqualTo("MixedField")); + Assert.That(dt.Columns[6].ColumnName, Is.EqualTo("Path")); - Assert.AreEqual("Bob", dt.Rows[0][0]); - Assert.AreEqual("3", dt.Rows[0][1]); - Assert.AreEqual("yes", dt.Rows[0][2]); + Assert.That(dt.Rows[0][0], Is.EqualTo("Bob")); + Assert.That(dt.Rows[0][1], Is.EqualTo("3")); + Assert.That(dt.Rows[0][2], Is.EqualTo("yes")); - Assert.AreEqual(_fileLocations[versionOfTestFile].FullName, dt.Rows[0][6]); + Assert.That(dt.Rows[0][6], Is.EqualTo(_fileLocations[versionOfTestFile].FullName)); + }); } @@ -146,27 +155,30 @@ public void ExcelDateTimeDeciphering(string versionOfTestFile) source.PreInitialize(new FlatFileToLoad(_fileLocations[versionOfTestFile]), listener); var dt = source.GetChunk(listener, new GracefulCancellationToken()); - Assert.AreEqual(5, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(5)); - Assert.AreEqual("2001-01-01", dt.Rows[0][3]); - Assert.AreEqual("0.1", dt.Rows[0][4]); - Assert.AreEqual("10:30:00", dt.Rows[0][5]); - - Assert.AreEqual("2001-01-01 10:30:00", dt.Rows[1][3]); - Assert.AreEqual("0.51", dt.Rows[1][4]); - Assert.AreEqual("11:30:00", dt.Rows[1][5]); - - Assert.AreEqual("2002-01-01 11:30:00", dt.Rows[2][3]); - Assert.AreEqual("0.22", dt.Rows[2][4]); - Assert.AreEqual("0.1", dt.Rows[2][5]); - - Assert.AreEqual("2003-01-01 01:30:00", dt.Rows[3][3]); - Assert.AreEqual("0.10", dt.Rows[3][4]); - Assert.AreEqual("0.51", dt.Rows[3][5]); - - Assert.AreEqual("2015-09-18", dt.Rows[4][3]); - Assert.AreEqual("15:09:00", dt.Rows[4][4]); - Assert.AreEqual("00:03:56", dt.Rows[4][5]); + Assert.Multiple(() => + { + Assert.That(dt.Rows[0][3], Is.EqualTo("2001-01-01")); + Assert.That(dt.Rows[0][4], Is.EqualTo("0.1")); + Assert.That(dt.Rows[0][5], Is.EqualTo("10:30:00")); + + Assert.That(dt.Rows[1][3], Is.EqualTo("2001-01-01 10:30:00")); + Assert.That(dt.Rows[1][4], Is.EqualTo("0.51")); + Assert.That(dt.Rows[1][5], Is.EqualTo("11:30:00")); + + Assert.That(dt.Rows[2][3], Is.EqualTo("2002-01-01 11:30:00")); + Assert.That(dt.Rows[2][4], Is.EqualTo("0.22")); + Assert.That(dt.Rows[2][5], Is.EqualTo("0.1")); + + Assert.That(dt.Rows[3][3], Is.EqualTo("2003-01-01 01:30:00")); + Assert.That(dt.Rows[3][4], Is.EqualTo("0.10")); + Assert.That(dt.Rows[3][5], Is.EqualTo("0.51")); + + Assert.That(dt.Rows[4][3], Is.EqualTo("2015-09-18")); + Assert.That(dt.Rows[4][4], Is.EqualTo("15:09:00")); + Assert.That(dt.Rows[4][5], Is.EqualTo("00:03:56")); + }); } [Test] @@ -182,30 +194,35 @@ public void TestOddFormats() source.PreInitialize(new FlatFileToLoad(_fileLocations[OddFormatsFile]), listener); var dt = source.GetChunk(listener, new GracefulCancellationToken()); - Assert.AreEqual(2, dt.Rows.Count); - Assert.AreEqual(5, dt.Columns.Count); - - Assert.AreEqual("Name", dt.Columns[0].ColumnName); - Assert.AreEqual("Category", dt.Columns[1].ColumnName); - Assert.AreEqual("Age", dt.Columns[2].ColumnName); - Assert.AreEqual("Wage", dt.Columns[3].ColumnName); - Assert.AreEqual("Invisibre", - dt.Columns[4].ColumnName); //this column is hidden in the spreadsheet but we still load it - - Assert.AreEqual("Frank", dt.Rows[0][0]); - Assert.AreEqual("Upper, Left", dt.Rows[0][1]); - Assert.AreEqual("30", dt.Rows[0][2]); - - //its a pound symbol alright! but since there is 2 encodings for pound symbol let's just make everyones life easier - StringAssert.IsMatch(@"^\W11.00$", dt.Rows[0][3].ToString()); - - Assert.AreEqual("0.1", dt.Rows[0][4]); + Assert.Multiple(() => + { + Assert.That(dt.Rows, Has.Count.EqualTo(2)); + Assert.That(dt.Columns, Has.Count.EqualTo(5)); + }); - Assert.AreEqual("Castello", dt.Rows[1][0]); - Assert.AreEqual("Lower, Back", dt.Rows[1][1]); - Assert.AreEqual("31", dt.Rows[1][2]); - Assert.AreEqual("50.00%", dt.Rows[1][3]); - Assert.AreEqual("0.2", dt.Rows[1][4]); + Assert.Multiple(() => + { + Assert.That(dt.Columns[0].ColumnName, Is.EqualTo("Name")); + Assert.That(dt.Columns[1].ColumnName, Is.EqualTo("Category")); + Assert.That(dt.Columns[2].ColumnName, Is.EqualTo("Age")); + Assert.That(dt.Columns[3].ColumnName, Is.EqualTo("Wage")); + Assert.That(dt.Columns[4].ColumnName, Is.EqualTo("Invisibre")); //this column is hidden in the spreadsheet but we still load it + + Assert.That(dt.Rows[0][0], Is.EqualTo("Frank")); + Assert.That(dt.Rows[0][1], Is.EqualTo("Upper, Left")); + Assert.That(dt.Rows[0][2], Is.EqualTo("30")); + + //its a pound symbol alright! but since there is 2 encodings for pound symbol let's just make everyones life easier + Assert.That(dt.Rows[0][3].ToString(), Does.Match(@"^\W11.00$")); + + Assert.That(dt.Rows[0][4], Is.EqualTo("0.1")); + + Assert.That(dt.Rows[1][0], Is.EqualTo("Castello")); + Assert.That(dt.Rows[1][1], Is.EqualTo("Lower, Back")); + Assert.That(dt.Rows[1][2], Is.EqualTo("31")); + Assert.That(dt.Rows[1][3], Is.EqualTo("50.00%")); + Assert.That(dt.Rows[1][4], Is.EqualTo("0.2")); + }); } @@ -219,7 +236,7 @@ public void NormalBook_NoEmptyRowsRead() source.PreInitialize(new FlatFileToLoad(_fileLocations[TestFile]), listener); var dt = source.GetChunk(listener, new GracefulCancellationToken()); - Assert.AreEqual(5, dt.Rows.Count); + Assert.That(dt.Rows, Has.Count.EqualTo(5)); } [Test] @@ -237,7 +254,7 @@ public void FreakyTestFile_WarningsCorrect() Console.Write(messages.ToString()); - Assert.IsTrue(args.Any(a => + Assert.That(args.Any(a => a.Message.Contains("Discarded the following data (that was found in unnamed columns):RowCount:5") && a.ProgressEventType == ProgressEventType.Warning)); } @@ -249,18 +266,23 @@ public void BlankFirstLineFile() var fi = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, "DataLoad", "Engine", "Resources", "BlankLineBook.xlsx")); - Assert.IsTrue(fi.Exists); + Assert.That(fi.Exists); source.PreInitialize(new FlatFileToLoad(fi), ThrowImmediatelyDataLoadEventListener.Quiet); var dt = source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken()); - - Assert.AreEqual(3, dt.Rows.Count); - Assert.AreEqual(2, dt.Columns.Count); - Assert.AreEqual("Name", dt.Columns[0].ColumnName); - Assert.AreEqual("Age", dt.Columns[1].ColumnName); + Assert.Multiple(() => + { + Assert.That(dt.Rows, Has.Count.EqualTo(3)); + Assert.That(dt.Columns, Has.Count.EqualTo(2)); + }); + Assert.Multiple(() => + { + Assert.That(dt.Columns[0].ColumnName, Is.EqualTo("Name")); + Assert.That(dt.Columns[1].ColumnName, Is.EqualTo("Age")); + }); } @@ -272,14 +294,14 @@ public void BlankWorkbook() var fi = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, "DataLoad", "Engine", "Resources", "BlankBook.xlsx")); - Assert.IsTrue(fi.Exists); + Assert.That(fi.Exists); source.PreInitialize(new FlatFileToLoad(fi), ThrowImmediatelyDataLoadEventListener.Quiet); var ex = Assert.Throws(() => source.GetChunk(ThrowImmediatelyDataLoadEventListener.Quiet, new GracefulCancellationToken())); - Assert.AreEqual("The Excel sheet 'Sheet1' in workbook 'BlankBook.xlsx' is empty", ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("The Excel sheet 'Sheet1' in workbook 'BlankBook.xlsx' is empty")); } [Test] @@ -296,8 +318,7 @@ public void Checks_ValidFileExtension_InvalidExtensionPass() var source = new ExcelDataFlowSource(); source.PreInitialize(new FlatFileToLoad(new FileInfo("bob.csv")), ThrowImmediatelyDataLoadEventListener.Quiet); var ex = Assert.Throws(() => source.Check(ThrowImmediatelyCheckNotifier.QuietPicky)); - Assert.AreEqual("File extension bob.csv has an invalid extension:.csv (this class only accepts:.xlsx,.xls)", - ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("File extension bob.csv has an invalid extension:.csv (this class only accepts:.xlsx,.xls)")); } [TestCase(true)] @@ -326,17 +347,17 @@ public void TestToCSVConverter(bool prefixWithWorkbookName) ? loc.Directory.GetFiles("Book1_Sheet1.csv").Single() : loc.Directory.GetFiles("Sheet1.csv").Single(); - Assert.IsTrue(file.Exists); + Assert.That(file.Exists); var contents = File.ReadAllText(file.FullName); - Assert.AreEqual( - @"Participant,Score,IsEvil,DateField,DoubleField,MixedField + Assert.That( +contents.Trim(new[] { ',', '\r', '\n', ' ', '\t' }), Is.EqualTo(@"Participant,Score,IsEvil,DateField,DoubleField,MixedField Bob,3,yes,2001-01-01,0.1,10:30:00 Frank,1.1,no,2001-01-01 10:30:00,0.51,11:30:00 Hank,2.1,no,2002-01-01 11:30:00,0.22,0.1 Shanker,2,yes,2003-01-01 01:30:00,0.10,0.51 -Bobboy,2,maybe,2015-09-18,15:09:00,00:03:56", contents.Trim(new[] { ',', '\r', '\n', ' ', '\t' })); +Bobboy,2,maybe,2015-09-18,15:09:00,00:03:56")); file.Delete(); } diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Unit/ExecutableProcessTaskTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Unit/ExecutableProcessTaskTests.cs index 74e6349740..05a6ac22a5 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Unit/ExecutableProcessTaskTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Unit/ExecutableProcessTaskTests.cs @@ -34,7 +34,7 @@ public void TestCreateArgString() var argString = task.CreateArgString(); const string expectedArgString = $"--database-name={db}"; - Assert.AreEqual(expectedArgString, argString); + Assert.That(argString, Is.EqualTo(expectedArgString)); } [Test] @@ -44,6 +44,6 @@ public void TestConstructionFromProcessTask() processTask.Path.Returns("path"); var runtimeTask = new ExecutableRuntimeTask(processTask, null); - Assert.AreEqual("path", runtimeTask.ExeFilepath); + Assert.That(runtimeTask.ExeFilepath, Is.EqualTo("path")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Unit/JobDateGenerationStrategyFactoryTestsUnit.cs b/Rdmp.Core.Tests/DataLoad/Engine/Unit/JobDateGenerationStrategyFactoryTestsUnit.cs index e33e001e32..88ffab9a8c 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Unit/JobDateGenerationStrategyFactoryTestsUnit.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Unit/JobDateGenerationStrategyFactoryTestsUnit.cs @@ -24,8 +24,7 @@ public void NoDates() var ex = Assert.Throws(() => factory.Create(lp, ThrowImmediatelyDataLoadEventListener.Quiet)); - Assert.AreEqual("Don't know when to start the data load, both DataLoadProgress and OriginDate are null", - ex?.Message); + Assert.That(ex?.Message, Is.EqualTo("Don't know when to start the data load, both DataLoadProgress and OriginDate are null")); } [Test] @@ -36,7 +35,6 @@ public void DateKnown_NoCache_SuggestSingleScheduleConsecutiveDateStrategy() var factory = new JobDateGenerationStrategyFactory(new SingleLoadProgressSelectionStrategy(lp)); - Assert.AreEqual(typeof(SingleScheduleConsecutiveDateStrategy), - factory.Create(lp, ThrowImmediatelyDataLoadEventListener.Quiet).GetType()); + Assert.That(factory.Create(lp, ThrowImmediatelyDataLoadEventListener.Quiet).GetType(), Is.EqualTo(typeof(SingleScheduleConsecutiveDateStrategy))); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Unit/JobDateGenerationStrategyTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Unit/JobDateGenerationStrategyTests.cs index 4f2a482a03..e68ffab858 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Unit/JobDateGenerationStrategyTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Unit/JobDateGenerationStrategyTests.cs @@ -25,14 +25,20 @@ public void TestSingleScheduleConsecutiveDateStrategy() var strategy = new SingleScheduleConsecutiveDateStrategy(schedule); var dates = strategy.GetDates(2, false); - Assert.AreEqual(2, dates.Count); - Assert.AreEqual(new DateTime(2015, 1, 2), dates[0]); - Assert.AreEqual(new DateTime(2015, 1, 3), dates[1]); + Assert.That(dates, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(dates[0], Is.EqualTo(new DateTime(2015, 1, 2))); + Assert.That(dates[1], Is.EqualTo(new DateTime(2015, 1, 3))); + }); dates = strategy.GetDates(2, false); - Assert.AreEqual(2, dates.Count); - Assert.AreEqual(new DateTime(2015, 1, 4), dates[0]); - Assert.AreEqual(new DateTime(2015, 1, 5), dates[1]); + Assert.That(dates, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(dates[0], Is.EqualTo(new DateTime(2015, 1, 4))); + Assert.That(dates[1], Is.EqualTo(new DateTime(2015, 1, 5))); + }); } [Test] @@ -46,8 +52,11 @@ public void TestSingleScheduleConsecutiveDateStrategy_FutureDates_AreForbidden() var strategy = new SingleScheduleConsecutiveDateStrategy(schedule); var dates = strategy.GetDates(100, false); - Assert.AreEqual(dates.Count, 1); - Assert.AreEqual(dates[0], DateTime.Now.Date.AddDays(-1)); //it should try to load yesterday + Assert.Multiple(() => + { + Assert.That(dates, Has.Count.EqualTo(1)); + Assert.That(DateTime.Now.Date.AddDays(-1), Is.EqualTo(dates[0])); //it should try to load yesterday + }); } [Test] @@ -61,9 +70,12 @@ public void TestSingleScheduleConsecutiveDateStrategy_FutureDates_AreAllowed() var strategy = new SingleScheduleConsecutiveDateStrategy(schedule); var dates = strategy.GetDates(100, true); - Assert.AreEqual(dates.Count, 100); - Assert.AreEqual(dates[0], DateTime.Now.Date.AddDays(-1)); //it should try to load yesterday - Assert.AreEqual(dates[99], DateTime.Now.Date.AddDays(98)); //it should try to load yesterday + Assert.Multiple(() => + { + Assert.That(dates, Has.Count.EqualTo(100)); + Assert.That(DateTime.Now.Date.AddDays(-1), Is.EqualTo(dates[0])); //it should try to load yesterday + Assert.That(DateTime.Now.Date.AddDays(98), Is.EqualTo(dates[99])); //it should try to load yesterday + }); } [Test] diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Unit/MDFAttacherTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Unit/MDFAttacherTests.cs index 38394e3d95..89abadb449 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Unit/MDFAttacherTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Unit/MDFAttacherTests.cs @@ -91,7 +91,7 @@ public void Test_MDFFile_AlreadyExists() , new GracefulCancellationToken()) ); - StringAssert.Contains("Overwriting", ex?.Message); + Assert.That(ex?.Message, Does.Contain("Overwriting")); } finally { @@ -128,17 +128,16 @@ public void TestLocations_NoNetworkPath() var locations = new MdfFileAttachLocations(new DirectoryInfo(TestContext.CurrentContext.TestDirectory), serverDatabasePath, null); + Assert.Multiple(() => + { + Assert.That(locations.OriginLocationMdf, Is.EqualTo(new FileInfo(mdf).FullName)); + Assert.That(locations.OriginLocationLdf, Is.EqualTo(new FileInfo(ldf).FullName)); - Assert.AreEqual(new FileInfo(mdf).FullName, locations.OriginLocationMdf); - Assert.AreEqual(new FileInfo(ldf).FullName, locations.OriginLocationLdf); - - Assert.AreEqual(@"H:/Program Files/Microsoft SQL Server/MSSQL13.SQLEXPRESS/MSSQL/DATA/MyFile_log.ldf", - locations.CopyToLdf); - Assert.AreEqual(@"H:/Program Files/Microsoft SQL Server/MSSQL13.SQLEXPRESS/MSSQL/DATA/MyFile.mdf", - locations.CopyToMdf); + Assert.That(locations.CopyToLdf, Is.EqualTo(@"H:/Program Files/Microsoft SQL Server/MSSQL13.SQLEXPRESS/MSSQL/DATA/MyFile_log.ldf")); + Assert.That(locations.CopyToMdf, Is.EqualTo(@"H:/Program Files/Microsoft SQL Server/MSSQL13.SQLEXPRESS/MSSQL/DATA/MyFile.mdf")); - Assert.AreEqual(@"H:/Program Files/Microsoft SQL Server/MSSQL13.SQLEXPRESS/MSSQL/DATA/MyFile.mdf", - locations.AttachMdfPath); + Assert.That(locations.AttachMdfPath, Is.EqualTo(@"H:/Program Files/Microsoft SQL Server/MSSQL13.SQLEXPRESS/MSSQL/DATA/MyFile.mdf")); + }); } finally { @@ -190,7 +189,7 @@ public void ConnectToServer() "MDFAttacherTest", true); var db = DiscoveredServerICanCreateRandomDatabasesAndTablesOn.ExpectDatabase("MyImaginaryDB_RAW"); - Assert.IsFalse(db.Exists()); + Assert.That(db.Exists(), Is.False); var mdf = new MDFAttacher(); mdf.Initialize(hicProjDir, db); @@ -198,7 +197,7 @@ public void ConnectToServer() { var memory = new ToMemoryCheckNotifier(ThrowImmediatelyCheckNotifier.Quiet); mdf.Check(memory); - Assert.IsTrue(memory.Messages.Any(m => + Assert.That(memory.Messages.Any(m => m.Message.Contains("Found server DATA folder") && m.Result == CheckResult.Success)); } catch (Exception e) @@ -211,7 +210,7 @@ public void ConnectToServer() var memory2 = new ToMemoryCheckNotifier(ThrowImmediatelyCheckNotifier.Quiet); mdf.OverrideMDFFileCopyDestination = TestContext.CurrentContext.WorkDirectory; mdf.Check(memory2); - Assert.IsTrue(memory2.Messages.Any(m => Regex.IsMatch(m.Message, + Assert.That(memory2.Messages.Any(m => Regex.IsMatch(m.Message, $@"Found server DATA folder .*{Regex.Escape(TestContext.CurrentContext.WorkDirectory)}") && m.Result == CheckResult.Success)); @@ -239,15 +238,16 @@ public void TestLocations_NetworkPath() var locations = new MdfFileAttachLocations(new DirectoryInfo(TestContext.CurrentContext.TestDirectory), serverDatabasePath, @"//MyDbServer1/Share/Database"); + Assert.Multiple(() => + { + Assert.That(locations.OriginLocationMdf, Is.EqualTo(new FileInfo(mdf).FullName)); + Assert.That(locations.OriginLocationLdf, Is.EqualTo(new FileInfo(ldf).FullName)); - Assert.AreEqual(new FileInfo(mdf).FullName, locations.OriginLocationMdf); - Assert.AreEqual(new FileInfo(ldf).FullName, locations.OriginLocationLdf); - - StringAssert.IsMatch(@"//MyDbServer1/Share/Database[/\\]MyFile_log.ldf", locations.CopyToLdf); - StringAssert.IsMatch(@"//MyDbServer1/Share/Database[/\\]MyFile.mdf", locations.CopyToMdf); + Assert.That(locations.CopyToLdf, Does.Match(@"//MyDbServer1/Share/Database[/\\]MyFile_log.ldf")); + Assert.That(locations.CopyToMdf, Does.Match(@"//MyDbServer1/Share/Database[/\\]MyFile.mdf")); - Assert.AreEqual(@"H:/Program Files/Microsoft SQL Server/MSSQL13.SQLEXPRESS/MSSQL/DATA/MyFile.mdf", - locations.AttachMdfPath); + Assert.That(locations.AttachMdfPath, Is.EqualTo(@"H:/Program Files/Microsoft SQL Server/MSSQL13.SQLEXPRESS/MSSQL/DATA/MyFile.mdf")); + }); } finally { @@ -323,8 +323,8 @@ public void TestFactory() { attacher.Initialize(loadDirectory, GetCleanedServer(FAnsi.DatabaseType.MicrosoftSQLServer)); - Assert.IsNotNull(attacher); - Assert.IsInstanceOf(attacher); + Assert.That(attacher, Is.Not.Null); + Assert.That(attacher, Is.InstanceOf()); } finally { diff --git a/Rdmp.Core.Tests/DataLoad/Engine/Unit/SchedulingTests.cs b/Rdmp.Core.Tests/DataLoad/Engine/Unit/SchedulingTests.cs index 240d1cc5f9..a394ccbc4a 100644 --- a/Rdmp.Core.Tests/DataLoad/Engine/Unit/SchedulingTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Engine/Unit/SchedulingTests.cs @@ -24,7 +24,7 @@ public void TestLoadDateCalculation_DayGranularity() var lastLoadDate = SingleScheduleCacheDateTrackingStrategy.CalculateLastLoadDate(CacheFileGranularity.Day, cacheFillProgress); - Assert.AreEqual(new DateTime(2015, 12, 10, 0, 0, 0).Ticks, lastLoadDate.Ticks); + Assert.That(lastLoadDate.Ticks, Is.EqualTo(new DateTime(2015, 12, 10, 0, 0, 0).Ticks)); } [Test] @@ -37,7 +37,7 @@ public void TestLoadDateCalculation_DayGranularityAtMonthBoundary() var lastLoadDate = SingleScheduleCacheDateTrackingStrategy.CalculateLastLoadDate(CacheFileGranularity.Day, cacheFillProgress); - Assert.AreEqual(new DateTime(2015, 11, 30, 0, 0, 0).Ticks, lastLoadDate.Ticks); + Assert.That(lastLoadDate.Ticks, Is.EqualTo(new DateTime(2015, 11, 30, 0, 0, 0).Ticks)); } [Test] @@ -50,6 +50,6 @@ public void TestLoadDateCalculation_HourGranularity() var lastLoadDate = SingleScheduleCacheDateTrackingStrategy.CalculateLastLoadDate(CacheFileGranularity.Hour, cacheFillProgress); - Assert.AreEqual(new DateTime(2015, 12, 11, 14, 0, 0).Ticks, lastLoadDate.Ticks); + Assert.That(lastLoadDate.Ticks, Is.EqualTo(new DateTime(2015, 12, 11, 14, 0, 0).Ticks)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Modules/Attachers/RemoteTableAttacherTests.cs b/Rdmp.Core.Tests/DataLoad/Modules/Attachers/RemoteTableAttacherTests.cs index 7c7dc948e1..9eff584697 100644 --- a/Rdmp.Core.Tests/DataLoad/Modules/Attachers/RemoteTableAttacherTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Modules/Attachers/RemoteTableAttacherTests.cs @@ -99,35 +99,39 @@ private void RunAttachStageWithNormalJob(RemoteTableAttacher attacher, Discovere attacher.Initialize(null, db); - using (var dt = new DataTable()) - { - dt.Columns.Add("Col1"); - dt.Rows.Add("fff"); + using var dt = new DataTable(); + dt.Columns.Add("Col1"); + dt.Rows.Add("fff"); - var tbl1 = db.CreateTable("table1", dt); - var tbl2 = db.CreateTable("table2", - new[] { new DatabaseColumnRequest("Col1", new DatabaseTypeRequest(typeof(string), 5)) }); + var tbl1 = db.CreateTable("table1", dt); + var tbl2 = db.CreateTable("table2", + new[] { new DatabaseColumnRequest("Col1", new DatabaseTypeRequest(typeof(string), 5)) }); - Assert.AreEqual(1, tbl1.GetRowCount()); - Assert.AreEqual(0, tbl2.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(tbl1.GetRowCount(), Is.EqualTo(1)); + Assert.That(tbl2.GetRowCount(), Is.EqualTo(0)); + }); - var logManager = new LogManager(new DiscoveredServer(UnitTestLoggingConnectionString)); + var logManager = new LogManager(new DiscoveredServer(UnitTestLoggingConnectionString)); - var lmd = RdmpMockFactory.Mock_LoadMetadataLoadingTable(tbl2); - lmd.CatalogueRepository.Returns(CatalogueRepository); - logManager.CreateNewLoggingTaskIfNotExists(lmd.GetDistinctLoggingTask()); + var lmd = RdmpMockFactory.Mock_LoadMetadataLoadingTable(tbl2); + lmd.CatalogueRepository.Returns(CatalogueRepository); + logManager.CreateNewLoggingTaskIfNotExists(lmd.GetDistinctLoggingTask()); - var dbConfiguration = new HICDatabaseConfiguration(lmd, - RdmpMockFactory.Mock_INameDatabasesAndTablesDuringLoads(db, "table2")); + var dbConfiguration = new HICDatabaseConfiguration(lmd, + RdmpMockFactory.Mock_INameDatabasesAndTablesDuringLoads(db, "table2")); - var job = new DataLoadJob(RepositoryLocator, "test job", logManager, lmd, new TestLoadDirectory(), - ThrowImmediatelyDataLoadEventListener.Quiet, dbConfiguration); - job.StartLogging(); - attacher.Attach(job, new GracefulCancellationToken()); + var job = new DataLoadJob(RepositoryLocator, "test job", logManager, lmd, new TestLoadDirectory(), + ThrowImmediatelyDataLoadEventListener.Quiet, dbConfiguration); + job.StartLogging(); + attacher.Attach(job, new GracefulCancellationToken()); - Assert.AreEqual(1, tbl1.GetRowCount()); - Assert.AreEqual(1, tbl2.GetRowCount()); - } + Assert.Multiple(() => + { + Assert.That(tbl1.GetRowCount(), Is.EqualTo(1)); + Assert.That(tbl2.GetRowCount(), Is.EqualTo(1)); + }); } private void RunAttachStageWithLoadProgressJob(RemoteTableAttacher attacher, DiscoveredDatabase db, @@ -160,8 +164,11 @@ private void RunAttachStageWithLoadProgressJob(RemoteTableAttacher attacher, Dis new DatabaseColumnRequest("DateCol", new DatabaseTypeRequest(typeof(DateTime))) }); - Assert.AreEqual(3, tbl1.GetRowCount()); - Assert.AreEqual(0, tbl2.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(tbl1.GetRowCount(), Is.EqualTo(3)); + Assert.That(tbl2.GetRowCount(), Is.EqualTo(0)); + }); var logManager = new LogManager(new DiscoveredServer(UnitTestLoggingConnectionString)); @@ -193,7 +200,10 @@ private void RunAttachStageWithLoadProgressJob(RemoteTableAttacher attacher, Dis job.StartLogging(); attacher.Attach(job, new GracefulCancellationToken()); - Assert.AreEqual(3, tbl1.GetRowCount()); - Assert.AreEqual(mismatchProgress ? 0 : 1, tbl2.GetRowCount()); + Assert.Multiple(() => + { + Assert.That(tbl1.GetRowCount(), Is.EqualTo(3)); + Assert.That(tbl2.GetRowCount(), Is.EqualTo(mismatchProgress ? 0 : 1)); + }); } } diff --git a/Rdmp.Core.Tests/DataLoad/Modules/DataFlowOperations/RowDeleterTests.cs b/Rdmp.Core.Tests/DataLoad/Modules/DataFlowOperations/RowDeleterTests.cs index 2aeb6a8029..1397d514ab 100644 --- a/Rdmp.Core.Tests/DataLoad/Modules/DataFlowOperations/RowDeleterTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Modules/DataFlowOperations/RowDeleterTests.cs @@ -37,19 +37,25 @@ public void TestRowDeleter_OneCell() var result = operation.ProcessPipelineData(dt, listener, new GracefulCancellationToken()); - Assert.AreEqual(2, result.Rows.Count); + Assert.That(result.Rows, Has.Count.EqualTo(2)); - Assert.AreEqual("dog", result.Rows[0]["a"]); - Assert.AreEqual("dog", result.Rows[0]["b"]); + Assert.Multiple(() => + { + Assert.That(result.Rows[0]["a"], Is.EqualTo("dog")); + Assert.That(result.Rows[0]["b"], Is.EqualTo("dog")); - Assert.AreEqual("cat", result.Rows[1]["a"]); - Assert.AreEqual("dog", result.Rows[1]["b"]); + Assert.That(result.Rows[1]["a"], Is.EqualTo("cat")); + Assert.That(result.Rows[1]["b"], Is.EqualTo("dog")); + }); operation.Dispose(listener, null); var msg = listener.EventsReceivedBySender[operation].Single(); - Assert.AreEqual(ProgressEventType.Warning, msg.ProgressEventType); - Assert.AreEqual("Total RowDeleted operations for ColumnNameToFind 'b' was 1", msg.Message); + Assert.Multiple(() => + { + Assert.That(msg.ProgressEventType, Is.EqualTo(ProgressEventType.Warning)); + Assert.That(msg.Message, Is.EqualTo("Total RowDeleted operations for ColumnNameToFind 'b' was 1")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataLoad/Modules/DataFlowOperations/SetNullTests.cs b/Rdmp.Core.Tests/DataLoad/Modules/DataFlowOperations/SetNullTests.cs index 0c8227b85c..0de26ed49e 100644 --- a/Rdmp.Core.Tests/DataLoad/Modules/DataFlowOperations/SetNullTests.cs +++ b/Rdmp.Core.Tests/DataLoad/Modules/DataFlowOperations/SetNullTests.cs @@ -38,22 +38,28 @@ public void TestSetNull_OneCell() var result = operation.ProcessPipelineData(dt, listener, new GracefulCancellationToken()); - Assert.AreEqual(3, result.Rows.Count); + Assert.That(result.Rows, Has.Count.EqualTo(3)); - Assert.AreEqual("cat", result.Rows[0]["a"]); - Assert.AreEqual(DBNull.Value, result.Rows[0]["b"]); + Assert.Multiple(() => + { + Assert.That(result.Rows[0]["a"], Is.EqualTo("cat")); + Assert.That(result.Rows[0]["b"], Is.EqualTo(DBNull.Value)); - Assert.AreEqual("dog", result.Rows[1]["a"]); - Assert.AreEqual("dog", result.Rows[1]["b"]); + Assert.That(result.Rows[1]["a"], Is.EqualTo("dog")); + Assert.That(result.Rows[1]["b"], Is.EqualTo("dog")); - Assert.AreEqual("cat", result.Rows[2]["a"]); - Assert.AreEqual("dog", result.Rows[2]["b"]); + Assert.That(result.Rows[2]["a"], Is.EqualTo("cat")); + Assert.That(result.Rows[2]["b"], Is.EqualTo("dog")); + }); operation.Dispose(listener, null); var msg = listener.EventsReceivedBySender[operation].Single(); - Assert.AreEqual(ProgressEventType.Warning, msg.ProgressEventType); - Assert.AreEqual("Total SetNull operations for ColumnNameToFind 'b' was 1", msg.Message); + Assert.Multiple(() => + { + Assert.That(msg.ProgressEventType, Is.EqualTo(ProgressEventType.Warning)); + Assert.That(msg.Message, Is.EqualTo("Total SetNull operations for ColumnNameToFind 'b' was 1")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/DataQualityEngine/CatalogueConstraintReportTests.cs b/Rdmp.Core.Tests/DataQualityEngine/CatalogueConstraintReportTests.cs index 6a6a9cd298..f36d3b233a 100644 --- a/Rdmp.Core.Tests/DataQualityEngine/CatalogueConstraintReportTests.cs +++ b/Rdmp.Core.Tests/DataQualityEngine/CatalogueConstraintReportTests.cs @@ -51,7 +51,7 @@ public void ValidateBulkTestData(DatabaseType dbType, bool testCancellingValidat var dqeRepository = GetDqeRepository(dbType); //there shouldn't be any lingering results in the database - Assert.IsNull(dqeRepository.GetMostRecentEvaluationFor(_catalogue)); + Assert.That(dqeRepository.GetMostRecentEvaluationFor(_catalogue), Is.Null); //set some validation rules testData.catalogue.ValidatorXML = bulkTestDataValidation; @@ -79,13 +79,13 @@ public void ValidateBulkTestData(DatabaseType dbType, bool testCancellingValidat if (testCancellingValidationEarly) { - Assert.IsTrue( - listener.EventsReceivedBySender[report].Count(m => m.Exception is OperationCanceledException) == 1); + Assert.That( + listener.EventsReceivedBySender[report].Count(m => m.Exception is OperationCanceledException), Is.EqualTo(1)); testData.DeleteCatalogue(); return; } - Assert.IsTrue(listener.EventsReceivedBySender[report].All(m => m.Exception == null), + Assert.That(listener.EventsReceivedBySender[report].All(m => m.Exception == null), string.Join(Environment.NewLine, listener.EventsReceivedBySender[report].Where(m => m.Exception != null) .Select(m => m.Exception))); //all messages must have null exceptions @@ -94,24 +94,30 @@ public void ValidateBulkTestData(DatabaseType dbType, bool testCancellingValidat //get the results now var results = dqeRepository.GetMostRecentEvaluationFor(testData.catalogue); - Assert.IsNotNull(results); + Assert.That(results, Is.Not.Null); - //the sum of all consequences across all data load run ids should be the record count - Assert.AreEqual(10000, results.RowStates.Sum(r => r.Missing + r.Invalid + r.Wrong + r.Correct)); + Assert.Multiple(() => + { + //the sum of all consequences across all data load run ids should be the record count + Assert.That(results.RowStates.Sum(r => r.Missing + r.Invalid + r.Wrong + r.Correct), Is.EqualTo(10000)); - //there should be at least 5 data load run ids (should be around 12 actually - see BulkTestData but theoretically everyone could magically - all 10,000 into 5 decades - or even less but those statistics must be astronomical) - Assert.GreaterOrEqual(results.RowStates.Length, 5); + //there should be at least 5 data load run ids (should be around 12 actually - see BulkTestData but theoretically everyone could magically - all 10,000 into 5 decades - or even less but those statistics must be astronomical) + Assert.That(results.RowStates, Has.Length.GreaterThanOrEqualTo(5)); - //there should be lots of column results too - Assert.GreaterOrEqual(results.ColumnStates.Length, 5); + //there should be lots of column results too + Assert.That(results.ColumnStates, Has.Length.GreaterThanOrEqualTo(5)); + }); //Did it log? var logManager = new LogManager(CatalogueRepository.GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID)); var log = logManager.GetArchivalDataLoadInfos("DQE").FirstOrDefault(); - Assert.IsNotNull(log); - Assert.GreaterOrEqual(log.StartTime, startTime); - Assert.AreEqual(0, log.Errors.Count); - Assert.AreEqual(numberOfRecordsToGenerate, log.TableLoadInfos.Single().Inserts); + Assert.That(log, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(log.StartTime, Is.GreaterThanOrEqualTo(startTime)); + Assert.That(log.Errors, Is.Empty); + Assert.That(log.TableLoadInfos.Single().Inserts, Is.EqualTo(numberOfRecordsToGenerate)); + }); testData.DeleteCatalogue(); } @@ -126,7 +132,7 @@ public void SupportsValidation_NoLoggingServer() var before = defaults.GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID); //cannot run test because it didn't have a value to clear! - Assert.IsNotNull(before); + Assert.That(before, Is.Not.Null); //clear the default value defaults.ClearDefault(PermissableDefaults.LiveLoggingServer_ID); @@ -136,10 +142,8 @@ public void SupportsValidation_NoLoggingServer() var report = new CatalogueConstraintReport(_catalogue, SpecialFieldNames.DataLoadRunID); var e = Assert.Throws(() => report.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.IsTrue( - e?.Message.StartsWith( - "Failed to setup logging of DQE runs") - ); + Assert.That( + e?.Message, Does.StartWith("Failed to setup logging of DQE runs")); } finally { @@ -154,7 +158,7 @@ public void SupportsValidation_NoDQE() var before = defaults.GetDefaultFor(PermissableDefaults.DQE); //cannot run test because it didn't have a value to clear! - Assert.IsNotNull(before); + Assert.That(before, Is.Not.Null); //clear the default value defaults.ClearDefault(PermissableDefaults.DQE); @@ -164,10 +168,8 @@ public void SupportsValidation_NoDQE() var report = new CatalogueConstraintReport(_catalogue, SpecialFieldNames.DataLoadRunID); var e = Assert.Throws(() => report.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.IsTrue( - e?.Message.StartsWith( - "Failed to create DQE Repository, possibly there is no DataQualityEngine Reporting Server (ExternalDatabaseServer). You will need to create/set one in CatalogueManager") - ); + Assert.That( + e?.Message, Does.StartWith("Failed to create DQE Repository, possibly there is no DataQualityEngine Reporting Server (ExternalDatabaseServer). You will need to create/set one in CatalogueManager")); } finally { @@ -183,10 +185,10 @@ public void SupportsValidation_NoValidatorXML() _catalogue.ValidatorXML = null; //it has no validator XML currently - Assert.IsFalse(report.CatalogueSupportsReport(_catalogue)); + Assert.That(report.CatalogueSupportsReport(_catalogue), Is.False); var ex = Assert.Throws(() => report.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.Contains("There is no ValidatorXML specified for the Catalogue TestTable", ex.Message); + Assert.That(ex.Message, Does.Contain("There is no ValidatorXML specified for the Catalogue TestTable")); } [Test] @@ -196,11 +198,10 @@ public void SupportsValidation_BadXML() _catalogue.ValidatorXML = "fish"; //it has no validator XML currently - Assert.IsFalse(report.CatalogueSupportsReport(_catalogue)); + Assert.That(report.CatalogueSupportsReport(_catalogue), Is.False); var ex = Assert.Throws(() => report.Check(ThrowImmediatelyCheckNotifier.Quiet)); - StringAssert.Contains("ValidatorXML for Catalogue TestTable could not be deserialized into a Validator", - ex.Message); + Assert.That(ex.Message, Does.Contain("ValidatorXML for Catalogue TestTable could not be deserialized into a Validator")); } [Test] @@ -210,11 +211,10 @@ public void SupportsValidation_MadeUpColumnName() _catalogue.ValidatorXML = dodgyColumnXML; //it has no validator XML currently - Assert.IsFalse(report.CatalogueSupportsReport(_catalogue)); + Assert.That(report.CatalogueSupportsReport(_catalogue), Is.False); var ex = Assert.Throws(() => report.Check(ThrowImmediatelyCheckNotifier.Quiet)); - Assert.AreEqual("Could not find a column in the extraction SQL that would match TargetProperty chi", - ex.Message); + Assert.That(ex.Message, Is.EqualTo("Could not find a column in the extraction SQL that would match TargetProperty chi")); } [Test] @@ -232,15 +232,16 @@ public void SupportsValidation_GoodButNoDataLoadRunID() var notifier = new ToMemoryCheckNotifier(); report.Check(notifier); - Assert.AreEqual(CheckResult.Warning, notifier.GetWorst()); - Assert.Contains("Found column in query builder columns which matches TargetProperty Name", - notifier.Messages.Select(m => m.Message).ToArray()); + Assert.Multiple(() => + { + Assert.That(notifier.GetWorst(), Is.EqualTo(CheckResult.Warning)); + Assert.That(notifier.Messages.Select(m => m.Message).ToArray(), Does.Contain("Found column in query builder columns which matches TargetProperty Name")); - Assert.IsTrue(report.CatalogueSupportsReport(_catalogue)); + Assert.That(report.CatalogueSupportsReport(_catalogue)); + }); var ex = Assert.Throws(() => report.Check(ThrowImmediatelyCheckNotifier.QuietPicky)); - Assert.IsTrue(ex.Message == - "Did not find ExtractionInformation for a column called hic_dataLoadRunID, this will prevent you from viewing the resulting report subdivided by data load batch (make sure you have this column and that it is marked as extractable)"); + Assert.That(ex.Message, Is.EqualTo("Did not find ExtractionInformation for a column called hic_dataLoadRunID, this will prevent you from viewing the resulting report subdivided by data load batch (make sure you have this column and that it is marked as extractable)")); } #endregion diff --git a/Rdmp.Core.Tests/DataQualityEngine/DQEGraphAnnotationTests.cs b/Rdmp.Core.Tests/DataQualityEngine/DQEGraphAnnotationTests.cs index b79db929e3..583636ab57 100644 --- a/Rdmp.Core.Tests/DataQualityEngine/DQEGraphAnnotationTests.cs +++ b/Rdmp.Core.Tests/DataQualityEngine/DQEGraphAnnotationTests.cs @@ -29,19 +29,25 @@ public void TestCreatingOne() var annotation = new DQEGraphAnnotation(dqeRepo, 1, 2, 3, 4, "Fishesfly", evaluation, DQEGraphType.TimePeriodicityGraph, "ALL"); - Assert.AreEqual(annotation.StartX, 1); - Assert.AreEqual(annotation.StartY, 2); - Assert.AreEqual(annotation.EndX, 3); - Assert.AreEqual(annotation.EndY, 4); - Assert.AreEqual(annotation.AnnotationIsForGraph, DQEGraphType.TimePeriodicityGraph); + Assert.Multiple(() => + { + Assert.That(annotation.StartX, Is.EqualTo(1)); + Assert.That(annotation.StartY, Is.EqualTo(2)); + Assert.That(annotation.EndX, Is.EqualTo(3)); + Assert.That(annotation.EndY, Is.EqualTo(4)); + Assert.That(annotation.AnnotationIsForGraph, Is.EqualTo(DQEGraphType.TimePeriodicityGraph)); - //should be about 2 milliseconds ago - Assert.IsTrue(annotation.CreationDate <= DateTime.Now.AddSeconds(3)); - //certainly shouldnt be before yesterday! - Assert.IsTrue(annotation.CreationDate > DateTime.Now.AddDays(-1)); + //should be about 2 milliseconds ago + Assert.That(annotation.CreationDate, Is.LessThanOrEqualTo(DateTime.Now.AddSeconds(3))); + }); + Assert.Multiple(() => + { + //certainly shouldn't be before yesterday! + Assert.That(annotation.CreationDate, Is.GreaterThan(DateTime.Now.AddDays(-1))); - //text should match - Assert.AreEqual(annotation.Text, "Fishesfly"); + //text should match + Assert.That(annotation.Text, Is.EqualTo("Fishesfly")); + }); annotation.Text = "flibble"; annotation.SaveToDatabase(); @@ -49,7 +55,7 @@ public void TestCreatingOne() annotation.Text = ""; //new copy is flibble - Assert.AreEqual("flibble", dqeRepo.GetObjectByID(annotation.ID).Text); + Assert.That(dqeRepo.GetObjectByID(annotation.ID).Text, Is.EqualTo("flibble")); annotation.DeleteInDatabase(); } diff --git a/Rdmp.Core.Tests/DataQualityEngine/PeriodicityStateTests.cs b/Rdmp.Core.Tests/DataQualityEngine/PeriodicityStateTests.cs index 24cac6f8b8..4c908dca81 100644 --- a/Rdmp.Core.Tests/DataQualityEngine/PeriodicityStateTests.cs +++ b/Rdmp.Core.Tests/DataQualityEngine/PeriodicityStateTests.cs @@ -26,7 +26,7 @@ public void TestGetPeriodicityForDataTableForEvaluation_EmptyEvaluation(bool piv var dt = PeriodicityState.GetPeriodicityForDataTableForEvaluation(eval, "ALL", pivot); - Assert.IsNull(dt); + Assert.That(dt, Is.Null); } [Test] @@ -40,7 +40,7 @@ public void GetPeriodicityCountsForEvaluation_EmptyEvaluation() var dict = PeriodicityState.GetPeriodicityCountsForEvaluation(eval, true); - Assert.IsNotNull(dict); - Assert.IsEmpty(dict); + Assert.That(dict, Is.Not.Null); + Assert.That(dict, Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Databases/MasterDatabaseScriptExecutorTests.cs b/Rdmp.Core.Tests/Databases/MasterDatabaseScriptExecutorTests.cs index ac3ec7e23b..de6322918b 100644 --- a/Rdmp.Core.Tests/Databases/MasterDatabaseScriptExecutorTests.cs +++ b/Rdmp.Core.Tests/Databases/MasterDatabaseScriptExecutorTests.cs @@ -29,8 +29,7 @@ public void TestCreatingSchemaTwice() var ex = Assert.Throws(() => mds.CreateAndPatchDatabase(new LoggingDatabasePatcher(), new AcceptAllCheckNotifier())); - StringAssert.Contains( - "is already set up as a platform database for another schema (it has the 'ScriptsRun' table)", - ex.InnerException.Message); + Assert.That( + ex.InnerException.Message, Does.Contain("is already set up as a platform database for another schema (it has the 'ScriptsRun' table)")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Databases/Patch68FixNamespacesTest.cs b/Rdmp.Core.Tests/Databases/Patch68FixNamespacesTest.cs index c7ef0feb5a..0e5fc55fb7 100644 --- a/Rdmp.Core.Tests/Databases/Patch68FixNamespacesTest.cs +++ b/Rdmp.Core.Tests/Databases/Patch68FixNamespacesTest.cs @@ -44,8 +44,7 @@ public void TestClassNameRefactoring() var foundNow = Core.Repositories.MEF.GetType(newClass); - Assert.IsNotNull(foundNow, "Patch did not work correctly for Type '{0}' which after renaming became '{1}'", - oldClass, newClass); + Assert.That(foundNow, Is.Not.Null, $"Patch did not work correctly for Type '{oldClass}' which after renaming became '{newClass}'"); } } diff --git a/Rdmp.Core.Tests/DesignPatternTests/DatabaseEntityConventionTests.cs b/Rdmp.Core.Tests/DesignPatternTests/DatabaseEntityConventionTests.cs index e9c812bd95..645357ddf2 100644 --- a/Rdmp.Core.Tests/DesignPatternTests/DatabaseEntityConventionTests.cs +++ b/Rdmp.Core.Tests/DesignPatternTests/DatabaseEntityConventionTests.cs @@ -4,7 +4,6 @@ // RDMP 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 General Public License for more details. // You should have received a copy of the GNU General Public License along with RDMP. If not, see . -using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Rdmp.Core.Curation.Data; @@ -37,6 +36,6 @@ public void AllDatabaseEntitiesHaveTypedIRepository() foreach (var problem in problems) TestContext.Out.WriteLine(problem); - Assert.IsEmpty(problems); + Assert.That(problems, Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/IHasSummaryTests.cs b/Rdmp.Core.Tests/IHasSummaryTests.cs index 9ec6e60dc0..e4f27e6736 100644 --- a/Rdmp.Core.Tests/IHasSummaryTests.cs +++ b/Rdmp.Core.Tests/IHasSummaryTests.cs @@ -19,7 +19,7 @@ public void AllObjects_SupportSummary() try { var text = obj.GetSummary(true, true); - Assert.IsNotNull(text); + Assert.That(text, Is.Not.Null); } catch (Exception ex) { diff --git a/Rdmp.Core.Tests/Logging/ArchivalDataLoadInfoTests.cs b/Rdmp.Core.Tests/Logging/ArchivalDataLoadInfoTests.cs index ae9ee5eb4e..525bcd87b0 100644 --- a/Rdmp.Core.Tests/Logging/ArchivalDataLoadInfoTests.cs +++ b/Rdmp.Core.Tests/Logging/ArchivalDataLoadInfoTests.cs @@ -22,6 +22,6 @@ public void ArchivalDataLoadInfo_ToString() }; // This dle took 2 days, 1 hour, 20 mins and 23 seconds - StringAssert.Contains("(49:20:23)", adi.ToString()); + Assert.That(adi.ToString(), Does.Contain("(49:20:23)")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Logging/FatalErrorLoggingTest.cs b/Rdmp.Core.Tests/Logging/FatalErrorLoggingTest.cs index d864b5ab5b..23e402abb4 100644 --- a/Rdmp.Core.Tests/Logging/FatalErrorLoggingTest.cs +++ b/Rdmp.Core.Tests/Logging/FatalErrorLoggingTest.cs @@ -23,8 +23,11 @@ public void CreateNewDataLoadTask() lm.CreateNewLoggingTaskIfNotExists("Fish"); - Assert.Contains("Fish", lm.ListDataTasks()); - Assert.Contains("Fish", lm.ListDataSets()); + Assert.Multiple(() => + { + Assert.That(lm.ListDataTasks(), Does.Contain("Fish")); + Assert.That(lm.ListDataSets(), Does.Contain("Fish")); + }); lm.CreateNewLoggingTaskIfNotExists("Fish"); lm.CreateNewLoggingTaskIfNotExists("Fish"); @@ -47,7 +50,7 @@ public void FataErrorLoggingTest() d.LogFatalError("HICSSISLibraryTests.FataErrorLoggingTest", "Some terrible event happened"); - Assert.IsTrue(d.IsClosed); + Assert.That(d.IsClosed); } [Test] @@ -71,7 +74,7 @@ public void MD5Test() ds[0].MD5 = hashAsBytes; //MD5 is a property so confirm write and read are the same - and don't bomb - Assert.AreEqual(ds[0].MD5, hashAsBytes); + Assert.That(hashAsBytes, Is.EqualTo(ds[0].MD5)); var d = new DataLoadInfo("Internal", "HICSSISLibraryTests.FatalErrorLoggingTest", "Test case for fatal error generation", diff --git a/Rdmp.Core.Tests/Logging/LogManagerTest.cs b/Rdmp.Core.Tests/Logging/LogManagerTest.cs index 99fd9f1645..aa23f34db8 100644 --- a/Rdmp.Core.Tests/Logging/LogManagerTest.cs +++ b/Rdmp.Core.Tests/Logging/LogManagerTest.cs @@ -6,7 +6,6 @@ using System; using System.Linq; -using System.Threading; using FAnsi.Discovery; using NUnit.Framework; using Rdmp.Core.Logging; @@ -103,19 +102,16 @@ public void TestLastLoadStatusAssemblage() var loadHistoryForTask = lm.GetArchivalDataLoadInfos(_dataLoadTaskName).ToArray(); - Assert.Greater(loadHistoryForTask.Length, 0); //some records + Assert.That(loadHistoryForTask, Is.Not.Empty); //some records - Assert.Greater(loadHistoryForTask.Count(load => load.Errors.Count > 0), 0); //some with some errors - Assert.Greater(loadHistoryForTask.Count(load => load.Progress.Count > 0), 0); //some with some progress - - - Assert.Greater(loadHistoryForTask.Count(load => load.TableLoadInfos.Count == 1), - 0); //some with some table loads + Assert.Multiple(() => + { + Assert.That(loadHistoryForTask.Count(static load => load.Errors.Count > 0), Is.GreaterThan(0)); //some with some errors + Assert.That(loadHistoryForTask.Count(static load => load.Progress.Count > 0), Is.GreaterThan(0)); //some with some progress - Console.WriteLine($"Records fetched:{loadHistoryForTask.Length}"); - Console.WriteLine($"Errors fetched:{loadHistoryForTask.Aggregate(0, (p, c) => p + c.Errors.Count)}"); - Console.WriteLine($"Progress fetched:{loadHistoryForTask.Aggregate(0, (p, c) => p + c.Progress.Count)}"); + Assert.That(loadHistoryForTask.Count(static load => load.TableLoadInfos.Count == 1), Is.GreaterThan(0)); //some with some table loads + }); } [Test] @@ -123,12 +119,12 @@ public void TestLoggingVsDynamicSQLHacker() { CleanupTruncateCommand(); - Assert.AreEqual(0, _logManager.ListDataTasks().Count(t => t.Equals("','') Truncate Table Fishes"))); + Assert.That(_logManager.ListDataTasks().Count(t => t.Equals("','') Truncate Table Fishes")), Is.EqualTo(0)); _logManager.CreateNewLoggingTaskIfNotExists("','') Truncate Table Fishes"); - Assert.AreEqual(1, _logManager.ListDataTasks().Count(t => t.Equals("','') Truncate Table Fishes"))); + Assert.That(_logManager.ListDataTasks().Count(t => t.Equals("','') Truncate Table Fishes")), Is.EqualTo(1)); CleanupTruncateCommand(); - Assert.AreEqual(0, _logManager.ListDataTasks().Count(t => t.Equals("','') Truncate Table Fishes"))); + Assert.That(_logManager.ListDataTasks().Count(t => t.Equals("','') Truncate Table Fishes")), Is.EqualTo(0)); } private void CleanupTruncateCommand() @@ -148,7 +144,7 @@ public void TestLastLoadStatusAssemblage_Top1() var loadHistoryForTask = lm.GetArchivalDataLoadInfos(_dataLoadTaskName).First(); - Assert.Greater(loadHistoryForTask.Progress.Count, 0); //some with some progress + Assert.That(loadHistoryForTask.Progress, Is.Not.Empty); //some with some progress Console.WriteLine($"Errors fetched:{loadHistoryForTask.Errors.Count}"); Console.WriteLine($"Progress fetched:{loadHistoryForTask.Progress.Count}"); @@ -170,7 +166,7 @@ public void TestLastLoadStatusAssemblage_MostRecent() all = all.OrderByDescending(d => d.StartTime).ToArray(); - Assert.AreEqual(mostRecent.StartTime, all[0].StartTime); + Assert.That(all[0].StartTime, Is.EqualTo(mostRecent.StartTime)); } /// @@ -186,17 +182,17 @@ public void TestLogging_CreateTasks_MixedCases() lm.CreateNewLoggingTaskIfNotExists("ff"); - Assert.AreEqual(1, lm.ListDataSets().Count(s => s.Equals("ff", StringComparison.CurrentCultureIgnoreCase))); + Assert.That(lm.ListDataSets().Count(s => s.Equals("ff", StringComparison.CurrentCultureIgnoreCase)), Is.EqualTo(1)); //don't create another one just because it's changed case lm.CreateNewLoggingTaskIfNotExists("FF"); - Assert.AreEqual(1, lm.ListDataSets().Count(s => s.Equals("ff", StringComparison.CurrentCultureIgnoreCase))); + Assert.That(lm.ListDataSets().Count(s => s.Equals("ff", StringComparison.CurrentCultureIgnoreCase)), Is.EqualTo(1)); var dli1 = lm.CreateDataLoadInfo("ff", "tests", "hi there", null, true); var dli2 = lm.CreateDataLoadInfo("FF", "tests", "hi there", null, true); - Assert.AreEqual(1, lm.ListDataSets().Count(s => s.Equals("ff", StringComparison.CurrentCultureIgnoreCase))); + Assert.That(lm.ListDataSets().Count(s => s.Equals("ff", StringComparison.CurrentCultureIgnoreCase)), Is.EqualTo(1)); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -224,15 +220,18 @@ public void LoggingDatabase_TestActuallyCreatingIt(DatabaseType type) var id = dli.ID; var archival = lm.GetArchivalDataLoadInfos("blarg", null, id).Single(); - Assert.AreEqual(500, archival.TableLoadInfos.Single().Inserts); - Assert.AreEqual(0, archival.TableLoadInfos.Single().Updates); - Assert.AreEqual(0, archival.TableLoadInfos.Single().Deletes); - Assert.AreEqual(DateTime.Now.Date, archival.StartTime.Date); - Assert.AreEqual(DateTime.Now.Date, archival.EndTime.Value.Date); - - Assert.AreEqual("it went bad", archival.Errors.Single().Description); - Assert.AreEqual("bad.cs", archival.Errors.Single().Source); - Assert.AreEqual("Wrote some records", archival.Progress.Single().Description); + Assert.Multiple(() => + { + Assert.That(archival.TableLoadInfos.Single().Inserts, Is.EqualTo(500)); + Assert.That(archival.TableLoadInfos.Single().Updates, Is.EqualTo(0)); + Assert.That(archival.TableLoadInfos.Single().Deletes, Is.EqualTo(0)); + Assert.That(archival.StartTime.Date, Is.EqualTo(DateTime.Now.Date)); + Assert.That(archival.EndTime.Value.Date, Is.EqualTo(DateTime.Now.Date)); + + Assert.That(archival.Errors.Single().Description, Is.EqualTo("it went bad")); + Assert.That(archival.Errors.Single().Source, Is.EqualTo("bad.cs")); + Assert.That(archival.Progress.Single().Description, Is.EqualTo("Wrote some records")); + }); var fatal = archival.Errors.Single(); lm.ResolveFatalErrors(new[] { fatal.ID }, DataLoadInfo.FatalErrorStates.Resolved, diff --git a/Rdmp.Core.Tests/Providers/CatalogueProblemProviderTests.cs b/Rdmp.Core.Tests/Providers/CatalogueProblemProviderTests.cs index 595fd04ccb..07fe714660 100644 --- a/Rdmp.Core.Tests/Providers/CatalogueProblemProviderTests.cs +++ b/Rdmp.Core.Tests/Providers/CatalogueProblemProviderTests.cs @@ -35,8 +35,8 @@ public void TestRootOrderCohortContainer_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(container); - Assert.IsNotNull(problem); - Assert.AreEqual("Child order is ambiguous, show the Order column and reorder contents", problem); + Assert.That(problem, Is.Not.Null); + Assert.That(problem, Is.EqualTo("Child order is ambiguous, show the Order column and reorder contents")); } [Test] @@ -50,8 +50,8 @@ public void TestEmptyRootUNIONCohortContainer_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(container); - Assert.IsNotNull(problem); - Assert.AreEqual("You must have at least one element in the root container", problem); + Assert.That(problem, Is.Not.Null); + Assert.That(problem, Is.EqualTo("You must have at least one element in the root container")); } [Test] @@ -65,10 +65,9 @@ public void TestEmptyRootEXCEPTCohortContainer_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(container); - Assert.IsNotNull(problem); - Assert.AreEqual( - "EXCEPT/INTERSECT containers must have at least two elements within. Either Add a Catalogue or Disable/Delete this container if not required", - problem); + Assert.That(problem, Is.Not.Null); + Assert.That( + problem, Is.EqualTo("EXCEPT/INTERSECT containers must have at least two elements within. Either Add a Catalogue or Disable/Delete this container if not required")); } [Test] @@ -82,10 +81,9 @@ public void TestEmptyRootINTERSECTCohortContainer_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(container); - Assert.IsNotNull(problem); - Assert.AreEqual( - "EXCEPT/INTERSECT containers must have at least two elements within. Either Add a Catalogue or Disable/Delete this container if not required", - problem); + Assert.That(problem, Is.Not.Null); + Assert.That( + problem, Is.EqualTo("EXCEPT/INTERSECT containers must have at least two elements within. Either Add a Catalogue or Disable/Delete this container if not required")); } [Test] @@ -101,7 +99,7 @@ public void Test1ChildRootUNIONCohortContainer_IsOk() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(container); - Assert.IsNull(problem); + Assert.That(problem, Is.Null); } [Test] @@ -119,7 +117,7 @@ public void Test2ChildRootUNIONCohortContainer_IsOk() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(container); - Assert.IsNull(problem); + Assert.That(problem, Is.Null); } [Test] @@ -135,10 +133,9 @@ public void Test1ChildRootEXCEPTCohortContainer_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(container); - Assert.IsNotNull(problem); - Assert.AreEqual( - "EXCEPT/INTERSECT containers must have at least two elements within. Either Add a Catalogue or Disable/Delete this container if not required", - problem); + Assert.That(problem, Is.Not.Null); + Assert.That( + problem, Is.EqualTo("EXCEPT/INTERSECT containers must have at least two elements within. Either Add a Catalogue or Disable/Delete this container if not required")); } [Test] @@ -156,7 +153,7 @@ public void Test2ChildRootEXCEPTCohortContainer_IsOk() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(container); - Assert.IsNull(problem); + Assert.That(problem, Is.Null); } [Test] @@ -172,10 +169,9 @@ public void Test1ChildRootINTERSECTCohortContainer_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(container); - Assert.IsNotNull(problem); - Assert.AreEqual( - "EXCEPT/INTERSECT containers must have at least two elements within. Either Add a Catalogue or Disable/Delete this container if not required", - problem); + Assert.That(problem, Is.Not.Null); + Assert.That( + problem, Is.EqualTo("EXCEPT/INTERSECT containers must have at least two elements within. Either Add a Catalogue or Disable/Delete this container if not required")); } [Test] @@ -193,7 +189,7 @@ public void Test2ChildRootINTERSECTCohortContainer_IsOk() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(container); - Assert.IsNull(problem); + Assert.That(problem, Is.Null); } #endregion @@ -212,10 +208,9 @@ public void TestSetContainerUNION_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(childContainer); - Assert.IsNotNull(problem); - Assert.AreEqual( - "SET containers cannot be empty. Either Add a Catalogue or Disable/Delete this container if not required", - problem); + Assert.That(problem, Is.Not.Null); + Assert.That( + problem, Is.EqualTo("SET containers cannot be empty. Either Add a Catalogue or Disable/Delete this container if not required")); } [Test] @@ -232,10 +227,9 @@ public void TestSetContainer1ChildUNION_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(childContainer); - Assert.IsNotNull(problem); - Assert.AreEqual( - "SET containers have no effect if there is only one child within. Either Add a Catalogue or Disable/Delete this container if not required", - problem); + Assert.That(problem, Is.Not.Null); + Assert.That( + problem, Is.EqualTo("SET containers have no effect if there is only one child within. Either Add a Catalogue or Disable/Delete this container if not required")); } [Test] @@ -254,7 +248,7 @@ public void TestSetContainer2ChildUNION_IsOk() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(childContainer); - Assert.IsNull(problem); + Assert.That(problem, Is.Null); } [Test] @@ -269,10 +263,9 @@ public void TestSetContainerEXCEPT_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(childContainer); - Assert.IsNotNull(problem); - Assert.AreEqual( - "SET containers cannot be empty. Either Add a Catalogue or Disable/Delete this container if not required", - problem); + Assert.That(problem, Is.Not.Null); + Assert.That( + problem, Is.EqualTo("SET containers cannot be empty. Either Add a Catalogue or Disable/Delete this container if not required")); } [Test] @@ -289,10 +282,9 @@ public void TestSetContainer1ChildEXCEPT_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(childContainer); - Assert.IsNotNull(problem); - Assert.AreEqual( - "SET containers have no effect if there is only one child within. Either Add a Catalogue or Disable/Delete this container if not required", - problem); + Assert.That(problem, Is.Not.Null); + Assert.That( + problem, Is.EqualTo("SET containers have no effect if there is only one child within. Either Add a Catalogue or Disable/Delete this container if not required")); } [Test] @@ -311,7 +303,7 @@ public void TestSetContainer2ChildEXCEPT_IsOk() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(childContainer); - Assert.IsNull(problem); + Assert.That(problem, Is.Null); } [Test] @@ -326,10 +318,9 @@ public void TestSetContainerINTERSECT_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(childContainer); - Assert.IsNotNull(problem); - Assert.AreEqual( - "SET containers cannot be empty. Either Add a Catalogue or Disable/Delete this container if not required", - problem); + Assert.That(problem, Is.Not.Null); + Assert.That( + problem, Is.EqualTo("SET containers cannot be empty. Either Add a Catalogue or Disable/Delete this container if not required")); } [Test] @@ -346,10 +337,9 @@ public void TestSetContainer1ChildINTERSECT_IsProblem() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(childContainer); - Assert.IsNotNull(problem); - Assert.AreEqual( - "SET containers have no effect if there is only one child within. Either Add a Catalogue or Disable/Delete this container if not required", - problem); + Assert.That(problem, Is.Not.Null); + Assert.That( + problem, Is.EqualTo("SET containers have no effect if there is only one child within. Either Add a Catalogue or Disable/Delete this container if not required")); } [Test] @@ -368,7 +358,7 @@ public void TestSetContainer2ChildINTERSECT_IsOk() pp.RefreshProblems(new CatalogueChildProvider(Repository, null, ThrowImmediatelyCheckNotifier.Quiet, null)); var problem = pp.DescribeProblem(childContainer); - Assert.IsNull(problem); + Assert.That(problem, Is.Null); } #endregion @@ -391,25 +381,27 @@ public void MixedCollationIsAProblemForJoinInfos_WhenNoExplicitCollation(string var pp = new CatalogueProblemProvider(); var childProvider = GetActivator().CoreChildProvider; - Assert.IsFalse(pp.HasProblem(ci1), "Should not be problem because no collations are declared"); + Assert.That(pp.HasProblem(ci1), Is.False, "Should not be problem because no collations are declared"); pp.RefreshProblems(childProvider); - Assert.IsFalse(pp.HasProblem(ci1), "Should not be problem because no collations are declared"); + Assert.That(pp.HasProblem(ci1), Is.False, "Should not be problem because no collations are declared"); pp.RefreshProblems(childProvider); ci1.ColumnInfo.Collation = "fishy"; ci2.ColumnInfo.Collation = "fishy"; pp.RefreshProblems(childProvider); - Assert.IsFalse(pp.HasProblem(ci1), "Should not be problem because collations are the same"); + Assert.That(pp.HasProblem(ci1), Is.False, "Should not be problem because collations are the same"); ci1.ColumnInfo.Collation = "fishy"; ci2.ColumnInfo.Collation = "splishy"; pp.RefreshProblems(childProvider); - Assert.IsTrue(pp.HasProblem(ci1)); - Assert.AreEqual("Columns in joins declared on this column have mismatched collations ( My_Col = My_Col)", - pp.DescribeProblem(ci1)); + Assert.Multiple(() => + { + Assert.That(pp.HasProblem(ci1)); + Assert.That(pp.DescribeProblem(ci1), Is.EqualTo("Columns in joins declared on this column have mismatched collations ( My_Col = My_Col)")); + }); } [Test] @@ -431,13 +423,13 @@ public void MixedCollationIsAProblemForJoinInfos_ExplicitCollation() var childProvider = GetActivator().CoreChildProvider; - Assert.IsFalse(pp.HasProblem(ci1), "Should not be problem because collations are the same"); + Assert.That(pp.HasProblem(ci1), Is.False, "Should not be problem because collations are the same"); ci1.ColumnInfo.Collation = "fishy"; ci2.ColumnInfo.Collation = "splishy"; pp.RefreshProblems(childProvider); - Assert.IsFalse(pp.HasProblem(ci1), + Assert.That(pp.HasProblem(ci1), Is.False, "Should not be problem because JoinInfo explicitly states a resolution collation"); } @@ -459,9 +451,9 @@ public void TestParameterIsDate(string val, bool expectProblem) var problem = pp.DescribeProblem(param); if (expectProblem) - Assert.AreEqual("Parameter value looks like a date but is not surrounded by quotes", problem); + Assert.That(problem, Is.EqualTo("Parameter value looks like a date but is not surrounded by quotes")); else - Assert.IsNull(problem); + Assert.That(problem, Is.Null); } #endregion diff --git a/Rdmp.Core.Tests/Providers/RowVerTest.cs b/Rdmp.Core.Tests/Providers/RowVerTest.cs index 28d57f5bc0..89d1d4f6ce 100644 --- a/Rdmp.Core.Tests/Providers/RowVerTest.cs +++ b/Rdmp.Core.Tests/Providers/RowVerTest.cs @@ -24,9 +24,9 @@ public void Test_RowVer() var cata = new Catalogue(CatalogueRepository, "FFFF"); //When we get all the Catalogues we should include cata - Assert.Contains(cata, CatalogueRepository.GetAllObjects()); - Assert.AreEqual(cata, CatalogueRepository.GetAllObjects()[0]); - Assert.AreNotSame(cata, CatalogueRepository.GetAllObjects()[0]); + Assert.That(CatalogueRepository.GetAllObjects(), Does.Contain(cata)); + Assert.That(CatalogueRepository.GetAllObjects()[0], Is.EqualTo(cata)); + Assert.That(CatalogueRepository.GetAllObjects()[0], Is.Not.SameAs(cata)); //create a cache var rowVerCache = new RowVerCache(CatalogueTableRepository); @@ -35,10 +35,10 @@ public void Test_RowVer() cata = rowVerCache.GetAllObjects()[0]; //should return the same instance - Assert.AreSame(cata, rowVerCache.GetAllObjects()[0]); + Assert.That(rowVerCache.GetAllObjects()[0], Is.SameAs(cata)); cata.DeleteInDatabase(); - Assert.IsEmpty(rowVerCache.GetAllObjects()); + Assert.That(rowVerCache.GetAllObjects(), Is.Empty); //create some catalogues new Catalogue(CatalogueRepository, "1"); @@ -52,25 +52,31 @@ public void Test_RowVer() var cata2 = new Catalogue(CatalogueRepository, "dddd"); //fresh fetch for this - Assert.Contains(cata2, rowVerCache.GetAllObjects()); - Assert.IsFalse(rowVerCache.GetAllObjects().Contains(cata)); + Assert.That(rowVerCache.GetAllObjects(), Does.Contain(cata2)); + Assert.That(rowVerCache.GetAllObjects(), Does.Not.Contain(cata)); - //change a value in the background but first make sure that what the cache has is a Equal but not reference to cata2 - Assert.IsFalse(rowVerCache.GetAllObjects().Any(o => ReferenceEquals(o, cata2))); - Assert.IsTrue(rowVerCache.GetAllObjects().Any(o => Equals(o, cata2))); + Assert.Multiple(() => + { + //change a value in the background but first make sure that what the cache has is a Equal but not reference to cata2 + Assert.That(rowVerCache.GetAllObjects().Any(o => ReferenceEquals(o, cata2)), Is.False); + Assert.That(rowVerCache.GetAllObjects().Any(o => Equals(o, cata2))); + }); cata2.Name = "boom"; cata2.SaveToDatabase(); - Assert.AreEqual(1, rowVerCache.GetAllObjects().Count(c => c.Name.Equals("boom"))); + Assert.That(rowVerCache.GetAllObjects().Count(static c => c.Name.Equals("boom")), Is.EqualTo(1)); cata2.Name = "vroom"; cata2.SaveToDatabase(); - Assert.AreEqual(1, rowVerCache.GetAllObjects().Count(c => c.Name.Equals("vroom"))); + Assert.That(rowVerCache.GetAllObjects().Count(c => c.Name.Equals("vroom")), Is.EqualTo(1)); - Assert.AreEqual(1, rowVerCache.GetAllObjects().Count(c => c.Name.Equals("vroom"))); + Assert.Multiple(() => + { + Assert.That(rowVerCache.GetAllObjects().Count(c => c.Name.Equals("vroom")), Is.EqualTo(1)); - Assert.IsFalse(rowVerCache.Broken); + Assert.That(rowVerCache.Broken, Is.False); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Providers/SearchablesMatchScorerTests.cs b/Rdmp.Core.Tests/Providers/SearchablesMatchScorerTests.cs index 98950a2e6e..b1e5c458ce 100644 --- a/Rdmp.Core.Tests/Providers/SearchablesMatchScorerTests.cs +++ b/Rdmp.Core.Tests/Providers/SearchablesMatchScorerTests.cs @@ -39,12 +39,15 @@ public void Find_ExactMatch_ScoresHigher() var cataScore = scores.Single(d => Equals(d.Key.Key, cata)); var projScore = scores.Single(d => Equals(d.Key.Key, proj)); - // Both score because they have the text FF - Assert.Greater(cataScore.Value, 0); - Assert.Greater(projScore.Value, 0); + Assert.Multiple(() => + { + // Both score because they have the text FF + Assert.That(cataScore.Value, Is.GreaterThan(0)); + Assert.That(projScore.Value, Is.GreaterThan(0)); + }); // Catalogue scores higher because it is an exact match to the name - Assert.Greater(cataScore.Value, projScore.Value); + Assert.That(cataScore.Value, Is.GreaterThan(projScore.Value)); } @@ -71,7 +74,7 @@ public void Find_CohortAggregateContainer_ByTypeName(bool userSetting) new List { typeof(CohortAggregateContainer) }, CancellationToken.None); var score = scores.Single(d => Equals(d.Key.Key, container)); - Assert.Greater(score.Value, 0); + Assert.That(score.Value, Is.GreaterThan(0)); } /// @@ -103,9 +106,9 @@ public void Find_CohortAggregateContainer_ByFreeText(bool userSetting) if (userSetting) // although the text appears in the search they are not doing it by exact type name and their settings // mean they don't want to see these objects by default. - Assert.AreEqual(0, score.Value); + Assert.That(score.Value, Is.EqualTo(0)); else - Assert.Greater(score.Value, 0); + Assert.That(score.Value, Is.GreaterThan(0)); } [TestCase(true, true, true)] @@ -220,10 +223,10 @@ private void TestScoringFlag(Action setter, bool var score = scores.Single(d => Equals(d.Key.Key, c)); if (expectedResult) - Assert.Greater(score.Value, 0); + Assert.That(score.Value, Is.GreaterThan(0)); else // score 0 and don't be included in results - Assert.AreEqual(0, score.Value); + Assert.That(score.Value, Is.EqualTo(0)); // Cleanup test foreach (var d in Repository.GetAllObjects()) d.DeleteInDatabase(); diff --git a/Rdmp.Core.Tests/QueryCaching/CachedAggregateConfigurationResultsManagerTests.cs b/Rdmp.Core.Tests/QueryCaching/CachedAggregateConfigurationResultsManagerTests.cs index 3486285cc7..0b8f45cca7 100644 --- a/Rdmp.Core.Tests/QueryCaching/CachedAggregateConfigurationResultsManagerTests.cs +++ b/Rdmp.Core.Tests/QueryCaching/CachedAggregateConfigurationResultsManagerTests.cs @@ -64,18 +64,17 @@ public void CommitResults_CreatesTablessuccessfully() _manager.GetLatestResultsTableUnsafe(_config, AggregateOperation.IndexedExtractionIdentifierList); - Assert.AreEqual($"IndexedExtractionIdentifierList_AggregateConfiguration{_config.ID}", - resultsTableName.GetRuntimeName()); + Assert.That(resultsTableName.GetRuntimeName(), Is.EqualTo($"IndexedExtractionIdentifierList_AggregateConfiguration{_config.ID}")); var table = DataAccessPortal .ExpectDatabase(QueryCachingDatabaseServer, DataAccessContext.InternalDataProcessing) .ExpectTable(resultsTableName.GetRuntimeName()); - Assert.IsTrue(table.Exists()); + Assert.That(table.Exists()); var col = table.DiscoverColumn("MyCol"); - Assert.IsNotNull(col); - Assert.AreEqual("varchar(10)", col.DataType.SQLType); + Assert.That(col, Is.Not.Null); + Assert.That(col.DataType.SQLType, Is.EqualTo("varchar(10)")); using (var con = DataAccessPortal .ExpectServer(QueryCachingDatabaseServer, DataAccessContext.InternalDataProcessing).GetConnection()) @@ -87,15 +86,18 @@ public void CommitResults_CreatesTablessuccessfully() (SqlConnection)con); da.Fill(dt2); - Assert.AreEqual(dt.Rows.Count, dt2.Rows.Count); + Assert.That(dt2.Rows, Has.Count.EqualTo(dt.Rows.Count)); con.Close(); } - Assert.IsNotNull(_manager.GetLatestResultsTable(_config, AggregateOperation.IndexedExtractionIdentifierList, - SomeComplexBitOfSqlCode)); - Assert.IsNull(_manager.GetLatestResultsTable(_config, AggregateOperation.IndexedExtractionIdentifierList, - "select name,height,scalecount from fish")); + Assert.Multiple(() => + { + Assert.That(_manager.GetLatestResultsTable(_config, AggregateOperation.IndexedExtractionIdentifierList, + SomeComplexBitOfSqlCode), Is.Not.Null); + Assert.That(_manager.GetLatestResultsTable(_config, AggregateOperation.IndexedExtractionIdentifierList, + "select name,height,scalecount from fish"), Is.Null); + }); } @@ -110,7 +112,7 @@ public void Throws_BecauseItHasDuplicates() var ex = Assert.Throws(() => _manager.CommitResults(new CacheCommitIdentifierList(_config, "select * from fish", dt, _myColSpecification, 30))); - Assert.IsTrue(ex.Message.Contains("primary key")); + Assert.That(ex.Message, Does.Contain("primary key")); } [Test] @@ -129,7 +131,7 @@ public void Throws_BecauseInceptionCaching() var ex = Assert.Throws(() => _manager.CommitResults(new CacheCommitIdentifierList(_config, sql, dt, _myColSpecification, 30))); - Assert.IsTrue(ex.Message.Contains("This is referred to as Inception Caching and isn't allowed")); + Assert.That(ex.Message, Does.Contain("This is referred to as Inception Caching and isn't allowed")); } [Test] @@ -159,9 +161,12 @@ public void NullsAreDropped() da.Fill(dt2); } - Assert.AreEqual(2, dt2.Rows.Count); - Assert.IsTrue(dt2.Rows.Cast().Any(r => (string)r[0] == "0101010101")); - Assert.IsTrue(dt2.Rows.Cast().Any(r => (string)r[0] == "0101010102")); + Assert.That(dt2.Rows, Has.Count.EqualTo(2)); + Assert.Multiple(() => + { + Assert.That(dt2.Rows.Cast().Any(r => (string)r[0] == "0101010101")); + Assert.That(dt2.Rows.Cast().Any(r => (string)r[0] == "0101010102")); + }); } private const string SomeComplexBitOfSqlCode = diff --git a/Rdmp.Core.Tests/QueryCaching/DataAccessPortalCollectionTests.cs b/Rdmp.Core.Tests/QueryCaching/DataAccessPortalCollectionTests.cs index aaf6e043bb..ccc9d4a864 100644 --- a/Rdmp.Core.Tests/QueryCaching/DataAccessPortalCollectionTests.cs +++ b/Rdmp.Core.Tests/QueryCaching/DataAccessPortalCollectionTests.cs @@ -38,7 +38,7 @@ public void TestOneServer_CountCorrect(bool singleServer) _dap.Server.Returns("loco"); _dap.DatabaseType.Returns(DatabaseType.Oracle); collection.Add(_dap); - Assert.AreEqual(1, collection.Points.Count); + Assert.That(collection.Points, Has.Count.EqualTo(1)); } [Test] @@ -47,22 +47,22 @@ public void TestTwo_SameServer_PersistDatabase() var collection = new DataAccessPointCollection(true); var _dap = Substitute.For(); - _dap.Server = ("loco"); - _dap.Database = ("B"); - _dap.DatabaseType = (DatabaseType.Oracle); + _dap.Server = "loco"; + _dap.Database = "B"; + _dap.DatabaseType = DatabaseType.Oracle; var _dap0 = Substitute.For(); - _dap0.Server = ("loco"); - _dap0.Database = ("A"); - _dap0.DatabaseType = (DatabaseType.Oracle); + _dap0.Server = "loco"; + _dap0.Database = "A"; + _dap0.DatabaseType = DatabaseType.Oracle; collection.Add(_dap0); collection.Add(_dap); - Assert.AreEqual(2, collection.Points.Count); + Assert.That(collection.Points, Has.Count.EqualTo(2)); var db = collection.GetDistinctServer().GetCurrentDatabase(); - Assert.IsNull(db); + Assert.That(db, Is.Null); } [Test] @@ -88,11 +88,11 @@ public void TestTwo_SameServer_NoCredentials() collection.Add(_dap0); - Assert.AreEqual(2, collection.Points.Count); + Assert.That(collection.Points, Has.Count.EqualTo(2)); //they both go to loco server so the single server should specify loco but no clear db var db = collection.GetDistinctServer().GetCurrentDatabase(); - Assert.IsNull(db); + Assert.That(db, Is.Null); } [Test] @@ -119,7 +119,7 @@ public void TestTwo_SameServer_SameCredentials() collection.Add(_dap0); - Assert.AreEqual(2, collection.Points.Count); + Assert.That(collection.Points, Has.Count.EqualTo(2)); } [Test] @@ -149,10 +149,12 @@ public void TestTwo_SameServer_OnlyOneUsesCredentials() collection.Add(_dap0) ); - //should be relevant error and it shouldn't have been added - StringAssert.Contains("ollection could not agree on a single Username", - ex.InnerException.Message); - Assert.AreEqual(1, collection.Points.Count); + Assert.Multiple(() => + { + //should be relevant error and it shouldn't have been added + Assert.That(ex.InnerException.Message, Does.Contain("ollection could not agree on a single Username")); + Assert.That(collection.Points, Has.Count.EqualTo(1)); + }); } [Test] @@ -187,10 +189,12 @@ public void TestTwo_SameServer_DifferentUsernames() collection.Add(_dap0) ); - //should be relevant error and it shouldn't have been added - StringAssert.Contains("could not agree on a single Username to use to access the data under", - ex.InnerException.Message); - Assert.AreEqual(1, collection.Points.Count); + Assert.Multiple(() => + { + //should be relevant error and it shouldn't have been added + Assert.That(ex.InnerException.Message, Does.Contain("could not agree on a single Username to use to access the data under")); + Assert.That(collection.Points, Has.Count.EqualTo(1)); + }); } [Test] @@ -225,10 +229,12 @@ public void TestTwo_SameServer_DifferentPasswords() collection.Add(_dap0) ); - //should be relevant error and it shouldn't have been added - StringAssert.Contains("collection could not agree on a single Password to use to access the data under", - ex.InnerException.Message); - Assert.AreEqual(1, collection.Points.Count); + Assert.Multiple(() => + { + //should be relevant error and it shouldn't have been added + Assert.That(ex.InnerException.Message, Does.Contain("collection could not agree on a single Password to use to access the data under")); + Assert.That(collection.Points, Has.Count.EqualTo(1)); + }); } [Test] @@ -250,9 +256,12 @@ public void TestTwo_DifferentServer() collection.Add(_dap0) ); - //should be relevant error and it shouldn't have been added - StringAssert.Contains("There was a mismatch in server names for data access points", ex.InnerException.Message); - Assert.AreEqual(1, collection.Points.Count); + Assert.Multiple(() => + { + //should be relevant error and it shouldn't have been added + Assert.That(ex.InnerException.Message, Does.Contain("There was a mismatch in server names for data access points")); + Assert.That(collection.Points, Has.Count.EqualTo(1)); + }); } @@ -275,8 +284,11 @@ public void TestTwo_DifferentDatabaseType() collection.Add(_dap) ); - //should be relevant error and it shouldn't have been added - StringAssert.Contains("There was a mismatch on DatabaseType for data access points", ex.InnerException.Message); - Assert.AreEqual(1, collection.Points.Count); + Assert.Multiple(() => + { + //should be relevant error and it shouldn't have been added + Assert.That(ex.InnerException.Message, Does.Contain("There was a mismatch on DatabaseType for data access points")); + Assert.That(collection.Points, Has.Count.EqualTo(1)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/QueryCaching/ExtractableAggregateCachingTests.cs b/Rdmp.Core.Tests/QueryCaching/ExtractableAggregateCachingTests.cs index f34dcf4a9c..eede6759cd 100644 --- a/Rdmp.Core.Tests/QueryCaching/ExtractableAggregateCachingTests.cs +++ b/Rdmp.Core.Tests/QueryCaching/ExtractableAggregateCachingTests.cs @@ -59,8 +59,7 @@ public void BasicCase() new DataTable(), 30))); - Assert.IsTrue(ex.Message.StartsWith( - "The DataTable that you claimed was an ExtractableAggregateResults had zero columns and therefore cannot be cached")); + Assert.That(ex.Message, Does.StartWith("The DataTable that you claimed was an ExtractableAggregateResults had zero columns and therefore cannot be cached")); var dt = new DataTable(); dt.Columns.Add("Col1"); @@ -70,9 +69,8 @@ public void BasicCase() _manager.CommitResults( new CacheCommitExtractableAggregate(_config, "I've got a lovely bunch of coconuts", dt, 30))); - Assert.IsTrue( - ex2.Message.StartsWith( - "Aggregate ExtractableAggregateCachingTests is not marked as IsExtractable therefore cannot be cached")); + Assert.That( + ex2.Message, Does.StartWith("Aggregate ExtractableAggregateCachingTests is not marked as IsExtractable therefore cannot be cached")); _config.IsExtractable = true; @@ -90,9 +88,8 @@ public void BasicCase() _manager.CommitResults( new CacheCommitExtractableAggregate(_config, "I've got a lovely bunch of coconuts", dt, 30))); - Assert.IsTrue( - ex3.Message.StartsWith( - "Aggregate ExtractableAggregateCachingTests contains dimensions marked as IsExtractionIdentifier or HashOnDataRelease (Col1)")); + Assert.That( + ex3.Message, Does.StartWith("Aggregate ExtractableAggregateCachingTests contains dimensions marked as IsExtractionIdentifier or HashOnDataRelease (Col1)")); _extractionInformation.IsExtractionIdentifier = false; _extractionInformation.SaveToDatabase(); @@ -112,7 +109,10 @@ public void BasicCase() con.Open(); using var cmd = DatabaseCommandHelper.GetCommand($"Select * from {table.GetFullyQualifiedName()}", con); using var r = cmd.ExecuteReader(); - Assert.IsTrue(r.Read()); - Assert.AreEqual("fishy!", r["Col1"]); + Assert.Multiple(() => + { + Assert.That(r.Read()); + Assert.That(r["Col1"], Is.EqualTo("fishy!")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/QueryCaching/QueryCachingCrossServerTests.cs b/Rdmp.Core.Tests/QueryCaching/QueryCachingCrossServerTests.cs index 3362d7af86..8243b7c9e9 100644 --- a/Rdmp.Core.Tests/QueryCaching/QueryCachingCrossServerTests.cs +++ b/Rdmp.Core.Tests/QueryCaching/QueryCachingCrossServerTests.cs @@ -91,7 +91,7 @@ public void Test_SingleServer_WithOneParameter(DatabaseType dbType, bool usePara AssertNoErrors(compiler); - Assert.IsTrue( + Assert.That( compiler.Tasks.Where(t => t.Key is AggregationContainerTask) .Any(t => t.Key.GetCachedQueryUseCount().Equals("1/1")), "Expected UNION container to use the cache"); } @@ -303,18 +303,18 @@ public void Test_EXCEPT_TwoAggregates(DatabaseType dbType) AssertNoErrors(compiler); - - Assert.AreEqual( - compiler.Tasks.Single(static t => t.Value is { IsResultsForRootContainer: true }).Key.FinalRowCount, 0); - Assert.Greater( - compiler.Tasks.Single(t => t.Key is AggregationTask at && at.Aggregate.Equals(ac1)).Key.FinalRowCount, - 0); //both ac should have the same total - Assert.Greater( - compiler.Tasks.Single(t => t.Key is AggregationTask at && at.Aggregate.Equals(ac2)).Key.FinalRowCount, - 0); // that is not 0 - - Assert.IsTrue(compiler.Tasks.Any(static t => t.Key.GetCachedQueryUseCount().Equals("2/2")), - "Expected EXCEPT container to use the cache"); + Assert.Multiple(() => + { + Assert.That( + compiler.Tasks.Single(static t => t.Value is { IsResultsForRootContainer: true }).Key.FinalRowCount, Is.EqualTo(0)); + Assert.That( + compiler.Tasks.Single(t => t.Key is AggregationTask at && at.Aggregate.Equals(ac1)).Key.FinalRowCount, Is.GreaterThan(0)); //both ac should have the same total + Assert.That( + compiler.Tasks.Single(t => t.Key is AggregationTask at && at.Aggregate.Equals(ac2)).Key.FinalRowCount, Is.GreaterThan(0)); // that is not 0 + + Assert.That(compiler.Tasks.Any(static t => t.Key.GetCachedQueryUseCount().Equals("2/2")), + "Expected EXCEPT container to use the cache"); + }); } /// @@ -375,10 +375,10 @@ public void Join_PatientIndexTable_OptionalCacheOnSameServer(DatabaseType dbType AssertNoErrors(compiler); if (createQueryCache) - Assert.IsTrue(compiler.Tasks.Any(t => t.Key.GetCachedQueryUseCount().Equals("1/1")), + Assert.That(compiler.Tasks.Any(t => t.Key.GetCachedQueryUseCount().Equals("1/1")), "Expected cache to be used for the joinable"); else - Assert.IsTrue(compiler.Tasks.Any(t => t.Key.GetCachedQueryUseCount().Equals("0/1")), + Assert.That(compiler.Tasks.Any(t => t.Key.GetCachedQueryUseCount().Equals("0/1")), "Did not create cache so expected cache usage to be 0"); } @@ -434,7 +434,7 @@ public void Join_PatientIndexTable_DoNotUseCacheOnDifferentServer(DatabaseType d AssertNoErrors(compiler); - Assert.IsTrue(compiler.Tasks.Any(t => t.Key.GetCachedQueryUseCount().Equals("1/1")), + Assert.That(compiler.Tasks.Any(t => t.Key.GetCachedQueryUseCount().Equals("1/1")), "Expected cache to be used only for the final UNION"); } @@ -486,7 +486,7 @@ public void Join_PatientIndexTable_NotOnCacheServer() AssertNoErrors(compiler); - Assert.IsTrue(compiler.Tasks.Any(t => t.Key.GetCachedQueryUseCount().Equals("1/1")), + Assert.That(compiler.Tasks.Any(t => t.Key.GetCachedQueryUseCount().Equals("1/1")), "Expected cache to be used only for the final UNION"); } @@ -543,10 +543,12 @@ public void Join_PatientIndexTable_ThreeServers() var hospitalAdmissionsTask = compiler.Tasks.Keys.OfType() .Single(t => t.Aggregate.Equals(hospitalAdmissions)); - Assert.AreEqual(CompilationState.Crashed, hospitalAdmissionsTask.State); + Assert.Multiple(() => + { + Assert.That(hospitalAdmissionsTask.State, Is.EqualTo(CompilationState.Crashed)); - StringAssert.Contains("is not fully cached and CacheUsageDecision is MustUse", - hospitalAdmissionsTask.CrashMessage.ToString()); + Assert.That(hospitalAdmissionsTask.CrashMessage.ToString(), Does.Contain("is not fully cached and CacheUsageDecision is MustUse")); + }); } [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))] @@ -607,7 +609,7 @@ public void Join_PatientIndexTable_ThenShipToCacheForSets(DatabaseType dbType) AssertNoErrors(compiler); - Assert.IsTrue(compiler.Tasks.Any(t => t.Key.GetCachedQueryUseCount().Equals("2/2")), + Assert.That(compiler.Tasks.Any(t => t.Key.GetCachedQueryUseCount().Equals("2/2")), "Expected cache to be used for both top level operations in the EXCEPT"); } @@ -814,7 +816,7 @@ private AggregateConfiguration SetupAggregateConfigurationWithFilter(DiscoveredD /// private static void AssertNoErrors(CohortCompiler compiler) { - Assert.IsNotEmpty(compiler.Tasks); + Assert.That(compiler.Tasks, Is.Not.Empty); TestContext.WriteLine($"| Task | Type | State | Error | RowCount | CacheUse |"); @@ -824,7 +826,7 @@ private static void AssertNoErrors(CohortCompiler compiler) TestContext.WriteLine( $"{i++} - {kvp.ToString()} | {kvp.GetType()} | {kvp.State} | {kvp.CrashMessage} | {kvp.FinalRowCount} | {kvp.GetCachedQueryUseCount()}"); - Assert.IsTrue(compiler.Tasks.All(static t => t.Key.State == CompilationState.Finished), + Assert.That(compiler.Tasks.All(static t => t.Key.State == CompilationState.Finished), "Expected all tasks to finish without error"); } @@ -836,8 +838,11 @@ private static void AssertCrashed(CohortCompiler compiler, AggregateConfiguratio string expectedErrorMessageToContain) { var acResult = compiler.Tasks.Single(t => t.Key is AggregationTask a && a.Aggregate.Equals(task)); - Assert.AreEqual(CompilationState.Crashed, acResult.Key.State); - StringAssert.Contains(expectedErrorMessageToContain, acResult.Key.CrashMessage.Message); + Assert.Multiple(() => + { + Assert.That(acResult.Key.State, Is.EqualTo(CompilationState.Crashed)); + Assert.That(acResult.Key.CrashMessage.Message, Does.Contain(expectedErrorMessageToContain)); + }); } /// @@ -855,10 +860,10 @@ private static void AssertNoErrors(CohortCompiler compiler, AggregateConfigurati Console.WriteLine($"Build Log For '{task}':"); Console.WriteLine(acResult.Key.Log); - Assert.AreEqual(CompilationState.Finished, acResult.Key.State); + Assert.That(acResult.Key.State, Is.EqualTo(CompilationState.Finished)); foreach (var s in expectedSqlBits) - StringAssert.IsMatch(s, acResult.Value.CountSQL); + Assert.That(acResult.Value.CountSQL, Does.Match(s)); } /// @@ -872,10 +877,10 @@ private static void AssertNoErrors(CohortCompiler compiler, CohortAggregateConta params string[] expectedSqlBits) { var acResult = compiler.Tasks.Single(t => t.Key is AggregationContainerTask a && a.Container.Equals(task)); - Assert.AreEqual(CompilationState.Finished, acResult.Key.State); + Assert.That(acResult.Key.State, Is.EqualTo(CompilationState.Finished)); foreach (var s in expectedSqlBits) - StringAssert.Contains(s, acResult.Value.CountSQL); + Assert.That(acResult.Value.CountSQL, Does.Contain(s)); } /// @@ -892,8 +897,11 @@ private static void AssertCacheUsed(CohortCompiler compiler, CohortAggregateCont var containerResult = compiler.Tasks.Single(t => t.Key is AggregationContainerTask c && c.Container.Equals(container)); - Assert.AreEqual(CompilationState.Finished, containerResult.Key.State); - Assert.AreEqual(expectedCacheUsageCount, containerResult.Key.GetCachedQueryUseCount()); + Assert.Multiple(() => + { + Assert.That(containerResult.Key.State, Is.EqualTo(CompilationState.Finished)); + Assert.That(containerResult.Key.GetCachedQueryUseCount(), Is.EqualTo(expectedCacheUsageCount)); + }); } #endregion diff --git a/Rdmp.Core.Tests/Rdmp.Core.Tests.csproj b/Rdmp.Core.Tests/Rdmp.Core.Tests.csproj index 68ef61d107..aa3f251a8f 100644 --- a/Rdmp.Core.Tests/Rdmp.Core.Tests.csproj +++ b/Rdmp.Core.Tests/Rdmp.Core.Tests.csproj @@ -69,9 +69,13 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Rdmp.Core.Tests/Reports/CustomMetadataReportTests.cs b/Rdmp.Core.Tests/Reports/CustomMetadataReportTests.cs index 757b8217d5..682d40caf7 100644 --- a/Rdmp.Core.Tests/Reports/CustomMetadataReportTests.cs +++ b/Rdmp.Core.Tests/Reports/CustomMetadataReportTests.cs @@ -9,6 +9,7 @@ using System.IO; using NSubstitute; using NUnit.Framework; +using NUnit.Framework.Legacy; using Rdmp.Core.CommandExecution; using Rdmp.Core.CommandExecution.AtomicCommands; using Rdmp.Core.Curation.Data; @@ -97,8 +98,8 @@ public void TestCustomMetadataReport_SingleCatalogue(bool oneFile) FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"| Name | Desc| -| ffff | |", resultText.TrimEnd()); + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"| Name | Desc| +| ffff | |").IgnoreCase); } [Test] @@ -130,8 +131,8 @@ public void TestCustomMetadataReport_SingleCatalogueWithNoDQEResults() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"| Name | Desc| Range | -| ffff | | Unknown |", resultText.TrimEnd()); + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"| Name | Desc| Range | +| ffff | | Unknown |").IgnoreCase); } [Test] @@ -180,9 +181,9 @@ public void TestCustomMetadataReport_SingleCatalogue_DQEMetrics() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase( - @"| Name | Desc| StartYear | EndYear | StartMonth | EndMonth | StartDay | EndDay | Range | TimeField | -| ffff | | 2001 | 2002 | 02 | 04 | 01 | 03 | 2001-2002 | mydate |", resultText.TrimEnd()); + Assert.That( +resultText.TrimEnd(), Is.EqualTo(@"| Name | Desc| StartYear | EndYear | StartMonth | EndMonth | StartDay | EndDay | Range | TimeField | +| ffff | | 2001 | 2002 | 02 | 04 | 01 | 03 | 2001-2002 | mydate |").IgnoreCase); } [TestCase(true)] @@ -227,8 +228,8 @@ public void TestCustomMetadataReport_TwoCatalogues(bool oneFile) FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase( - @" + Assert.That( +resultText.TrimEnd(), Is.EqualTo(@" Forest me@g.com @@ -237,7 +238,7 @@ public void TestCustomMetadataReport_TwoCatalogues(bool oneFile) Trees trollolol -", resultText.TrimEnd()); +").IgnoreCase); } else { @@ -248,21 +249,21 @@ public void TestCustomMetadataReport_TwoCatalogues(bool oneFile) FileAssert.Exists(outFile2); var resultText1 = File.ReadAllText(outFile1); - StringAssert.AreEqualIgnoringCase( - @" + Assert.That( +resultText1.Trim(), Is.EqualTo(@" Forest me@g.com -".Trim(), resultText1.Trim()); +".Trim()).IgnoreCase); var resultText2 = File.ReadAllText(outFile2); - StringAssert.AreEqualIgnoringCase( - @" + Assert.That( +resultText2.Trim(), Is.EqualTo(@" Trees trollolol -".Trim(), resultText2.Trim()); +".Trim()).IgnoreCase); } } @@ -313,11 +314,11 @@ public void TestCustomMetadataReport_CatalogueItems(bool oneFile) FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"## ffff + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"## ffff A cool dataset with interesting stuff | Column | Description | | Col1 | some info about column 1 | -| Col2 | some info about column 2 |", resultText.TrimEnd()); +| Col2 | some info about column 2 |").IgnoreCase); } [Test] @@ -351,7 +352,7 @@ public void TestCustomMetadataReport_TwoCataloguesWithItems() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"## Demog + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"## Demog This is expensive dataset: $30 to use Price: $30 | Column | Description | @@ -363,7 +364,7 @@ A cool dataset with interesting stuff Price: $30 | Column | Description | | Col1 | some info about column 1 | -| Col2 | some info about column 2 |", resultText.TrimEnd()); +| Col2 | some info about column 2 |").IgnoreCase); } [Test] @@ -393,8 +394,11 @@ public void TestCustomMetadataReport_CatalogueItems_NoEndBlock() outDir, template, "$Name.md", false, null); var ex = Assert.Throws(cmd.Execute); - Assert.AreEqual(4, ex.LineNumber); - Assert.AreEqual("Expected $end to match $foreach which started on line 4", ex.Message); + Assert.Multiple(() => + { + Assert.That(ex.LineNumber, Is.EqualTo(4)); + Assert.That(ex.Message, Is.EqualTo("Expected $end to match $foreach which started on line 4")); + }); } [Test] @@ -428,8 +432,11 @@ public void TestCustomMetadataReport_CatalogueItems_TooManyForeachBlocks() outDir, template, "$Name.md", false, null); var ex = Assert.Throws(cmd.Execute); - Assert.AreEqual(6, ex.LineNumber); - StringAssert.StartsWith("Error, encountered '$foreach CatalogueItem' on line 6", ex.Message); + Assert.Multiple(() => + { + Assert.That(ex.LineNumber, Is.EqualTo(6)); + Assert.That(ex.Message, Does.StartWith("Error, encountered '$foreach CatalogueItem' on line 6")); + }); } [Test] @@ -437,18 +444,24 @@ public void TestNewlineSubstitution() { var report = new CustomMetadataReport(RepositoryLocator); - //default is no substitution - Assert.IsNull(report.NewlineSubstitution); + Assert.Multiple(() => + { + //default is no substitution + Assert.That(report.NewlineSubstitution, Is.Null); - Assert.IsNull(report.ReplaceNewlines(null)); + Assert.That(report.ReplaceNewlines(null), Is.Null); - Assert.AreEqual("aa\r\nbb", report.ReplaceNewlines("aa\r\nbb")); - Assert.AreEqual("aa\nbb", report.ReplaceNewlines("aa\nbb")); + Assert.That(report.ReplaceNewlines("aa\r\nbb"), Is.EqualTo("aa\r\nbb")); + Assert.That(report.ReplaceNewlines("aa\nbb"), Is.EqualTo("aa\nbb")); + }); report.NewlineSubstitution = "
"; - Assert.AreEqual("aa
bb", report.ReplaceNewlines("aa\r\nbb")); - Assert.AreEqual("aa
bb", report.ReplaceNewlines("aa\nbb")); + Assert.Multiple(() => + { + Assert.That(report.ReplaceNewlines("aa\r\nbb"), Is.EqualTo("aa
bb")); + Assert.That(report.ReplaceNewlines("aa\nbb"), Is.EqualTo("aa
bb")); + }); } [Test] @@ -498,11 +511,11 @@ about column 2" FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"## ffff + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"## ffff A cool
dataset with interesting stuff | Column | Description | | Col1 | some info about column 1 | -| Col2 | some info
about column 2 |", resultText.TrimEnd()); +| Col2 | some info
about column 2 |").IgnoreCase); } @@ -536,9 +549,9 @@ public void TestTableInfoProperties_NoTableInfo() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"## ffff + Assert.That(resultText, Is.EqualTo(@"## ffff Server: -Description: A cool dataset with interesting stuff", resultText); +Description: A cool dataset with interesting stuff").IgnoreCase); } @@ -577,9 +590,9 @@ public void TestTableInfoProperties_OneTableInfo() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"## ffff + Assert.That(resultText, Is.EqualTo(@"## ffff Server: myserver -Description: A cool dataset with interesting stuff", resultText); +Description: A cool dataset with interesting stuff").IgnoreCase); } [Test] @@ -619,7 +632,7 @@ public void TestCustomMetadataReport_LoopCataloguesPrefix() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"# Welcome + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"# Welcome We love data here, see our datasets: @@ -635,7 +648,7 @@ A cool dataset with interesting stuff Price: $30 | Column | Description | | Col1 | some info about column 1 | -| Col2 | some info about column 2 |", resultText.TrimEnd()); +| Col2 | some info about column 2 |").IgnoreCase); } @@ -684,7 +697,7 @@ public void TestCustomMetadataReport_ColumnInfoDatatype() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"# Welcome + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"# Welcome We love data here, see our datasets: @@ -697,7 +710,7 @@ public void TestCustomMetadataReport_ColumnInfoDatatype() Price: $30 | Column | Description | Datatype | -| MyCataItem | | datetime2 |", resultText.TrimEnd()); +| MyCataItem | | datetime2 |").IgnoreCase); } @@ -747,7 +760,7 @@ public void TestCustomMetadataReport_Nullability_NoDQERun() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"# Welcome + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"# Welcome We love data here, see our datasets: @@ -762,7 +775,7 @@ public void TestCustomMetadataReport_Nullability_NoDQERun() Price: $30 Number of Records: | Column | Description | Nullability | -| Cata2Col1 | | |", resultText.TrimEnd()); +| Cata2Col1 | | |").IgnoreCase); } @@ -837,7 +850,7 @@ public void TestCustomMetadataReport_Nullability_WithDQERun() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"# Welcome + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"# Welcome We love data here, see our datasets: @@ -854,7 +867,7 @@ public void TestCustomMetadataReport_Nullability_WithDQERun() Number of Records: 10 | Column | Description | Nullability | Correct | Missing | Wrong | Invalid | Null (inclusive) | Total | | Cata2Col1 | | 50% | 1 | 2 | 3 | 4 | 5 | 10 | -Accurate as of : 01/01/0001 00:00:00", resultText.TrimEnd()); +Accurate as of : 01/01/0001 00:00:00").IgnoreCase); } @@ -893,7 +906,7 @@ public void TestCustomMetadataReport_LoopCataloguesSuffix() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"## Catalogue 'Demog' + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"## Catalogue 'Demog' This is expensive dataset: $30 to use Price: $30 | Column | Description | @@ -907,7 +920,7 @@ A cool dataset with interesting stuff | Col1 | some info about column 1 | | Col2 | some info about column 2 | -Get in touch with us at noreply@nobody.com", resultText.TrimEnd()); +Get in touch with us at noreply@nobody.com").IgnoreCase); } [Test] @@ -949,7 +962,7 @@ public void TestCustomMetadataReport_LoopCataloguesPrefixAndSuffix() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"# Welcome + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"# Welcome We love data here, see our datasets: @@ -967,7 +980,7 @@ A cool dataset with interesting stuff | Col1 | some info about column 1 | | Col2 | some info about column 2 | -Get in touch with us at noreply@nobody.com", resultText.TrimEnd()); +Get in touch with us at noreply@nobody.com").IgnoreCase); } @@ -1019,7 +1032,7 @@ public void TestCustomMetadataReport_LoopCataloguesTableOfContents() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"# Welcome + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"# Welcome - [Background](#background) - [Datasets](#datasets) - [Demog](#Demog) @@ -1045,7 +1058,7 @@ A cool dataset with interesting stuff | Col1 | some info about column 1 | | Col2 | some info about column 2 | -Get in touch with us at noreply@nobody.com", resultText.TrimEnd()); +Get in touch with us at noreply@nobody.com").IgnoreCase); } [Test] @@ -1074,8 +1087,11 @@ some more text outDir, template, "Datasets.md", true, null); var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual("Unexpected '$foreach Catalogue' before the end of the last one on line 4", ex.Message); - Assert.AreEqual(4, ex.LineNumber); + Assert.Multiple(() => + { + Assert.That(ex.Message, Is.EqualTo("Unexpected '$foreach Catalogue' before the end of the last one on line 4")); + Assert.That(ex.LineNumber, Is.EqualTo(4)); + }); } [Test] @@ -1104,8 +1120,11 @@ some more text outDir, template, "Datasets.md", true, null); var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual("Error, encountered '$end' on line 3 while not in a $foreach Catalogue block", ex.Message); - Assert.AreEqual(3, ex.LineNumber); + Assert.Multiple(() => + { + Assert.That(ex.Message, Is.EqualTo("Error, encountered '$end' on line 3 while not in a $foreach Catalogue block")); + Assert.That(ex.LineNumber, Is.EqualTo(3)); + }); } @@ -1136,8 +1155,11 @@ some more text outDir, template, "Datasets.md", true, null); var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual("Error, encountered '$end' on line 5 while not in a $foreach Catalogue block", ex.Message); - Assert.AreEqual(5, ex.LineNumber); + Assert.Multiple(() => + { + Assert.That(ex.Message, Is.EqualTo("Error, encountered '$end' on line 5 while not in a $foreach Catalogue block")); + Assert.That(ex.LineNumber, Is.EqualTo(5)); + }); } [Test] @@ -1168,10 +1190,12 @@ some more text outDir, template, "Datasets.md", true, null); var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual( - "Error, Unexpected '$foreach CatalogueItem' on line 3. Current section is plain text, '$foreach CatalogueItem' can only appear within a '$foreach Catalogue' block (you cannot mix and match top level loop elements)", - ex.Message); - Assert.AreEqual(3, ex.LineNumber); + Assert.Multiple(() => + { + Assert.That( + ex.Message, Is.EqualTo("Error, Unexpected '$foreach CatalogueItem' on line 3. Current section is plain text, '$foreach CatalogueItem' can only appear within a '$foreach Catalogue' block (you cannot mix and match top level loop elements)")); + Assert.That(ex.LineNumber, Is.EqualTo(3)); + }); } [Test] @@ -1196,7 +1220,7 @@ public void Test_CustomMetadataElementSeperator_ThrowsWhenNotInForEach() outDir, template, "Datasets.md", true, null); var ex = Assert.Throws(() => cmd.Execute()); - Assert.AreEqual("Unexpected use of $Comma outside of an iteration ($foreach) block", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Unexpected use of $Comma outside of an iteration ($foreach) block")); } [Test] @@ -1238,7 +1262,7 @@ public void Test_CustomMetadataElementSeperator_JsonExample() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"[ + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"[ { ""Name"": ""Demog"", ""Columns"": [ @@ -1264,7 +1288,7 @@ public void Test_CustomMetadataElementSeperator_JsonExample() } ] } -]", resultText.TrimEnd()); +]").IgnoreCase); } [Test] @@ -1306,7 +1330,7 @@ public void Test_CustomMetadataElementSeperator_JsonExample_SemicolonSub() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - StringAssert.AreEqualIgnoringCase(@"[ + Assert.That(resultText.TrimEnd(), Is.EqualTo(@"[ { ""Name"": ""Demog"", ""Columns"": [ @@ -1332,7 +1356,7 @@ public void Test_CustomMetadataElementSeperator_JsonExample_SemicolonSub() } ] } -]", resultText.TrimEnd()); +]").IgnoreCase); } [Test] @@ -1423,7 +1447,7 @@ public void TestAllSubs_Catalogue() // this appears in a Catalogue description resultText = resultText.Replace("$30", ""); - Assert.IsFalse(resultText.Contains('$'), $"Expected all template values to disappear but was {resultText}"); + Assert.That(resultText, Does.Not.Contain('$'), $"Expected all template values to disappear but was {resultText}"); } @@ -1483,6 +1507,6 @@ public void TestAllSubs_CatalogueItem() FileAssert.Exists(outFile); var resultText = File.ReadAllText(outFile); - Assert.IsFalse(resultText.Contains('$'), $"Expected all template values to disappear but was {resultText}"); + Assert.That(resultText, Does.Not.Contain('$'), $"Expected all template values to disappear but was {resultText}"); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Reports/ExtractionTime/WordDataReleaseFileGeneratorTests.cs b/Rdmp.Core.Tests/Reports/ExtractionTime/WordDataReleaseFileGeneratorTests.cs index 6faa07f36d..72b27a0bfb 100644 --- a/Rdmp.Core.Tests/Reports/ExtractionTime/WordDataReleaseFileGeneratorTests.cs +++ b/Rdmp.Core.Tests/Reports/ExtractionTime/WordDataReleaseFileGeneratorTests.cs @@ -21,6 +21,6 @@ public void Test_WordDataReleaseFileGenerator_Normal() var filename = Path.Combine(TestContext.CurrentContext.WorkDirectory, "release.doc"); report.GenerateWordFile(filename); - Assert.IsTrue(File.Exists(filename)); + Assert.That(File.Exists(filename)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Reports/MetadataReportTests.cs b/Rdmp.Core.Tests/Reports/MetadataReportTests.cs index fbb6e5f496..14be3023a1 100644 --- a/Rdmp.Core.Tests/Reports/MetadataReportTests.cs +++ b/Rdmp.Core.Tests/Reports/MetadataReportTests.cs @@ -37,11 +37,14 @@ public void Test_MetadataReport_Basic() var file = reporter.GenerateWordFile(ThrowImmediatelyDataLoadEventListener.Quiet, false); - Assert.IsNotNull(file); - Assert.IsTrue(File.Exists(file.FullName)); + Assert.Multiple(() => + { + Assert.That(file, Is.Not.Null); + Assert.That(File.Exists(file.FullName)); - //refreshes the file stream status - Assert.Greater(new FileInfo(file.FullName).Length, 0); + //refreshes the file stream status + Assert.That(new FileInfo(file.FullName).Length, Is.GreaterThan(0)); + }); } [Test] @@ -61,7 +64,10 @@ public void Test_OrphanExtractionInformation() ); var file = reporter.GenerateWordFile(ThrowImmediatelyDataLoadEventListener.Quiet, false); - Assert.IsNotNull(file); - Assert.IsTrue(File.Exists(file.FullName)); + Assert.Multiple(() => + { + Assert.That(file, Is.Not.Null); + Assert.That(File.Exists(file.FullName)); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Repositories/CatalogueRepositoryTests.cs b/Rdmp.Core.Tests/Repositories/CatalogueRepositoryTests.cs index 4984bf2870..78d8f42656 100644 --- a/Rdmp.Core.Tests/Repositories/CatalogueRepositoryTests.cs +++ b/Rdmp.Core.Tests/Repositories/CatalogueRepositoryTests.cs @@ -34,11 +34,11 @@ public void TestConnection_NoServer_DoNotShowPassword() var msg = Assert.Throws(() => repo.TestConnection()); - StringAssert.StartsWith("Testing connection failed", msg.Message); - StringAssert.DoesNotContain("omg", msg.Message); - StringAssert.Contains("****", msg.Message); - StringAssert.Contains("Timeout", msg.Message); - StringAssert.Contains("2", msg.Message); + Assert.That(msg.Message, Does.StartWith("Testing connection failed")); + Assert.That(msg.Message, Does.Not.Contain("omg")); + Assert.That(msg.Message, Does.Contain("****")); + Assert.That(msg.Message, Does.Contain("Timeout")); + Assert.That(msg.Message, Does.Contain("2")); } [Test] @@ -59,9 +59,9 @@ public void TestConnection_NoServer_IntegratedSecurity() var msg = Assert.Throws(() => repo.TestConnection()); - StringAssert.StartsWith("Testing connection failed", msg.Message); - StringAssert.Contains("Integrated Security=", msg.Message); - StringAssert.Contains("Timeout", msg.Message); - StringAssert.Contains("2", msg.Message); + Assert.That(msg.Message, Does.StartWith("Testing connection failed")); + Assert.That(msg.Message, Does.Contain("Integrated Security=")); + Assert.That(msg.Message, Does.Contain("Timeout")); + Assert.That(msg.Message, Does.Contain("2")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/ReusableCodeTests/ChangeLogIsCorrectTests.cs b/Rdmp.Core.Tests/ReusableCodeTests/ChangeLogIsCorrectTests.cs index 93df08a5e1..c19aa91c51 100644 --- a/Rdmp.Core.Tests/ReusableCodeTests/ChangeLogIsCorrectTests.cs +++ b/Rdmp.Core.Tests/ReusableCodeTests/ChangeLogIsCorrectTests.cs @@ -25,7 +25,7 @@ public void TestChangeLogContents() log = dir.GetFiles("changelog.md", opts).SingleOrDefault(); } - Assert.IsNotNull(log, "CHANGELOG.md not found"); + Assert.That(log, Is.Not.Null, "CHANGELOG.md not found"); var assemblyInfo = Path.Combine(log.Directory.FullName, "SharedAssemblyInfo.cs"); @@ -33,11 +33,11 @@ public void TestChangeLogContents() Assert.Fail($"Could not find file {assemblyInfo}"); var match = Regex.Match(File.ReadAllText(assemblyInfo), @"AssemblyInformationalVersion\(""([^-]+).*""\)"); - Assert.IsTrue(match.Success, $"Could not find AssemblyInformationalVersion tag in {assemblyInfo}"); + Assert.That(match.Success, $"Could not find AssemblyInformationalVersion tag in {assemblyInfo}"); var currentVersion = match.Groups[1].Value; - Assert.IsTrue(File.ReadLines(log.FullName).Any(l => l.Contains($"## [{currentVersion}]")), + Assert.That(File.ReadLines(log.FullName).Any(l => l.Contains($"## [{currentVersion}]")), $"{log.FullName} did not contain a header for the current version '{currentVersion}'"); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/ReusableCodeTests/DataTableExtensionsTests.cs b/Rdmp.Core.Tests/ReusableCodeTests/DataTableExtensionsTests.cs index bb2f5457bc..76fb2daf4b 100644 --- a/Rdmp.Core.Tests/ReusableCodeTests/DataTableExtensionsTests.cs +++ b/Rdmp.Core.Tests/ReusableCodeTests/DataTableExtensionsTests.cs @@ -29,10 +29,11 @@ public void TestEscaping_CommaInCell() var answer = File.ReadAllText(path); - Assert.AreEqual(answer, - @"Phrase,Car -""omg,why me!"",Ferrari -"); + Assert.That(answer, Is.EqualTo(""" + Phrase,Car + "omg,why me!",Ferrari + + """)); } [Test] @@ -50,10 +51,11 @@ public void TestEscaping_CommaAndQuotesInCell() var answer = File.ReadAllText(path); - Assert.AreEqual(answer, - @"Phrase,Car -""omg,""""why"""" me!"",Ferrari -"); + Assert.That(answer, Is.EqualTo(""" + Phrase,Car + "omg,""why"" me!",Ferrari + + """)); } @@ -72,9 +74,10 @@ public void TestEscaping_CommaAndQuotesInCell2() var answer = File.ReadAllText(path); - Assert.AreEqual(answer, - @"Phrase,Car -""""""omg,why me!"""""",Ferrari -"); + Assert.That(answer, Is.EqualTo("""" + Phrase,Car + """omg,why me!""",Ferrari + + """")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/ReusableCodeTests/ExpectedIdenticalStringsExceptionTests.cs b/Rdmp.Core.Tests/ReusableCodeTests/ExpectedIdenticalStringsExceptionTests.cs index 30b3df96e0..0b1ec3d159 100644 --- a/Rdmp.Core.Tests/ReusableCodeTests/ExpectedIdenticalStringsExceptionTests.cs +++ b/Rdmp.Core.Tests/ReusableCodeTests/ExpectedIdenticalStringsExceptionTests.cs @@ -21,12 +21,12 @@ public void CompletelyDifferentCase() { var ex = new ExpectedIdenticalStringsException("These are different", "fish", "egg"); - Assert.AreEqual( - @"These are different + Assert.That( +ex.Message, Is.EqualTo(@"These are different Strings differ at index 0 EXPECTED:fish ACTUAL :egg ----------^", ex.Message); +---------^")); } [Test] @@ -34,13 +34,13 @@ public void ShortCase() { var ex = new ExpectedIdenticalStringsException("These are different", "fish", "fins"); - Assert.AreEqual( - @"These are different + Assert.That( +ex.Message, Is.EqualTo(@"These are different Strings differ at index 2 EXPECTED:fish ACTUAL :fins -----------^" - , ex.Message); +)); } @@ -49,13 +49,13 @@ public void MoreThanExpected() { var ex = new ExpectedIdenticalStringsException("These are different", "fish", "fish fly high"); - Assert.AreEqual( - @"These are different + Assert.That( +ex.Message, Is.EqualTo(@"These are different Strings are identical except that Expected string ends at character 4 while the Actual string had 9 additional characters EXPECTED:fish ACTUAL :fish fly high -------------^" - , ex.Message); +)); } [Test] @@ -64,13 +64,13 @@ public void Whitespace() var ex = new ExpectedIdenticalStringsException("These are different", @"fi sh", "fish"); - Assert.AreEqual( - $@"These are different + Assert.That( +ex.Message, Is.EqualTo($@"These are different Strings differ at index 2 EXPECTED:fi{eol}sh ACTUAL :fish -----------^" - , ex.Message); +)); } @@ -81,13 +81,13 @@ public void VeryLongStrings() @"Theosophists have guessed at the awesome grandeur of the cosmic cycle where our world and human race form transient incidents", @"Theosophists have guessed at the awesome grandeur of the cosmic cycle wherein our world and human race form transient incidents"); - Assert.AreEqual( - @"These are different + Assert.That( +ex.Message, Is.EqualTo(@"These are different Strings differ at index 75 EXPECTED:e cosmic cycle where our world... ACTUAL :e cosmic cycle wherein our wor... -----------------------------^" - , ex.Message); +)); } [Test] @@ -104,10 +104,10 @@ public void VeryLongStringsWithWhitespace() my uncle, in his latter years become credulous of the most superficial impostures? ".Replace("\r", "")); // .Replace above forces Unix-style strings for test consistency - Assert.AreEqual($@"These are different + Assert.That(ex.Message, Is.EqualTo($@"These are different Strings differ at index 34 EXPECTED:d be the\nmeaning \nof the que... ACTUAL :d be the\nmeaning \nif the que... ------------------------------^", ex.Message); +-----------------------------^")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/ReusableCodeTests/PackageListIsCorrectTests.cs b/Rdmp.Core.Tests/ReusableCodeTests/PackageListIsCorrectTests.cs index 5418634735..882630995a 100644 --- a/Rdmp.Core.Tests/ReusableCodeTests/PackageListIsCorrectTests.cs +++ b/Rdmp.Core.Tests/ReusableCodeTests/PackageListIsCorrectTests.cs @@ -61,10 +61,13 @@ public void TestPackagesDocumentCorrect(string rootPath = null) undocumented.AppendJoin(Environment.NewLine, undocumentedPackages); var unusedPackages = packagesMarkdown.Except(usedPackages).ToArray(); - Assert.IsEmpty(unusedPackages, - $"The following packages are listed in PACKAGES.md but are not used in any csproj file: {string.Join(", ", unusedPackages)}"); - Assert.Zero(undocumentedPackages.Count, - $"One or more packages not documented in PACKAGES.md. Recommended addition:{Environment.NewLine}{undocumented}"); + Assert.Multiple(() => + { + Assert.That(unusedPackages, Is.Empty, + $"The following packages are listed in PACKAGES.md but are not used in any csproj file: {string.Join(", ", unusedPackages)}"); + Assert.That(undocumentedPackages, Is.Empty, + $"One or more packages not documented in PACKAGES.md. Recommended addition:{Environment.NewLine}{undocumented}"); + }); } /// @@ -92,7 +95,7 @@ private static DirectoryInfo FindRoot(string path = null) var root = new DirectoryInfo(TestContext.CurrentContext.TestDirectory); while (!root.EnumerateFiles("*.sln", SearchOption.TopDirectoryOnly).Any() && root.Parent != null) root = root.Parent; - Assert.IsNotNull(root.Parent, "Could not find root of repository"); + Assert.That(root.Parent, Is.Not.Null, "Could not find root of repository"); return root; } @@ -115,7 +118,7 @@ private static IEnumerable GetCsprojFiles(DirectoryInfo root) private static string GetPackagesMarkdown(DirectoryInfo root) { var path = root.EnumerateFiles("packages.md", EnumerationOptions).Select(f => f.FullName).SingleOrDefault(); - Assert.IsNotNull(path, "Could not find packages.md"); + Assert.That(path, Is.Not.Null, "Could not find packages.md"); return path; } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/ReusableCodeTests/UsefulStuffTests.cs b/Rdmp.Core.Tests/ReusableCodeTests/UsefulStuffTests.cs index 5faf717c3d..ef8cbb440f 100644 --- a/Rdmp.Core.Tests/ReusableCodeTests/UsefulStuffTests.cs +++ b/Rdmp.Core.Tests/ReusableCodeTests/UsefulStuffTests.cs @@ -18,7 +18,7 @@ public void GetRowCountWhenNoIndexes() { var db = GetCleanedServer(DatabaseType.MicrosoftSQLServer); var table = db.ExpectTable("GetRowCountWhenNoIndexes"); - Assert.AreEqual("GetRowCountWhenNoIndexes", table.GetRuntimeName()); + Assert.That(table.GetRuntimeName(), Is.EqualTo("GetRowCountWhenNoIndexes")); var server = table.Database.Server; using var con = server.GetConnection(); @@ -28,9 +28,12 @@ public void GetRowCountWhenNoIndexes() cmd.ExecuteNonQuery(); var cmdInsert = server.GetCommand($"INSERT INTO {table.GetRuntimeName()} VALUES (1,'Fish')", con); - Assert.AreEqual(1, cmdInsert.ExecuteNonQuery()); + Assert.Multiple(() => + { + Assert.That(cmdInsert.ExecuteNonQuery(), Is.EqualTo(1)); - Assert.AreEqual(1, table.GetRowCount()); + Assert.That(table.GetRowCount(), Is.EqualTo(1)); + }); } [Test] @@ -44,40 +47,43 @@ public void GetRowCount_Views() cmd.ExecuteNonQuery(); var cmdInsert = db.Server.GetCommand("INSERT INTO GetRowCount_Views VALUES (1,'Fish')", con); - Assert.AreEqual(1, cmdInsert.ExecuteNonQuery()); + Assert.That(cmdInsert.ExecuteNonQuery(), Is.EqualTo(1)); var cmdView = db.Server.GetCommand( "CREATE VIEW v_GetRowCount_Views as select * from GetRowCount_Views", con); cmdView.ExecuteNonQuery(); - Assert.AreEqual(1, db.ExpectTable("v_GetRowCount_Views").GetRowCount()); + Assert.That(db.ExpectTable("v_GetRowCount_Views").GetRowCount(), Is.EqualTo(1)); } [Test] public void PascalCaseStringToHumanReadable() { - Assert.AreEqual("teststringhere", UsefulStuff.PascalCaseStringToHumanReadable("teststringhere")); - Assert.AreEqual("test Stringhere", UsefulStuff.PascalCaseStringToHumanReadable("testStringhere")); - Assert.AreEqual("test String Here", UsefulStuff.PascalCaseStringToHumanReadable("testStringHere")); - Assert.AreEqual("Test String Here", UsefulStuff.PascalCaseStringToHumanReadable("TestStringHere")); - Assert.AreEqual("TEST String Here", UsefulStuff.PascalCaseStringToHumanReadable("TESTStringHere")); - Assert.AreEqual("Test STRING Here", UsefulStuff.PascalCaseStringToHumanReadable("TestSTRINGHere")); - Assert.AreEqual("Test String HERE", UsefulStuff.PascalCaseStringToHumanReadable("TestStringHERE")); - - //Some practical tests for completeness sake - Assert.AreEqual("A", UsefulStuff.PascalCaseStringToHumanReadable("A")); - Assert.AreEqual("AS", UsefulStuff.PascalCaseStringToHumanReadable("AS")); - Assert.AreEqual("A String", UsefulStuff.PascalCaseStringToHumanReadable("AString")); - Assert.AreEqual("String A Test", UsefulStuff.PascalCaseStringToHumanReadable("StringATest")); - Assert.AreEqual("String AS Test", UsefulStuff.PascalCaseStringToHumanReadable("StringASTest")); - Assert.AreEqual("CT Head", UsefulStuff.PascalCaseStringToHumanReadable("CTHead")); - Assert.AreEqual("WHERE Clause", UsefulStuff.PascalCaseStringToHumanReadable("WHEREClause")); - Assert.AreEqual("Sql WHERE", UsefulStuff.PascalCaseStringToHumanReadable("SqlWHERE")); - - Assert.AreEqual("Test String", UsefulStuff.PascalCaseStringToHumanReadable("Test_String")); - Assert.AreEqual("Test string", UsefulStuff.PascalCaseStringToHumanReadable("Test_string")); - Assert.AreEqual("test String", UsefulStuff.PascalCaseStringToHumanReadable("_testString")); - Assert.AreEqual("test String", UsefulStuff.PascalCaseStringToHumanReadable("_testString_")); + Assert.Multiple(() => + { + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("teststringhere"), Is.EqualTo("teststringhere")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("testStringhere"), Is.EqualTo("test Stringhere")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("testStringHere"), Is.EqualTo("test String Here")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("TestStringHere"), Is.EqualTo("Test String Here")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("TESTStringHere"), Is.EqualTo("TEST String Here")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("TestSTRINGHere"), Is.EqualTo("Test STRING Here")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("TestStringHERE"), Is.EqualTo("Test String HERE")); + + //Some practical tests for completeness sake + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("A"), Is.EqualTo("A")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("AS"), Is.EqualTo("AS")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("AString"), Is.EqualTo("A String")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("StringATest"), Is.EqualTo("String A Test")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("StringASTest"), Is.EqualTo("String AS Test")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("CTHead"), Is.EqualTo("CT Head")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("WHEREClause"), Is.EqualTo("WHERE Clause")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("SqlWHERE"), Is.EqualTo("Sql WHERE")); + + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("Test_String"), Is.EqualTo("Test String")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("Test_string"), Is.EqualTo("Test string")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("_testString"), Is.EqualTo("test String")); + Assert.That(UsefulStuff.PascalCaseStringToHumanReadable("_testString_"), Is.EqualTo("test String")); + }); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/ReusableCodeTests/UsefulStuffUnitTests.cs b/Rdmp.Core.Tests/ReusableCodeTests/UsefulStuffUnitTests.cs index 72c21b9a91..d8ee4c41cd 100644 --- a/Rdmp.Core.Tests/ReusableCodeTests/UsefulStuffUnitTests.cs +++ b/Rdmp.Core.Tests/ReusableCodeTests/UsefulStuffUnitTests.cs @@ -18,7 +18,7 @@ public class UsefulStuffUnitTests [TestCase("1203567855", true)] public void ChiValidationTests(string chi, bool valid) { - Assert.AreEqual(valid, UsefulStuff.CHIisOK(chi), "Validation gave incorrect answer for CHI '{0}'", chi); + Assert.That(UsefulStuff.CHIisOK(chi), Is.EqualTo(valid), $"Validation gave incorrect answer for CHI '{chi}'"); } [TestCase("[ff ff]", "ff ff")] @@ -35,7 +35,7 @@ public void TestGetArrayOfColumnNamesFromStringPastedInByUser(string input, stri foreach (var suffix in new[] { "", "\n", "\r", "\r\n", ",\r\n" }) { var output = UsefulStuff.GetArrayOfColumnNamesFromStringPastedInByUser($"{input}{suffix}"); - Assert.AreEqual(expectedOutput, output.Single()); + Assert.That(output.Single(), Is.EqualTo(expectedOutput)); } } @@ -44,6 +44,6 @@ public void TestGetArrayOfColumnNamesFromStringPastedInByUser(string input, stri public void ClipboardHtmlTest() { const string test = "Version:1.0\r\nStartHTML:000051\r\nEndHTML:0000000055\r\nTest"; - Assert.AreEqual(test, UsefulStuff.GetClipboardFormattedHtmlStringFromHtmlString("Test")); + Assert.That(UsefulStuff.GetClipboardFormattedHtmlStringFromHtmlString("Test"), Is.EqualTo(test)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/Constraints/Primary/AlphaNumericTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Primary/AlphaNumericTest.cs index b5e947f9ac..54ff02cdfe 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Primary/AlphaNumericTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Primary/AlphaNumericTest.cs @@ -31,7 +31,7 @@ protected override void SetUp() [TestCase(" 1")] public void Validate_Invalid_ThrowsException(string code) { - Assert.NotNull(_alphanum.Validate(code)); + Assert.That(_alphanum.Validate(code), Is.Not.Null); } [TestCase(null)] @@ -43,7 +43,7 @@ public void Validate_Invalid_ThrowsException(string code) [TestCase("AAAAAA")] public void Validate_Valid_Success(string code) { - Assert.IsNull(_alphanum.Validate(code)); + Assert.That(_alphanum.Validate(code), Is.Null); } [Test] @@ -51,7 +51,7 @@ public void Validate_Invalid_ExceptionContainsRequiredInfo() { var result = _alphanum.Validate(" "); - Assert.NotNull(result.SourceConstraint); - Assert.AreEqual(typeof(AlphaNumeric), result.SourceConstraint.GetType()); + Assert.That(result.SourceConstraint, Is.Not.Null); + Assert.That(result.SourceConstraint.GetType(), Is.EqualTo(typeof(AlphaNumeric))); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/Constraints/Primary/AlphaTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Primary/AlphaTest.cs index 561113fe3d..d2fa03ff7d 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Primary/AlphaTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Primary/AlphaTest.cs @@ -31,7 +31,7 @@ protected override void SetUp() [TestCase("A1 ")] public void Validate_Invalid_ThrowsException(string code) { - Assert.NotNull(_alpha.Validate(code)); + Assert.That(_alpha.Validate(code), Is.Not.Null); } [TestCase(null)] @@ -43,7 +43,7 @@ public void Validate_Invalid_ThrowsException(string code) [TestCase("AAAAAA")] public void Validate_Valid_Success(string code) { - Assert.IsNull(_alpha.Validate(code)); + Assert.That(_alpha.Validate(code), Is.Null); } [Test] @@ -51,7 +51,7 @@ public void Validate_Invalid_ExceptionContainsRequiredInfo() { var result = _alpha.Validate("9"); - Assert.NotNull(result.SourceConstraint); - Assert.AreEqual(typeof(Alpha), result.SourceConstraint.GetType()); + Assert.That(result.SourceConstraint, Is.Not.Null); + Assert.That(result.SourceConstraint.GetType(), Is.EqualTo(typeof(Alpha))); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/Constraints/Primary/BoundsValidationDateTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Primary/BoundsValidationDateTest.cs index acb825b649..24b51ec5f0 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Primary/BoundsValidationDateTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Primary/BoundsValidationDateTest.cs @@ -36,7 +36,7 @@ public void must_occur_between_two_literal_dates_VALID() b.Upper = DateTime.MaxValue; var v = CreateLiteralDateValidator(b); - Assert.IsNull(v.Validate(_d)); + Assert.That(v.Validate(_d), Is.Null); } [Test] @@ -47,7 +47,7 @@ public void must_occur_between_two_literal_dates_INVALID_after() b.Upper = DateTime.MinValue.AddYears(1); var v = CreateLiteralDateValidator(b); - Assert.NotNull(v.Validate(_d)); + Assert.That(v.Validate(_d), Is.Not.Null); } [Test] @@ -58,7 +58,7 @@ public void must_occur_between_two_literal_dates_INVALID_before() b.Upper = DateTime.MaxValue; var v = CreateLiteralDateValidator(b); - Assert.NotNull(v.Validate(_d)); + Assert.That(v.Validate(_d), Is.Not.Null); } [Test] @@ -71,7 +71,7 @@ public void must_occur_between_two_literal_dates_INVALID_onlower() var v = CreateLiteralDateValidator(b); - Assert.NotNull(v.Validate(_d)); + Assert.That(v.Validate(_d), Is.Not.Null); } [Test] @@ -83,7 +83,7 @@ public void must_occur_between_two_literal_dates_INVALID_onupper() b.Inclusive = false; var v = CreateLiteralDateValidator(b); - Assert.NotNull(v.Validate(_d)); + Assert.That(v.Validate(_d), Is.Not.Null); } [Test] @@ -95,7 +95,7 @@ public void must_occur_inclusively_between_two_literal_dates_VALID_onlower() b.Inclusive = true; var v = CreateLiteralDateValidator(b); - Assert.IsNull(v.Validate(_d)); + Assert.That(v.Validate(_d), Is.Null); } [Test] @@ -107,7 +107,7 @@ public void must_occur_inclusively_between_two_literal_dates_VALID_onupper() b.Inclusive = true; var v = CreateLiteralDateValidator(b); - Assert.IsNull(v.Validate(_d)); + Assert.That(v.Validate(_d), Is.Null); } #endregion @@ -123,7 +123,7 @@ public void must_occur_after_field_VALID() var v = CreateAdmissionDateValidator(b); - Assert.IsNull(v.Validate(TestConstants.AdmissionDateOccursAfterDob)); + Assert.That(v.Validate(TestConstants.AdmissionDateOccursAfterDob), Is.Null); } @@ -136,7 +136,7 @@ public void must_occur_after_field_INVALID_before() var v = CreateAdmissionDateValidator(b); - Assert.NotNull(v.Validate(TestConstants.AdmissionDateOccursBeforeDob)); + Assert.That(v.Validate(TestConstants.AdmissionDateOccursBeforeDob), Is.Not.Null); } [Test] @@ -148,7 +148,7 @@ public void must_occur_after_field_INVALID_same() b.Inclusive = false; var v = CreateAdmissionDateValidator(b); - Assert.NotNull(v.Validate(TestConstants.AdmissionDateOccursOnDob)); + Assert.That(v.Validate(TestConstants.AdmissionDateOccursOnDob), Is.Not.Null); } [Test] @@ -167,7 +167,7 @@ public void must_occur_after_field_INVALID_violation_report() var l = result.GetExceptionList(); - StringAssert.EndsWith($"Expected a date greater than [{b.LowerFieldName}].", l[0].Message); + Assert.That(l[0].Message, Does.EndWith($"Expected a date greater than [{b.LowerFieldName}].")); Console.WriteLine(result.Message); } @@ -180,7 +180,7 @@ public void must_occur_before_field_VALID() var v = CreateParentDobValidator(b); - Assert.IsNull(v.Validate(TestConstants.ParentDobOccursBeforeDob)); + Assert.That(v.Validate(TestConstants.ParentDobOccursBeforeDob), Is.Null); } [Test] @@ -192,7 +192,7 @@ public void must_occur_before_field_INVALID_same() var v = CreateParentDobValidator(b); - Assert.NotNull(v.Validate(TestConstants.ParentDobOccursOnDob)); + Assert.That(v.Validate(TestConstants.ParentDobOccursOnDob), Is.Not.Null); } [Test] @@ -204,7 +204,7 @@ public void must_occur_before_field_INVALID_after() var v = CreateParentDobValidator(b); - Assert.NotNull(v.Validate(TestConstants.ParentDobOccursAfterDob)); + Assert.That(v.Validate(TestConstants.ParentDobOccursAfterDob), Is.Not.Null); } [Test] @@ -223,7 +223,7 @@ public void must_occur_before_field_INVALID_violation_report() var l = result.GetExceptionList(); - StringAssert.EndsWith($"Expected a date less than [{b.UpperFieldName}].", l[0].Message); + Assert.That(l[0].Message, Does.EndWith($"Expected a date less than [{b.UpperFieldName}].")); Console.WriteLine(result.Message); } @@ -236,7 +236,7 @@ public void must_occur_between_fields_VALID() var v = CreateOperationDateValidator(b); - Assert.IsNull(v.Validate(TestConstants.OperationOccursDuringStay)); + Assert.That(v.Validate(TestConstants.OperationOccursDuringStay), Is.Null); } [Test] @@ -249,7 +249,7 @@ public void must_occur_inclusively_between_fields_VALID_onstart() var v = CreateOperationDateValidator(b); - Assert.IsNull(v.Validate(TestConstants.OperationOccursOnStartOfStay)); + Assert.That(v.Validate(TestConstants.OperationOccursOnStartOfStay), Is.Null); } [Test] @@ -262,7 +262,7 @@ public void must_occur_inclusively_between_fields_VALID_onend() var v = CreateOperationDateValidator(b); - Assert.IsNull(v.Validate(TestConstants.OperationOccursOnEndOfStay)); + Assert.That(v.Validate(TestConstants.OperationOccursOnEndOfStay), Is.Null); } [Test] @@ -274,7 +274,7 @@ public void must_occur_between_fields_INVALID_onstart() b.Inclusive = false; var v = CreateOperationDateValidator(b); - Assert.NotNull(v.Validate(TestConstants.OperationOccursOnStartOfStay)); + Assert.That(v.Validate(TestConstants.OperationOccursOnStartOfStay), Is.Not.Null); } [Test] @@ -286,7 +286,7 @@ public void must_occur_between_fields_INVALID_onend() b.Inclusive = false; var v = CreateOperationDateValidator(b); - Assert.NotNull(v.Validate(TestConstants.OperationOccursOnEndOfStay)); + Assert.That(v.Validate(TestConstants.OperationOccursOnEndOfStay), Is.Not.Null); } [Test] @@ -298,7 +298,7 @@ public void must_occur_between_fields_INVALID_before() var v = CreateOperationDateValidator(b); - Assert.NotNull(v.Validate(TestConstants.OperationOccursBeforeStay)); + Assert.That(v.Validate(TestConstants.OperationOccursBeforeStay), Is.Not.Null); } [Test] @@ -310,7 +310,7 @@ public void must_occur_between_fields_INVALID_after() var v = CreateOperationDateValidator(b); - Assert.NotNull(v.Validate(TestConstants.OperationOccursAfterStay)); + Assert.That(v.Validate(TestConstants.OperationOccursAfterStay), Is.Not.Null); } #endregion @@ -341,7 +341,7 @@ public void f_must_occur_after_field_VALID() var v = new Validator(); v.EnsureThatValue("admission_date").OccursAfter("dob"); - Assert.IsNull(v.Validate(TestConstants.AdmissionDateOccursAfterDob)); + Assert.That(v.Validate(TestConstants.AdmissionDateOccursAfterDob), Is.Null); } [Test] @@ -350,7 +350,7 @@ public void f_must_occur_after_field_INVALID_before() var v = new Validator(); v.EnsureThatValue("admission_date").OccursAfter("dob"); - Assert.NotNull(v.Validate(TestConstants.AdmissionDateOccursBeforeDob)); + Assert.That(v.Validate(TestConstants.AdmissionDateOccursBeforeDob), Is.Not.Null); } [Test] @@ -359,7 +359,7 @@ public void f_must_occur_after_field_INVALID_same() var v = new Validator(); v.EnsureThatValue("admission_date").OccursAfter("dob"); - Assert.NotNull(v.Validate(TestConstants.AdmissionDateOccursOnDob)); + Assert.That(v.Validate(TestConstants.AdmissionDateOccursOnDob), Is.Not.Null); } [Test] @@ -368,7 +368,7 @@ public void f_must_occur_before_field_VALID() var v = new Validator(); v.EnsureThatValue("parent_dob").OccursBefore("dob"); - Assert.IsNull(v.Validate(TestConstants.ParentDobOccursBeforeDob)); + Assert.That(v.Validate(TestConstants.ParentDobOccursBeforeDob), Is.Null); } [Test] @@ -377,7 +377,7 @@ public void f_must_occur_before_field_INVALID_after() var v = new Validator(); v.EnsureThatValue("parent_dob").OccursBefore("dob"); - Assert.NotNull(v.Validate(TestConstants.ParentDobOccursAfterDob)); + Assert.That(v.Validate(TestConstants.ParentDobOccursAfterDob), Is.Not.Null); } [Test] @@ -386,7 +386,7 @@ public void f_must_occur_before_field_INVALID_same() var v = new Validator(); v.EnsureThatValue("parent_dob").OccursBefore("dob"); - Assert.NotNull(v.Validate(TestConstants.ParentDobOccursOnDob)); + Assert.That(v.Validate(TestConstants.ParentDobOccursOnDob), Is.Not.Null); } #endregion diff --git a/Rdmp.Core.Tests/Validation/Constraints/Primary/BoundsValidationIntegerTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Primary/BoundsValidationIntegerTest.cs index 566f50848e..6dd79a4a2f 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Primary/BoundsValidationIntegerTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Primary/BoundsValidationIntegerTest.cs @@ -30,6 +30,6 @@ public void simple_integer_bounds() var d = new Dictionary { { "number", 119 } }; - Assert.IsNull(v.Validate(d)); + Assert.That(v.Validate(d), Is.Null); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/Constraints/Primary/ChiTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Primary/ChiTest.cs index 8c49152e8a..465f5c5b08 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Primary/ChiTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Primary/ChiTest.cs @@ -33,14 +33,14 @@ protected override void SetUp() [TestCase("02044503731")] public void Validate_InvalidChi_ThrowsException(string code) { - Assert.NotNull(_chi.Validate(code)); + Assert.That(_chi.Validate(code), Is.Not.Null); } [TestCase(null)] [TestCase("0204450373")] public void Validate_ValidChi_Success(string code) { - Assert.IsNull(_chi.Validate(code)); + Assert.That(_chi.Validate(code), Is.Null); } [Test] @@ -48,7 +48,7 @@ public void Validate_InvalidChi_ExceptionContainsRequiredInfo() { var result = _chi.Validate("banana"); - Assert.NotNull(result.SourceConstraint); - Assert.AreEqual(typeof(Chi), result.SourceConstraint.GetType()); + Assert.That(result.SourceConstraint, Is.Not.Null); + Assert.That(result.SourceConstraint.GetType(), Is.EqualTo(typeof(Chi))); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/Constraints/Primary/ChiValidationTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Primary/ChiValidationTest.cs index 995980dbe2..3e09180db4 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Primary/ChiValidationTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Primary/ChiValidationTest.cs @@ -37,7 +37,7 @@ public void validation_scenario_CHI() var domainObject = new Dictionary { { "chi", TestConstants._VALID_CHI } }; // 6. Validate, passing in the target object to be validated against - ValidationFailure or null is returned - Assert.IsNull(validator.Validate(domainObject)); + Assert.That(validator.Validate(domainObject), Is.Null); } [Test] @@ -78,6 +78,6 @@ public void validation_scenario_CHI_and_age() }; // 9. Validate, passing in the target object to be validated against - Assert.IsNull(validator.Validate(domainObject)); + Assert.That(validator.Validate(domainObject), Is.Null); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/Constraints/Primary/DateEuTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Primary/DateEuTest.cs index 263fcf6d5c..b3c7aee341 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Primary/DateEuTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Primary/DateEuTest.cs @@ -36,7 +36,7 @@ protected override void SetUp() [TestCase("19670925")] public void Validate_InvalidDate_ThrowsException(string code) { - Assert.NotNull(_date.Validate(code)); + Assert.That(_date.Validate(code), Is.Not.Null); } [TestCase(null)] @@ -51,7 +51,7 @@ public void Validate_InvalidDate_ThrowsException(string code) [TestCase("5.12.67")] public void Validate_ValidDate_Success(string code) { - Assert.IsNull(_date.Validate(code)); + Assert.That(_date.Validate(code), Is.Null); } [Test] @@ -59,8 +59,8 @@ public void Validate_InvalidDate_ExceptionContainsRequiredInfo() { var result = _date.Validate("banana"); - Assert.NotNull(result.SourceConstraint); - Assert.AreEqual(typeof(Date), result.SourceConstraint.GetType()); + Assert.That(result.SourceConstraint, Is.Not.Null); + Assert.That(result.SourceConstraint.GetType(), Is.EqualTo(typeof(Date))); } // utility methods diff --git a/Rdmp.Core.Tests/Validation/Constraints/Secondary/BoundDateTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Secondary/BoundDateTest.cs index 4c85b2e35c..dbc97e377d 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Secondary/BoundDateTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Secondary/BoundDateTest.cs @@ -26,7 +26,7 @@ public void Validate_IsValid_Succeeds() var result = CallValidateOnValidData("admission_date", b); - Assert.IsNull(result); + Assert.That(result, Is.Null); } [Test] @@ -34,14 +34,14 @@ public void Validate_DateIsSame_Succeeds() { var b = (BoundDate)Validator.CreateConstraint("bounddate", Consequence.Wrong); - Assert.IsTrue(b.Inclusive); + Assert.That(b.Inclusive); var cols = new object[] { DateTime.Parse("2007-10-09 00:00:00.0000000") }; var names = new string[] { "dob2" }; b.LowerFieldName = "dob2"; - Assert.IsNull(b.Validate(DateTime.Parse("2007-10-09 00:00:00.0000000"), cols, names)); + Assert.That(b.Validate(DateTime.Parse("2007-10-09 00:00:00.0000000"), cols, names), Is.Null); } [Test] @@ -52,7 +52,7 @@ public void Validate_IsInvalid_ThrowsException() b.LowerFieldName = "dob"; b.Upper = DateTime.MaxValue; - Assert.NotNull(CallValidateOnInvalidData("admission_date", b)); + Assert.That(CallValidateOnInvalidData("admission_date", b), Is.Not.Null); } @@ -71,8 +71,8 @@ public void Validate_IsInvalid_ThrowsExceptionWithConsequence() Assert.Fail("Expected validation exception, but none came"); - Assert.NotNull(result.SourceConstraint); - Assert.AreEqual(result.SourceConstraint.Consequence, Consequence.InvalidatesRow); + Assert.That(result.SourceConstraint, Is.Not.Null); + Assert.That(result.SourceConstraint.Consequence, Is.EqualTo(Consequence.InvalidatesRow)); } diff --git a/Rdmp.Core.Tests/Validation/Constraints/Secondary/PredictionChiSexTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Secondary/PredictionChiSexTest.cs index ea7ca6ae00..1e4a0c9f5f 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Secondary/PredictionChiSexTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Secondary/PredictionChiSexTest.cs @@ -70,7 +70,7 @@ public void Validate_InconsistentChiAndSex_ThrowsException() var p = new Prediction(new ChiSexPredictor(), "gender"); var otherCols = new object[] { "F" }; var otherColsNames = new string[] { "gender" }; - Assert.NotNull(p.Validate(TestConstants._VALID_CHI, otherCols, otherColsNames)); + Assert.That(p.Validate(TestConstants._VALID_CHI, otherCols, otherColsNames), Is.Not.Null); } [Test] diff --git a/Rdmp.Core.Tests/Validation/Constraints/Secondary/PredictionNotNullTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Secondary/PredictionNotNullTest.cs index 22d1e14156..02376464a0 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Secondary/PredictionNotNullTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Secondary/PredictionNotNullTest.cs @@ -18,7 +18,7 @@ public void Validate_ValueNotNullAndRelatedValueNotNull_Succeeds() var p = new Prediction(new ValuePredictsOtherValueNullity(), "someColumn"); var otherCols = new object[] { "not null" }; var otherColsNames = new string[] { "someColumn" }; - Assert.IsNull(p.Validate("this is not null", otherCols, otherColsNames)); + Assert.That(p.Validate("this is not null", otherCols, otherColsNames), Is.Null); } [Test] @@ -27,7 +27,7 @@ public void Validate_ValueNotNullAndRelatedValueIsNull_ThrowsException() var p = new Prediction(new ValuePredictsOtherValueNullity(), "someColumn"); var otherCols = new object[] { null }; var otherColsNames = new string[] { "someColumn" }; - Assert.NotNull(p.Validate("this is not null", otherCols, otherColsNames)); + Assert.That(p.Validate("this is not null", otherCols, otherColsNames), Is.Not.Null); } [Test] @@ -36,8 +36,7 @@ public void Validate_ValueIsNullAndRelatedValueNotNull_Succeeds() var p = new Prediction(new ValuePredictsOtherValueNullity(), "someColumn"); var otherCols = new object[] { "not null" }; var otherColsNames = new string[] { "someColumn" }; - StringAssert.StartsWith("Nullity did not match, when one value is null, the other mus", - p.Validate(null, otherCols, otherColsNames)?.Message); + Assert.That(p.Validate(null, otherCols, otherColsNames)?.Message, Does.StartWith("Nullity did not match, when one value is null, the other mus")); } [Test] @@ -46,6 +45,6 @@ public void Validate_ValueIsNullAndRelatedValueIsNull_Succeeds() var p = new Prediction(new ValuePredictsOtherValueNullity(), "someColumn"); var otherCols = new object[] { null }; var otherColsNames = new string[] { "someColumn" }; - Assert.IsNull(p.Validate(null, otherCols, otherColsNames)); + Assert.That(p.Validate(null, otherCols, otherColsNames), Is.Null); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/Constraints/Secondary/RegularExpressionTest.cs b/Rdmp.Core.Tests/Validation/Constraints/Secondary/RegularExpressionTest.cs index 69bdab287d..c94fa85beb 100644 --- a/Rdmp.Core.Tests/Validation/Constraints/Secondary/RegularExpressionTest.cs +++ b/Rdmp.Core.Tests/Validation/Constraints/Secondary/RegularExpressionTest.cs @@ -24,31 +24,31 @@ public void SetUp() [Test] public void Validate_NullValue_IsIgnored() { - Assert.IsNull(_regex.Validate(null, null, null)); + Assert.That(_regex.Validate(null, null, null), Is.Null); } [Test] public void Validate_EmpytyValue_Invalid() { - Assert.NotNull(_regex.Validate("", null, null)); + Assert.That(_regex.Validate("", null, null), Is.Not.Null); } [Test] public void Validate_int_Succeeds() { _regex = new RegularExpression("^[0-9]+$"); - Assert.IsNull(_regex.Validate(5, null, null)); + Assert.That(_regex.Validate(5, null, null), Is.Null); } [Test] public void Validate_ValidValue_Valid() { - Assert.IsNull(_regex.Validate("M", null, null)); + Assert.That(_regex.Validate("M", null, null), Is.Null); } [Test] public void Validate_InvalidValue_Invalid() { - Assert.NotNull(_regex.Validate("INVALID", null, null)); + Assert.That(_regex.Validate("INVALID", null, null), Is.Not.Null); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/ExceptionHandlingTests.cs b/Rdmp.Core.Tests/Validation/ExceptionHandlingTests.cs index 09359b56dc..a4e3f42f65 100644 --- a/Rdmp.Core.Tests/Validation/ExceptionHandlingTests.cs +++ b/Rdmp.Core.Tests/Validation/ExceptionHandlingTests.cs @@ -21,7 +21,7 @@ internal class ExceptionHandlingTests public void Validate_WhenMultipleErrors_ReturnsAllErrors() { var validator = new Validator(); - + var chi = new ItemValidator { PrimaryConstraint = (PrimaryConstraint)Validator.CreateConstraint("chi", Consequence.Wrong) @@ -46,6 +46,6 @@ public void Validate_WhenMultipleErrors_ReturnsAllErrors() var result = validator.Validate(row); - Assert.AreEqual(2, result.GetExceptionList().Count); + Assert.That(result.GetExceptionList(), Has.Count.EqualTo(2)); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/ItemValidatorTest.cs b/Rdmp.Core.Tests/Validation/ItemValidatorTest.cs index 30ea0305c4..c1c61b038c 100644 --- a/Rdmp.Core.Tests/Validation/ItemValidatorTest.cs +++ b/Rdmp.Core.Tests/Validation/ItemValidatorTest.cs @@ -40,7 +40,7 @@ public void ValidateAll_IsTypeIncompatible_ThrowsException() _v.PrimaryConstraint = (PrimaryConstraint)Validator.CreateConstraint("chi", Consequence.Wrong); _v.ExpectedType = typeof(int); - Assert.NotNull(_v.ValidateAll(DateTime.Now, Array.Empty(), Array.Empty())); + Assert.That(_v.ValidateAll(DateTime.Now, Array.Empty(), Array.Empty()), Is.Not.Null); } [Test] @@ -51,9 +51,9 @@ public void ValidateAll_IsTypeIncompatible_GivesReason() var result = _v.ValidateAll(DateTime.Now, Array.Empty(), Array.Empty()); - Assert.IsNotNull(result); - Assert.IsTrue(result.Message.StartsWith("Incompatible type")); - Assert.IsTrue(result.Message.Contains(nameof(DateTime))); + Assert.That(result, Is.Not.Null); + Assert.That(result.Message, Does.StartWith("Incompatible type")); + Assert.That(result.Message, Does.Contain(nameof(DateTime))); } [Test] @@ -61,7 +61,7 @@ public void ValidateAll_ValidData_Succeeds() { _v.PrimaryConstraint = new Chi(); - Assert.IsNull(_v.ValidateAll(TestConstants._VALID_CHI, Array.Empty(), Array.Empty())); + Assert.That(_v.ValidateAll(TestConstants._VALID_CHI, Array.Empty(), Array.Empty()), Is.Null); } [Test] @@ -69,8 +69,8 @@ public void ValidateAll_InvalidData_ThrowsException() { _v.PrimaryConstraint = (PrimaryConstraint)Validator.CreateConstraint("chi", Consequence.Wrong); - Assert.NotNull( - _v.ValidateAll(TestConstants._INVALID_CHI_CHECKSUM, Array.Empty(), Array.Empty())); + Assert.That( + _v.ValidateAll(TestConstants._INVALID_CHI_CHECKSUM, Array.Empty(), Array.Empty()), Is.Not.Null); } [Test] @@ -80,6 +80,6 @@ public void ValidateAll_InvalidData_GivesReason() var result = _v.ValidateAll(TestConstants._INVALID_CHI_CHECKSUM, Array.Empty(), Array.Empty()); - Assert.AreEqual("CHI check digit did not match", result.Message); + Assert.That(result.Message, Is.EqualTo("CHI check digit did not match")); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/PredictionValidationTest.cs b/Rdmp.Core.Tests/Validation/PredictionValidationTest.cs index cc9aada06d..a387cbeba3 100644 --- a/Rdmp.Core.Tests/Validation/PredictionValidationTest.cs +++ b/Rdmp.Core.Tests/Validation/PredictionValidationTest.cs @@ -26,14 +26,14 @@ public void Validate_NullTargetField_GeneratesException(string targetField) var v = CreateInitialisedValidator(prediction); var ex = Assert.Throws(() => v.Validate(TestConstants.ValidChiAndInconsistentSex)); - Assert.IsInstanceOf(ex?.InnerException); + Assert.That(ex?.InnerException, Is.InstanceOf()); } [Test] public void Validate_NullRule_GeneratesException() { var ex = Assert.Throws(() => _ = new Prediction(null, "gender")); - StringAssert.Contains("You must specify a PredictionRule to follow", ex?.Message); + Assert.That(ex?.Message, Does.Contain("You must specify a PredictionRule to follow")); } [Test] @@ -54,7 +54,7 @@ public void Validate_UninitializedTarget_GeneratesException() }; var v = CreateInitialisedValidator(prediction); var ex = Assert.Throws(() => v.Validate(TestConstants.ValidChiAndInconsistentSex)); - Assert.IsInstanceOf(ex?.InnerException); + Assert.That(ex?.InnerException, Is.InstanceOf()); } [Test] @@ -78,7 +78,7 @@ public void Validate_ChiHasConsistentSexIndicator_Valid() var prediction = new Prediction(new ChiSexPredictor(), "gender"); var v = CreateInitialisedValidator(prediction); - Assert.IsNull(v.Validate(TestConstants.ValidChiAndConsistentSex)); + Assert.That(v.Validate(TestConstants.ValidChiAndConsistentSex), Is.Null); } [Test] @@ -87,7 +87,7 @@ public void Validate_ChiIsNull_Valid() var prediction = new Prediction(new ChiSexPredictor(), "gender"); var v = CreateInitialisedValidator(prediction); - Assert.IsNull(v.Validate(TestConstants.NullChiAndValidSex)); + Assert.That(v.Validate(TestConstants.NullChiAndValidSex), Is.Null); } [Test] @@ -96,7 +96,7 @@ public void Validate_SexIsNull_Valid() var prediction = new Prediction(new ChiSexPredictor(), "gender"); var v = CreateInitialisedValidator(prediction); - Assert.IsNull(v.Validate(TestConstants.NullChiAndNullSex)); + Assert.That(v.Validate(TestConstants.NullChiAndNullSex), Is.Null); } [Test] @@ -105,7 +105,7 @@ public void Validate_CHIHasInconsistentSexIndicator_Invalid() var prediction = new Prediction(new ChiSexPredictor(), "gender"); var v = CreateInitialisedValidator(prediction); - Assert.NotNull(v.Validate(TestConstants.ValidChiAndInconsistentSex)); + Assert.That(v.Validate(TestConstants.ValidChiAndInconsistentSex), Is.Not.Null); } [Test] @@ -114,7 +114,7 @@ public void Validate_ChiIsInvalid_Invalid() var prediction = new Prediction(new ChiSexPredictor(), "gender"); var v = CreateInitialisedValidator(prediction); - Assert.NotNull(v.Validate(TestConstants.InvalidChiAndValidSex)); + Assert.That(v.Validate(TestConstants.InvalidChiAndValidSex), Is.Not.Null); } #endregion @@ -127,7 +127,7 @@ public void Validate_NoPrimaryConstraintChiHasConsistentSexIndicator_Valid() var prediction = new Prediction(new ChiSexPredictor(), "gender"); var v = CreateInitialisedValidatorWithNoPrimaryConstraint(prediction); - Assert.IsNull(v.Validate(TestConstants.ValidChiAndConsistentSex)); + Assert.That(v.Validate(TestConstants.ValidChiAndConsistentSex), Is.Null); } [Test] @@ -136,7 +136,7 @@ public void Validate_NoPrimaryConstraintChiIsNull_Valid() var prediction = new Prediction(new ChiSexPredictor(), "gender"); var v = CreateInitialisedValidatorWithNoPrimaryConstraint(prediction); - Assert.IsNull(v.Validate(TestConstants.NullChiAndNullSex)); + Assert.That(v.Validate(TestConstants.NullChiAndNullSex), Is.Null); } [Test] @@ -145,7 +145,7 @@ public void Validate_NoPrimaryConstraintCHIHasInconsistentSexIndicator_Invalid() var prediction = new Prediction(new ChiSexPredictor(), "gender"); var v = CreateInitialisedValidatorWithNoPrimaryConstraint(prediction); - Assert.NotNull(v.Validate(TestConstants.ValidChiAndInconsistentSex)); + Assert.That(v.Validate(TestConstants.ValidChiAndInconsistentSex), Is.Not.Null); } [Test] @@ -155,7 +155,7 @@ public void var prediction = new Prediction(new ChiSexPredictor(), "gender"); var v = CreateInitialisedValidatorWithNoPrimaryConstraint(prediction); - Assert.Null(v.Validate(TestConstants.InvalidChiAndValidSex)); + Assert.That(v.Validate(TestConstants.InvalidChiAndValidSex), Is.Null); } #endregion diff --git a/Rdmp.Core.Tests/Validation/ValidationDeserializationMemoryTest.cs b/Rdmp.Core.Tests/Validation/ValidationDeserializationMemoryTest.cs index 047df65165..e64c544c0e 100644 --- a/Rdmp.Core.Tests/Validation/ValidationDeserializationMemoryTest.cs +++ b/Rdmp.Core.Tests/Validation/ValidationDeserializationMemoryTest.cs @@ -37,9 +37,7 @@ public void TestMemoryLeak() var bytesAtEnd = Process.GetCurrentProcess().WorkingSet64; - Assert.Less(bytesAtEnd, bytesAtStart * 2, - "Should not be using double the working memory as many bytes by the end, at start we were using " + - bytesAtStart + " at end we were using " + bytesAtEnd + " (Increase of " + (float)bytesAtEnd / bytesAtStart + - " times)"); + Assert.That(bytesAtEnd, Is.LessThan(bytesAtStart * 2), + $"Should not be using double the working memory as many bytes by the end, at start we were using {bytesAtStart} at end we were using {bytesAtEnd} (Increase of {(float)bytesAtEnd / bytesAtStart} times)"); } } \ No newline at end of file diff --git a/Rdmp.Core.Tests/Validation/ValidationPluginTests/LegacySerializationTest.cs b/Rdmp.Core.Tests/Validation/ValidationPluginTests/LegacySerializationTest.cs index 0664d23ac1..f46ebd072e 100644 --- a/Rdmp.Core.Tests/Validation/ValidationPluginTests/LegacySerializationTest.cs +++ b/Rdmp.Core.Tests/Validation/ValidationPluginTests/LegacySerializationTest.cs @@ -17,7 +17,7 @@ public void TestLegacyDeserialization() { Validator.LocatorForXMLDeserialization = RepositoryLocator; var v = Validator.LoadFromXml(LegacyXML); - Assert.IsNotNull(v); + Assert.That(v, Is.Not.Null); } private const string LegacyXML = @" diff --git a/Rdmp.Core.Tests/Validation/ValidationPluginTests/PluginValidationSerializationTest.cs b/Rdmp.Core.Tests/Validation/ValidationPluginTests/PluginValidationSerializationTest.cs index 71f187344e..9297bf74eb 100644 --- a/Rdmp.Core.Tests/Validation/ValidationPluginTests/PluginValidationSerializationTest.cs +++ b/Rdmp.Core.Tests/Validation/ValidationPluginTests/PluginValidationSerializationTest.cs @@ -23,21 +23,24 @@ public void TestSerialization() PrimaryConstraint = new FishConstraint() }; - //validation should be working - Assert.IsNull(iv.ValidateAll("Fish", Array.Empty(), Array.Empty())); - Assert.IsNotNull(iv.ValidateAll("Potato", Array.Empty(), Array.Empty())); + Assert.Multiple(() => + { + //validation should be working + Assert.That(iv.ValidateAll("Fish", Array.Empty(), Array.Empty()), Is.Null); + Assert.That(iv.ValidateAll("Potato", Array.Empty(), Array.Empty()), Is.Not.Null); + }); v.ItemValidators.Add(iv); - Assert.AreEqual(1, v.ItemValidators.Count); - Assert.AreEqual(typeof(FishConstraint), v.ItemValidators[0].PrimaryConstraint.GetType()); + Assert.That(v.ItemValidators, Has.Count.EqualTo(1)); + Assert.That(v.ItemValidators[0].PrimaryConstraint.GetType(), Is.EqualTo(typeof(FishConstraint))); var xml = v.SaveToXml(); var newV = Validator.LoadFromXml(xml); - Assert.AreEqual(1, newV.ItemValidators.Count); - Assert.AreEqual(typeof(FishConstraint), newV.ItemValidators[0].PrimaryConstraint.GetType()); + Assert.That(newV.ItemValidators, Has.Count.EqualTo(1)); + Assert.That(newV.ItemValidators[0].PrimaryConstraint.GetType(), Is.EqualTo(typeof(FishConstraint))); } } diff --git a/Rdmp.Core.Tests/Validation/ValidatorTest.cs b/Rdmp.Core.Tests/Validation/ValidatorTest.cs index e700c813b6..177d1892b1 100644 --- a/Rdmp.Core.Tests/Validation/ValidatorTest.cs +++ b/Rdmp.Core.Tests/Validation/ValidatorTest.cs @@ -28,7 +28,7 @@ public void Validate_InitialisedState_IsValid() { var validator = new Validator(); - Assert.IsNull(validator.Validate(_domainObjectWithValidChi)); + Assert.That(validator.Validate(_domainObjectWithValidChi), Is.Null); } [Test] @@ -37,7 +37,7 @@ public void GetItemValidator_InitialisedState_ReturnsNullItemValidator() var validator = new Validator(); var itemValidator = validator.GetItemValidator("non-existent"); - Assert.Null(itemValidator); + Assert.That(itemValidator, Is.Null); } [Test] @@ -54,7 +54,7 @@ public void PassValidatorArray_Passes() dr["chi"] = TestConstants._VALID_CHI; //validate the row - Assert.IsNull(v.Validate(dr)); + Assert.That(v.Validate(dr), Is.Null); } [Test] @@ -70,7 +70,7 @@ public void AddItemValidator_DuplicateCalls_ThrowsException() public void RemoveItemValidator_InitialisedState_BehavesAcceptably() { var validator = new Validator(); - Assert.False(validator.RemoveItemValidator("non-existent"), + Assert.That(validator.RemoveItemValidator("non-existent"), Is.False, "Expected removal of a non-existent ItemValidator to return false."); } @@ -80,7 +80,7 @@ public void Validate_NonExistentTargetProperty_ThrowsException() var validator = CreateValidatorForNonExistentProperty(); var ex = Assert.Throws(() => validator.Validate(_domainObjectWithValidChi)); - Assert.AreEqual("Validation failed: Target field [non-existent] not found in domain object.", ex.Message); + Assert.That(ex.Message, Is.EqualTo("Validation failed: Target field [non-existent] not found in domain object.")); } @@ -95,7 +95,7 @@ public void Validate_NonExistentTargetProperty_EmitsMessage() } catch (MissingFieldException exception) { - Assert.True(exception.Message.StartsWith("Validation failed")); + Assert.That(exception.Message, Does.StartWith("Validation failed")); } } @@ -104,7 +104,7 @@ public void Validate_ValidChi_Successful() { var validator = CreateSimpleChiValidator(); - Assert.IsNull(validator.Validate(_domainObjectWithValidChi)); + Assert.That(validator.Validate(_domainObjectWithValidChi), Is.Null); } [Test] @@ -112,7 +112,7 @@ public void Validate_InvalidChi_ThrowsException() { var validator = CreateSimpleChiValidator(); - Assert.NotNull(validator.Validate(_domainObjectWithInvalidChi)); + Assert.That(validator.Validate(_domainObjectWithInvalidChi), Is.Not.Null); } @@ -123,14 +123,14 @@ public void ValidateVerbose_InvalidChi_CountOfWrongIncreases() //run once var results = validator.ValidateVerboseAdditive(_domainObjectWithInvalidChi, null, out _); - Assert.IsNotNull(results); + Assert.That(results, Is.Not.Null); - Assert.AreEqual(results.DictionaryOfFailure["chi"][Consequence.Wrong], 1); + Assert.That(results.DictionaryOfFailure["chi"][Consequence.Wrong], Is.EqualTo(1)); //additive --give it same row again, expect the count of wrong ones to go SetUp by 1 results = validator.ValidateVerboseAdditive(_domainObjectWithInvalidChi, results, out _); - Assert.AreEqual(results.DictionaryOfFailure["chi"][Consequence.Wrong], 2); + Assert.That(results.DictionaryOfFailure["chi"][Consequence.Wrong], Is.EqualTo(2)); } @@ -153,7 +153,7 @@ public void Test_XML_Generation() var answer2 = v2.SaveToXml(false); - Assert.AreEqual(answer, answer2); + Assert.That(answer2, Is.EqualTo(answer)); } @@ -162,7 +162,7 @@ public void Validate_ValidChiAndAge_Successful() { var validator = CreateChiAndAgeValidators(); - Assert.IsNull(validator.Validate(_domainObjectWithValidChiAndAge)); + Assert.That(validator.Validate(_domainObjectWithValidChiAndAge), Is.Null); } [TestCase("chi", typeof(Chi))] @@ -171,8 +171,8 @@ public void CreatePrimaryConstraint_All_IsOfExpectedType(string name, Type expec { var constraint = Validator.CreateConstraint(name, Consequence.Wrong); - Assert.IsInstanceOf(typeof(IPrimaryConstraint), constraint); - Assert.IsInstanceOf(expected, constraint); + Assert.That(constraint, Is.InstanceOf(typeof(IPrimaryConstraint))); + Assert.That(constraint, Is.InstanceOf(expected)); } [TestCase("bounddouble", typeof(BoundDouble))] @@ -183,8 +183,8 @@ public void CreateSecondaryConstraint_All_IsOfExpectedType(string name, Type exp { var constraint = Validator.CreateConstraint(name, Consequence.Wrong); - Assert.IsInstanceOf(typeof(ISecondaryConstraint), constraint); - Assert.IsInstanceOf(expected, constraint); + Assert.That(constraint, Is.InstanceOf(typeof(ISecondaryConstraint))); + Assert.That(constraint, Is.InstanceOf(expected)); } [Test] @@ -206,26 +206,35 @@ public void RenameColumn_ThreeColumns_HasCorrectName() var dictionary = new Dictionary { { "OldCol2", "NewCol2" } }; //before and after rename of col2 - Assert.AreEqual(v.ItemValidators[0].TargetProperty, "OldCol2"); + Assert.That(v.ItemValidators[0].TargetProperty, Is.EqualTo("OldCol2")); v.RenameColumns(dictionary); - Assert.AreEqual(v.ItemValidators[0].TargetProperty, "NewCol2"); - Assert.AreEqual(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).LowerFieldName, "OldCol1"); - Assert.AreEqual(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).UpperFieldName, "OldCol3"); + Assert.Multiple(() => + { + Assert.That(v.ItemValidators[0].TargetProperty, Is.EqualTo("NewCol2")); + Assert.That(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).LowerFieldName, Is.EqualTo("OldCol1")); + Assert.That(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).UpperFieldName, Is.EqualTo("OldCol3")); + }); //now rename col 1 dictionary.Add("OldCol1", "NewCol1"); v.RenameColumns(dictionary); - Assert.AreEqual(v.ItemValidators[0].TargetProperty, "NewCol2"); - Assert.AreEqual(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).LowerFieldName, "NewCol1"); - Assert.AreEqual(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).UpperFieldName, "OldCol3"); + Assert.Multiple(() => + { + Assert.That(v.ItemValidators[0].TargetProperty, Is.EqualTo("NewCol2")); + Assert.That(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).LowerFieldName, Is.EqualTo("NewCol1")); + Assert.That(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).UpperFieldName, Is.EqualTo("OldCol3")); + }); //finally rename col 3 dictionary.Add("OldCol3", "NewCol3"); v.RenameColumns( dictionary); //not strict because we will get not found otherwise since we already renamed the first one - Assert.AreEqual(v.ItemValidators[0].TargetProperty, "NewCol2"); - Assert.AreEqual(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).LowerFieldName, "NewCol1"); - Assert.AreEqual(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).UpperFieldName, "NewCol3"); + Assert.Multiple(() => + { + Assert.That(v.ItemValidators[0].TargetProperty, Is.EqualTo("NewCol2")); + Assert.That(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).LowerFieldName, Is.EqualTo("NewCol1")); + Assert.That(((BoundDate)v.ItemValidators[0].SecondaryConstraints[0]).UpperFieldName, Is.EqualTo("NewCol3")); + }); } // This code is typically how a client of the API would set SetUp validation for a domain object: diff --git a/Rdmp.Core/CohortCommitting/CohortCommitting.md b/Rdmp.Core/CohortCommitting/CohortCommitting.md index a6c57cba1d..70b1ce96c2 100644 --- a/Rdmp.Core/CohortCommitting/CohortCommitting.md +++ b/Rdmp.Core/CohortCommitting/CohortCommitting.md @@ -2,7 +2,7 @@ A Cohort is a collection of unique person identifiers which can be linked against datasets during an extraction. This namespace covers saving a list of identifiers into a cohort database. -See [Cohort Creation](../CohortCreation/Readme.md) for building queries that identify cohorts from your database based on inclusion/exclusion criteria. +See [Cohort Creation](../CohortCreation/CohortCreation.md) for building queries that identify cohorts from your database based on inclusion/exclusion criteria. ## Cohort Storage diff --git a/Rdmp.Core/CohortCommitting/Pipeline/CohortHoldoutLookupRequest.cs b/Rdmp.Core/CohortCommitting/Pipeline/CohortHoldoutLookupRequest.cs new file mode 100644 index 0000000000..d83a53f0db --- /dev/null +++ b/Rdmp.Core/CohortCommitting/Pipeline/CohortHoldoutLookupRequest.cs @@ -0,0 +1,64 @@ +// Copyright (c) The University of Dundee 2018-2019 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using System; +using System.Globalization; +using Rdmp.Core.Curation.Data.Cohort; +using Rdmp.Core.Curation.Data.Pipelines; +using Rdmp.Core.DataFlowPipeline; +using Rdmp.Core.DataFlowPipeline.Requirements; +using Rdmp.Core.MapsDirectlyToDatabaseTable; +using Rdmp.Core.ReusableLibraryCode.Checks; + +namespace Rdmp.Core.CohortCommitting.Pipeline; + +/// +/// All details required to create a holdout set from a cohort +/// +public sealed class CohortHoldoutLookupRequest : PipelineUseCase, ICanBeSummarised, ICohortHoldoutLookupRequest +{ + public CohortIdentificationConfiguration CIC { get; set; } + public int Count { get; set; } + public bool IsPercent { get; set; } + + public string Description { get; set; } + + public string WhereQuery { get; set; } + + public string Name { get; set; } + + public DateTime MinDate { get; set; } + public DateTime MaxDate { get; set; } + public string DateColumnName { get; set; } + public CohortHoldoutLookupRequest(CohortIdentificationConfiguration cic, string name, int count, bool isPercent, string description = "", string minDate = null, string maxDate = null, string dateColumnName = null) + { + CIC = cic; + Name = name; + Count = count; + IsPercent = isPercent; + Description = description; + if (DateTime.TryParseExact(minDate, "DD/MM/YYYY", CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedMinDate)) + MinDate = parsedMinDate; + if (DateTime.TryParseExact(maxDate, "DD/MM/YYYY", CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedMaxDate)) + MaxDate = parsedMaxDate; + DateColumnName = dateColumnName; + AddInitializationObject(this); + } + public string GetSummary(bool includeName, bool includeId) => $"Cohort Holdout: {Name}"; + + + protected override IDataFlowPipelineContext GenerateContextImpl() => + new DataFlowPipelineContext + { + MustHaveDestination = typeof(ICohortPipelineDestination), + MustHaveSource = typeof(IDataFlowSource) + }; + + public void Check(ICheckNotifier notifier) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Rdmp.Core/Repositories/Managers/IPluginManager.cs b/Rdmp.Core/CohortCommitting/Pipeline/ICohortHoldoutLookupRequest.cs similarity index 67% rename from Rdmp.Core/Repositories/Managers/IPluginManager.cs rename to Rdmp.Core/CohortCommitting/Pipeline/ICohortHoldoutLookupRequest.cs index eadba9d719..f3231b14d7 100644 --- a/Rdmp.Core/Repositories/Managers/IPluginManager.cs +++ b/Rdmp.Core/CohortCommitting/Pipeline/ICohortHoldoutLookupRequest.cs @@ -1,17 +1,19 @@ -// Copyright (c) The University of Dundee 2018-2019 +// Copyright (c) The University of Dundee 2018-2023 // This file is part of the Research Data Management Platform (RDMP). // RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. // RDMP 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 General Public License for more details. // You should have received a copy of the GNU General Public License along with RDMP. If not, see . +using Rdmp.Core.Curation.Data.Pipelines; +using Rdmp.Core.ReusableLibraryCode.Checks; -using Rdmp.Core.Curation.Data; +namespace Rdmp.Core.CohortCommitting.Pipeline; -namespace Rdmp.Core.Repositories.Managers; /// -/// Handles high level management of all the loaded in the -/// -public interface IPluginManager +/// See CohortHoldoutLookupRequest +/// +public interface ICohortHoldoutLookupRequest : ICheckable, IPipelineUseCase { - Plugin[] GetCompatiblePlugins(); -} \ No newline at end of file + +} + diff --git a/Rdmp.Core/CohortCommitting/Pipeline/Sources/CohortIdentificationConfigurationSource.cs b/Rdmp.Core/CohortCommitting/Pipeline/Sources/CohortIdentificationConfigurationSource.cs index 5c590e3f5c..7f5485a69a 100644 --- a/Rdmp.Core/CohortCommitting/Pipeline/Sources/CohortIdentificationConfigurationSource.cs +++ b/Rdmp.Core/CohortCommitting/Pipeline/Sources/CohortIdentificationConfigurationSource.cs @@ -8,7 +8,6 @@ using System.Data; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Rdmp.Core.CohortCreation; using Rdmp.Core.CohortCreation.Execution; using Rdmp.Core.Curation.Data; diff --git a/Rdmp.Core/CohortCreation/CohortIdentificationConfigurationUICommon.cs b/Rdmp.Core/CohortCreation/CohortIdentificationConfigurationUICommon.cs index 2a290a0ecd..587de38d50 100644 --- a/Rdmp.Core/CohortCreation/CohortIdentificationConfigurationUICommon.cs +++ b/Rdmp.Core/CohortCreation/CohortIdentificationConfigurationUICommon.cs @@ -30,7 +30,6 @@ public class CohortIdentificationConfigurationUICommon public CohortIdentificationConfiguration Configuration; public ExternalDatabaseServer QueryCachingServer; - private CohortAggregateContainer _root; private CancellationTokenSource _cancelGlobalOperations; private ISqlParameter[] _globals; public CohortCompilerRunner Runner; @@ -145,7 +144,6 @@ public void RecreateAllTasks(bool cancelTasks = true) Configuration.CreateRootContainerIfNotExists(); //if there is no root container,create one - _root = Configuration.RootCohortAggregateContainer; _globals = Configuration.GetAllParameters(); //Could have configured/unconfigured a joinable state @@ -195,7 +193,7 @@ private void StartThisTaskOnly(IMapsDirectlyToDatabaseTable configOrContainer) task = Compiler.AddTask(configOrContainer, _globals); - //Task is now in state NotScheduled so we can start it + //Task is now in state NotScheduled, so we can start it Compiler.LaunchSingleTask(task, Timeout, true); } diff --git a/Rdmp.Core/CohortCreation/Execution/CohortCompiler.cs b/Rdmp.Core/CohortCreation/Execution/CohortCompiler.cs index 0800f7ebf2..65e07113d8 100644 --- a/Rdmp.Core/CohortCreation/Execution/CohortCompiler.cs +++ b/Rdmp.Core/CohortCreation/Execution/CohortCompiler.cs @@ -20,6 +20,7 @@ using Rdmp.Core.Providers; using Rdmp.Core.QueryBuilding; using Rdmp.Core.QueryCaching.Aggregation; +using Rdmp.Core.ReusableLibraryCode.Annotations; using Rdmp.Core.ReusableLibraryCode.Checks; using Rdmp.Core.ReusableLibraryCode.DataAccess; @@ -346,31 +347,23 @@ public ICompileable AddTask(IMapsDirectlyToDatabaseTable runnable, IEnumerable DoTaskAsync(task, execution, timeout, cacheOnCompletion)); Threads.Add(t); diff --git a/Rdmp.Core/CommandExecution/AtomicCommandFactory.cs b/Rdmp.Core/CommandExecution/AtomicCommandFactory.cs index c68e3c7b35..30fb077df2 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommandFactory.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommandFactory.cs @@ -104,7 +104,6 @@ public IEnumerable CreateCommands(object o) OverrideCommandName = "Catalogue SQL/Data", SuggestedCategory = View }; - yield return new ExecuteCommandAddNewCatalogueItem(_activator, c) { Weight = -99.9f, SuggestedCategory = Add, OverrideCommandName = "New Catalogue Item" }; yield return new ExecuteCommandAddNewAggregateGraph(_activator, c) @@ -472,6 +471,8 @@ public IEnumerable CreateCommands(object o) yield return new ExecuteCommandFreezeCohortIdentificationConfiguration(_activator, cic, !cic.Frozen) { Weight = -50.5f }; + yield return new ExecuteCommandCreateHoldoutLookup(_activator, cic) + { Weight = -50.5f }; var clone = new ExecuteCommandCloneCohortIdentificationConfiguration(_activator) { Weight = -50.4f, OverrideCommandName = "Clone" }.SetTarget(cic); @@ -545,6 +546,8 @@ public IEnumerable CreateCommands(object o) lsn.LoadMetadata, lsn.LoadStage); yield return new ExecuteCommandCreateNewFileBasedProcessTask(_activator, ProcessTaskType.Executable, lsn.LoadMetadata, lsn.LoadStage); + yield return new ExecuteCommandCreateNewFileBasedProcessTask(_activator, ProcessTaskType.SQLBakFile, + lsn.LoadMetadata, lsn.LoadStage); } if (Is(o, out LoadDirectoryNode ldn)) diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/CatalogueCreationCommands/ExecuteCommandCreateNewCatalogueByImportingFile.cs b/Rdmp.Core/CommandExecution/AtomicCommands/CatalogueCreationCommands/ExecuteCommandCreateNewCatalogueByImportingFile.cs index 9d91705fca..63fa9bc580 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommands/CatalogueCreationCommands/ExecuteCommandCreateNewCatalogueByImportingFile.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommands/CatalogueCreationCommands/ExecuteCommandCreateNewCatalogueByImportingFile.cs @@ -31,6 +31,8 @@ public class ExecuteCommandCreateNewCatalogueByImportingFile : CatalogueCreation { private readonly DiscoveredDatabase _targetDatabase; private IPipeline _pipeline; + private readonly string _extractionIdentifier; + private readonly string _initialDescription; public FileInfo File { get; private set; } @@ -62,13 +64,17 @@ public ExecuteCommandCreateNewCatalogueByImportingFile(IBasicActivateItems activ "Pipeline for reading the source file, applying any transforms and writing to the database")] Pipeline pipeline, [DemandsInitialization(Desc_ProjectSpecificParameter)] - Project projectSpecific) : base(activator, projectSpecific, null) + Project projectSpecific, + string initialDescription=null) : base(activator, projectSpecific, null) + { File = file; _targetDatabase = targetDatabase; _pipeline = pipeline; + _extractionIdentifier = extractionIdentifier; UseTripleDotSuffix = true; CheckFile(); + _initialDescription = initialDescription; } @@ -150,16 +156,21 @@ private void OnPipelineCompleted(object sender, PipelineEngineEventArgs args, Di var importer = new TableInfoImporter(BasicActivator.RepositoryLocator.CatalogueRepository, tbl); importer.DoImport(out var ti, out _); - - var cata = BasicActivator.CreateAndConfigureCatalogue(ti, null, + var extractionIdentifiers = _extractionIdentifier is null ? null : ti.ColumnInfos.Where(t => t.Name == _extractionIdentifier).ToArray(); + var cata = BasicActivator.CreateAndConfigureCatalogue(ti, extractionIdentifiers, $"Import of file '{File.FullName}' by {Environment.UserName} on {DateTime.Now}", ProjectSpecific, TargetFolder); - if (cata != null) + if (cata == null) return; + + if(_initialDescription is not null) { - Publish(cata); - Emphasise(cata); + cata.Description = _initialDescription; + cata.SaveToDatabase(); } + + Publish(cata); + Emphasise(cata); } public override Image GetImage(IIconProvider iconProvider) => diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandAddPlugins.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandAddPlugins.cs index bb9c01bc2f..280ccd3669 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandAddPlugins.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandAddPlugins.cs @@ -28,19 +28,10 @@ public ExecuteCommandAddPlugins(IBasicActivateItems itemActivator) : base(itemAc public ExecuteCommandAddPlugins(IBasicActivateItems itemActivator, FileCollectionCombineable fileCombineable) : base(itemActivator) { - if (fileCombineable.Files.Any(f => f.Extension != PackPluginRunner.PluginPackageSuffix)) - { - SetImpossible($"Plugins must end {PackPluginRunner.PluginPackageSuffix}"); - return; - } - - var existing = BasicActivator.RepositoryLocator.CatalogueRepository.PluginManager.GetCompatiblePlugins(); - _files = fileCombineable.Files; + if (!_files.Any(static f => f.Extension != PackPluginRunner.PluginPackageSuffix)) return; - var collision = existing.FirstOrDefault(p => _files.Any(f => f.Name.Equals(p.Name))); - if (collision != null) - SetImpossible($"There is already a plugin called '{collision}'"); + SetImpossible($"Plugins must end {PackPluginRunner.PluginPackageSuffix}"); } public override void Execute() @@ -65,11 +56,6 @@ public override void Execute() } Show("Changes will take effect on restart"); - var p = BasicActivator.RepositoryLocator.CatalogueRepository.GetAllObjects() - .FirstOrDefault(); - - if (p != null) - Publish(p); } public override Image GetImage(IIconProvider iconProvider) => diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateDataset.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateDataset.cs new file mode 100644 index 0000000000..c04a7929c8 --- /dev/null +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateDataset.cs @@ -0,0 +1,31 @@ +using Rdmp.Core.Curation.Data; + +namespace Rdmp.Core.CommandExecution.AtomicCommands; + +public class ExecuteCommandCreateDataset : BasicCommandExecution +{ + private readonly string _doi; + private readonly string _name; + private readonly string _source; + private readonly IBasicActivateItems _activator; + + public ExecuteCommandCreateDataset(IBasicActivateItems activator, [DemandsInitialization("The name of the dataset")]string name, string doi = null,string source = null) : base(activator) + { + _name = name; + _doi = doi; + _source = source; + _activator = activator; + + if (string.IsNullOrWhiteSpace(_name)) + SetImpossible("Datasets require a name"); + } + + + public override void Execute() + { + base.Execute(); + var dataset = new Curation.Data.Dataset(BasicActivator.RepositoryLocator.CatalogueRepository, _name) { DigitalObjectIdentifier = _doi, Source = _source }; + dataset.SaveToDatabase(); + _activator.Publish(dataset); + } +} \ No newline at end of file diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateHoldoutLookup.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateHoldoutLookup.cs new file mode 100644 index 0000000000..ded8358da2 --- /dev/null +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateHoldoutLookup.cs @@ -0,0 +1,202 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using FAnsi.Discovery; +using Rdmp.Core.CommandExecution.AtomicCommands.CatalogueCreationCommands; +using Rdmp.Core.Curation.Data.Cohort; +using Rdmp.Core.Curation.Data.Pipelines; +using Rdmp.Core.DataExport.Data; +using Rdmp.Core.DataViewing; +using Rdmp.Core.Icons.IconProvision; +using Rdmp.Core.ReusableLibraryCode.DataAccess; +using Rdmp.Core.ReusableLibraryCode.Icons.IconProvision; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using System; +using System.Data; +using System.IO; +using System.Linq; +using System.Text; + +namespace Rdmp.Core.CommandExecution.AtomicCommands; + +public class ExecuteCommandCreateHoldoutLookup : BasicCommandExecution +{ + private readonly CohortIdentificationConfiguration _cic; + readonly IBasicActivateItems _activator; + private DiscoveredServer _server; + private DataTable _dataTable; + + + public ExecuteCommandCreateHoldoutLookup(IBasicActivateItems activator, + CohortIdentificationConfiguration cic) : base(activator) + { + _cic = cic; + _activator = activator; + } + + public override string GetCommandName() => "Create Holdout"; + + /// + /// Describes in a user friendly way the activity of picking an + /// + /// + private static DialogArgs GetChooseCohortDialogArgs() => + new() + { + WindowTitle = "Choose where to save cohort", + TaskDescription = + "Select the Cohort Database in which to store the identifiers. If you have multiple methods of anonymising cohorts or manage different types of identifiers (e.g. CHI lists, ECHI lists and/or BarcodeIDs) then you must pick the Cohort Database that matches your cohort identifier type/anonymisation protocol.", + EntryLabel = "Select Cohort Database", + AllowAutoSelect = true + }; + + private DataTable LoadDataTable(DiscoveredServer server, string sql) + { + + var dt = new DataTable(); + + try + { + using var con = server.GetConnection(); + con.Open(); + using var cmd = server.GetCommand(sql, con); + cmd.CommandTimeout = 10000; + var adapter = server.GetDataAdapter(cmd); + dt.BeginLoadData(); + adapter.Fill(dt); + dt.EndLoadData(); + con.Close(); + } + catch (Exception e) + { + GlobalError("Unable to access datatable",e); + } + return dt; + + } + + private const string HoldoutShuffle = "_HoldoutShuffle"; + + public override void Execute() + { + base.Execute(); + + SelectOne(GetChooseCohortDialogArgs(), + BasicActivator.RepositoryLocator.DataExportRepository, + out ExternalCohortTable ect); + if (ect is null) + return; + + var holdoutRequest = BasicActivator.GetCohortHoldoutLookupRequest(ect, null, _cic); + if(holdoutRequest is null) + return; + + var cohortConfiguration = new ViewCohortIdentificationConfigurationSqlCollection(_cic); + var sql = cohortConfiguration.GetSql(); + _server = DataAccessPortal + .ExpectServer(cohortConfiguration.GetDataAccessPoint(), DataAccessContext.InternalDataProcessing, false); + _server.TestConnection(); + _dataTable = LoadDataTable(_server, sql); + if(_dataTable.Rows.Count == 0) + { + Show("Unable to Access Cohort"); + return; + } + StringBuilder sb = new(); + + var columnNames = _dataTable.Columns.Cast(). + Select(static column => column.ColumnName); + sb.AppendLine(string.Join(",", columnNames)); + _dataTable.Columns.Add(HoldoutShuffle); + Random rnd = new(); + foreach (DataRow row in _dataTable.Rows) + { + row[HoldoutShuffle] = rnd.Next(); + } + var beforeDate = holdoutRequest.MaxDate; + var afterDate = holdoutRequest.MinDate; + var dateColumn = holdoutRequest.DateColumnName; + var hasMinDate = false; + var hasMaxDate = false; + + + if (columnNames.Contains(dateColumn)) + { + if (beforeDate.Date != DateTime.MinValue) + { + //has max date + hasMaxDate = true; + } + if (afterDate.Date != DateTime.MinValue) + { + //has min date + hasMinDate = true; + } + } + + if (hasMinDate || hasMaxDate) + { + foreach(DataRow row in _dataTable.Rows) + { + if (hasMaxDate && DateTime.Parse(row[dateColumn].ToString()) > beforeDate) { + row.Delete(); + } + else if (hasMinDate && DateTime.Parse(row[dateColumn].ToString()) < afterDate) + { + row.Delete(); + } + } + } + _dataTable.DefaultView.Sort = HoldoutShuffle; + _dataTable = _dataTable.DefaultView.ToTable(); + _dataTable.Columns.Remove(HoldoutShuffle); + var rowCount = holdoutRequest.Count; + var rows = _dataTable.Rows.Cast().Take(rowCount); + if (holdoutRequest.IsPercent) + { + if (rowCount > 100) + { + rowCount = 100; + } + rowCount = (int)Math.Ceiling((float)_dataTable.Rows.Count / 100 * rowCount); + rows = _dataTable.Rows.Cast().Take(rowCount); + } + + var dataRows = rows as DataRow[] ?? rows.ToArray(); + if (!dataRows.Any()) + { + Show("Holdout would be empty with current configuration. Will not create holdout."); + return; + } + + foreach (var row in dataRows) + { + sb.AppendLine(string.Join(",", row.ItemArray.Select(static field => field?.ToString()))); + } + + File.WriteAllText($"{holdoutRequest.Name}.csv", sb.ToString()); + var fi = new FileInfo($"{holdoutRequest.Name}.csv"); + + var columns = _dataTable.Columns.Cast().Select(c=>c.ColumnName).ToList(); + + BasicActivator.SelectObject("Select an Extraction Identifier", columns.ToArray(), out var extractionIdentifier); + if (extractionIdentifier == null) + return; + + var db = SelectDatabase(true, "Select a Database to store the new Holdout."); + if(db == null) return; + + var pipe = _activator.RepositoryLocator.CatalogueRepository.GetAllObjects().OrderByDescending(static p => p.ID) + .FirstOrDefault(static p => p.Name.Contains("BULK INSERT: CSV Import File (automated column-type detection)")); + + var importCommand = new ExecuteCommandCreateNewCatalogueByImportingFile(_activator, fi, extractionIdentifier, db, pipe, null,holdoutRequest.Description); + importCommand.Execute(); + + } + + public override Image GetImage(IIconProvider iconProvider) => iconProvider.GetImage(RDMPConcept.CohortAggregate,OverlayKind.Link); +} diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewFileBasedProcessTask.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewFileBasedProcessTask.cs index 5c620fcb9e..5e8c37474b 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewFileBasedProcessTask.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandCreateNewFileBasedProcessTask.cs @@ -6,6 +6,7 @@ using System; using System.IO; +using System.Linq; using Rdmp.Core.Curation; using Rdmp.Core.Curation.Data.DataLoad; using Rdmp.Core.Icons.IconOverlays; @@ -41,8 +42,9 @@ public ExecuteCommandCreateNewFileBasedProcessTask(IBasicActivateItems activator SetImpossible("Could not construct LoadDirectory"); } - if (taskType is not (ProcessTaskType.SQLFile or ProcessTaskType.Executable)) - SetImpossible("Only SQLFile and Executable task types are supported by this command"); + ProcessTaskType[] AcceptedProcessTaskTypes = { ProcessTaskType.SQLFile, ProcessTaskType.Executable, ProcessTaskType.SQLBakFile }; + if (!AcceptedProcessTaskTypes.Contains(taskType)) + SetImpossible("Only SQLFile, SqlBakFile and Executable task types are supported by this command"); if (!ProcessTask.IsCompatibleStage(taskType, loadStage)) SetImpossible($"You cannot run {taskType} in {loadStage}"); @@ -56,26 +58,37 @@ public override void Execute() if (_file == null) { - if (_taskType == ProcessTaskType.SQLFile) + if (_taskType == ProcessTaskType.SQLBakFile) { - if (BasicActivator.TypeText("Enter a name for the SQL file", "File name", 100, "myscript.sql", - out var selected, false)) - { - var target = Path.Combine(_loadDirectory.ExecutablesPath.FullName, selected); - - if (!target.EndsWith(".sql")) - target += ".sql"; + if (!BasicActivator.TypeText("Enter a name for the SQL Bak file", "File name", 100, "database.bak", + out var selected, false)) return; - //create it if it doesn't exist - if (!File.Exists(target)) - File.WriteAllText(target, "/*todo Type some SQL*/"); + var target = Path.Combine(_loadDirectory.ExecutablesPath.FullName, selected); - _file = new FileInfo(target); - } - else + if (!File.Exists(target)) { - return; //user cancelled + return; //File doesn't exist } + + _file = new FileInfo(target); + + } + else if (_taskType == ProcessTaskType.SQLFile) + { + if (!BasicActivator.TypeText("Enter a name for the SQL file", "File name", 100, "myscript.sql", + out var selected, false)) return; + + var target = Path.Combine(_loadDirectory.ExecutablesPath.FullName, selected); + + if (!target.EndsWith(".sql")) + target += ".sql"; + + //create it if it doesn't exist + if (!File.Exists(target)) + File.WriteAllText(target, "/*todo Type some SQL*/"); + + _file = new FileInfo(target); + } else if (_taskType == ProcessTaskType.Executable) { @@ -117,6 +130,7 @@ public override string GetCommandName() { ProcessTaskType.Executable => "Add Run .exe File Task", ProcessTaskType.SQLFile => "Add Run SQL Script Task", + ProcessTaskType.SQLBakFile => "Add SQL backup File Task", _ => throw new ArgumentOutOfRangeException() }; } @@ -126,6 +140,7 @@ public override Image GetImage(IIconProvider iconProvider) return _taskType switch { ProcessTaskType.SQLFile => iconProvider.GetImage(RDMPConcept.SQL, OverlayKind.Add), + ProcessTaskType.SQLBakFile => iconProvider.GetImage(RDMPConcept.SQL, OverlayKind.Add), //todo maybe better ProcessTaskType.Executable => IconOverlayProvider.GetOverlayNoCache( Image.Load(CatalogueIcons.Exe), OverlayKind.Add), _ => null diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandDeleteDataset.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandDeleteDataset.cs new file mode 100644 index 0000000000..734a81c431 --- /dev/null +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandDeleteDataset.cs @@ -0,0 +1,26 @@ +using Rdmp.Core.Curation.Data; +using System.Linq; + +namespace Rdmp.Core.CommandExecution.AtomicCommands; +public sealed class ExecuteCommandDeleteDataset: BasicCommandExecution +{ + private readonly Curation.Data.Dataset _dataset; + private readonly IBasicActivateItems _activator; +public ExecuteCommandDeleteDataset(IBasicActivateItems activator, [DemandsInitialization("The Dataset to delete")]Curation.Data.Dataset dataset) + { + _dataset = dataset; + _activator = activator; + } + + public override void Execute() + { + base.Execute(); + var columnItemsLinkedToDataset = _activator.RepositoryLocator.CatalogueRepository.GetAllObjects().Where(cif => cif.Dataset_ID == _dataset.ID); + foreach (var col in columnItemsLinkedToDataset) + { + col.Dataset_ID = null; + col.SaveToDatabase(); + } + _dataset.DeleteInDatabase(); + } +} diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandExportDatabaseToDir.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandExportDatabaseToDir.cs new file mode 100644 index 0000000000..eefdba5401 --- /dev/null +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandExportDatabaseToDir.cs @@ -0,0 +1,52 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using Rdmp.Core.Curation.Data; +using Rdmp.Core.Repositories; + +namespace Rdmp.Core.CommandExecution.AtomicCommands; + +// Dump all compatible objects from the current platform database(s) into a +// YAML/JSON directory for SQL-free operation. +public class ExecuteCommandExportDatabaseToDir : BasicCommandExecution +{ + private readonly IBasicActivateItems _activator; + private readonly DirectoryInfo _target; + + public ExecuteCommandExportDatabaseToDir(IBasicActivateItems activator, [DemandsInitialization("Where the platform directory should be created")] string target) + { + _target = new DirectoryInfo(target); + _activator = activator; + } + + private readonly List ignoreList = new() { "Rdmp.Core.DataQualityEngine.Data.DQEGraphAnnotation", "Rdmp.Core.DataQualityEngine.Data.Evaluation" }; + + public override void Execute() + { + base.Execute(); + var repo = new YamlRepository(_target); + foreach (var t in repo.GetCompatibleTypes()) + { + if (ignoreList.Contains(t.FullName)) continue; + try + { + Console.WriteLine(t.FullName); + foreach (var o in _activator.GetRepositoryFor(t).GetAllObjects(t)) + repo.SaveToDatabase(o); + } + catch(Exception) + { + Console.WriteLine($"Unable to find repo for {t.FullName}"); + } + + } + } +} \ No newline at end of file diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandExportPlugins.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandExportPlugins.cs index b60a09538b..5da9b0838b 100644 --- a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandExportPlugins.cs +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandExportPlugins.cs @@ -6,30 +6,25 @@ using System.IO; using System.Linq; +using Rdmp.Core.Curation.Data; using Rdmp.Core.Icons.IconProvision; using Rdmp.Core.Repositories.Construction; +using Rdmp.Core.ReusableLibraryCode.Annotations; using Rdmp.Core.ReusableLibraryCode.Icons.IconProvision; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; namespace Rdmp.Core.CommandExecution.AtomicCommands; -public class ExecuteCommandExportPlugins : BasicCommandExecution +public sealed class ExecuteCommandExportPlugins : BasicCommandExecution { private DirectoryInfo _outDir; - private Curation.Data.Plugin[] _plugins; - - public ExecuteCommandExportPlugins(IBasicActivateItems activator) : this(activator, null) - { - } [UseWithObjectConstructor] - public ExecuteCommandExportPlugins(IBasicActivateItems activator, DirectoryInfo outputDirectory) : base(activator) + public ExecuteCommandExportPlugins(IBasicActivateItems activator, [CanBeNull] DirectoryInfo outputDirectory=null) : base(activator) { _outDir = outputDirectory; - _plugins = BasicActivator.RepositoryLocator.CatalogueRepository.PluginManager.GetCompatiblePlugins(); - - if (!_plugins.Any()) + if (!LoadModuleAssembly.Assemblies.Any()) SetImpossible("There are no compatible plugins (for the version of RDMP you are running)"); } @@ -42,11 +37,10 @@ public override void Execute() base.Execute(); _outDir ??= BasicActivator.SelectDirectory("Output directory"); - if (_outDir == null) return; - foreach (var p in _plugins) - p.LoadModuleAssemblies.FirstOrDefault()?.DownloadAssembly(_outDir); + foreach (var p in LoadModuleAssembly.Assemblies) + p.DownloadAssembly(_outDir); } } \ No newline at end of file diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandLinkCatalogueToDataset.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandLinkCatalogueToDataset.cs new file mode 100644 index 0000000000..683d910a14 --- /dev/null +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandLinkCatalogueToDataset.cs @@ -0,0 +1,49 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using System; +using Rdmp.Core.Curation.Data; +using System.Linq; + +namespace Rdmp.Core.CommandExecution.AtomicCommands; + +public sealed class ExecuteCommandLinkCatalogueToDataset : BasicCommandExecution +{ + private readonly Catalogue _catalogue; + private readonly Curation.Data.Dataset _dataset; + private readonly bool _linkAll; + public ExecuteCommandLinkCatalogueToDataset(IBasicActivateItems activator, [DemandsInitialization("The catalogue To link")]Catalogue catalogue, [DemandsInitialization("The dataset to link to")]Curation.Data.Dataset dataset, bool linkAllOtherColumns = true) : base(activator) + { + _catalogue = catalogue; + _dataset = dataset; + _linkAll = linkAllOtherColumns; + + if (_catalogue is null) SetImpossible("No Catalogue Selected"); + if (_dataset is null) SetImpossible("No Dataset Selected"); + } + + + public override void Execute() + { + base.Execute(); + var items = _catalogue.CatalogueItems.ToList(); + foreach (var ci in items.Select(static item => item.ColumnInfo).Where(ci => ci?.Dataset_ID != _dataset.ID)) + { + ci.Dataset_ID = _dataset.ID; + ci.SaveToDatabase(); + if (!_linkAll) continue; + + var databaseName = ci.Name[..ci.Name.LastIndexOf('.')]; + var catalogueItems = ci.CatalogueRepository.GetAllObjects().Where(ci => ci.Name[..ci.Name.LastIndexOf(".", StringComparison.Ordinal)] == databaseName).ToList(); + foreach (var aci in catalogueItems) + { + aci.Dataset_ID = _dataset.ID; + aci.SaveToDatabase(); + } + } + + } +} \ No newline at end of file diff --git a/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandLinkColumnInfoToDataset.cs b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandLinkColumnInfoToDataset.cs new file mode 100644 index 0000000000..7eac784215 --- /dev/null +++ b/Rdmp.Core/CommandExecution/AtomicCommands/ExecuteCommandLinkColumnInfoToDataset.cs @@ -0,0 +1,41 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using System; +using Rdmp.Core.Curation.Data; +using System.Linq; + +namespace Rdmp.Core.CommandExecution.AtomicCommands; + +public sealed class ExecuteCommandLinkColumnInfoToDataset : BasicCommandExecution +{ + private readonly ColumnInfo _columnInfo; + private readonly Curation.Data.Dataset _dataset; + private readonly bool _linkAll; + public ExecuteCommandLinkColumnInfoToDataset(IBasicActivateItems activator, [DemandsInitialization("The column to link")] ColumnInfo columnInfo, [DemandsInitialization("The dataset to link to")] Curation.Data.Dataset dataset, bool linkAllOtherColumns = true) : base(activator) + { + _columnInfo = columnInfo; + _dataset = dataset; + _linkAll = linkAllOtherColumns; + } + + + public override void Execute() + { + base.Execute(); + _columnInfo.Dataset_ID = _dataset.ID; + _columnInfo.SaveToDatabase(); + if (!_linkAll) return; + + var databaseName = _columnInfo.Name[.._columnInfo.Name.LastIndexOf('.')]; + var catalogueItems = _columnInfo.CatalogueRepository.GetAllObjects().Where(ci => ci.Name[..ci.Name.LastIndexOf(".", StringComparison.Ordinal)] == databaseName); + foreach (var ci in catalogueItems) + { + ci.Dataset_ID = _dataset.ID; + ci.SaveToDatabase(); + } + } +} \ No newline at end of file diff --git a/Rdmp.Core/CommandExecution/BasicActivateItems.cs b/Rdmp.Core/CommandExecution/BasicActivateItems.cs index c7917c0c79..79350d31c7 100644 --- a/Rdmp.Core/CommandExecution/BasicActivateItems.cs +++ b/Rdmp.Core/CommandExecution/BasicActivateItems.cs @@ -664,6 +664,16 @@ public virtual CohortCreationRequest GetCohortCreationRequest(ExternalCohortTabl RepositoryLocator.DataExportRepository, cohortInitialDescription); } + /// + public virtual CohortHoldoutLookupRequest GetCohortHoldoutLookupRequest(ExternalCohortTable externalCohortTable, IProject project, CohortIdentificationConfiguration cic) + { + + if (!TypeText("Name", "Enter name for cohort", 255, null, out var name, false)) + throw new Exception("User chose not to enter a name for the cohort and none was provided"); + + return new CohortHoldoutLookupRequest(cic, "empty", 1,false,"",""); + } + /// public virtual ICatalogue CreateAndConfigureCatalogue(ITableInfo tableInfo, ColumnInfo[] extractionIdentifierColumns, string initialDescription, IProject projectSpecific, diff --git a/Rdmp.Core/CommandExecution/IBasicActivateItems.cs b/Rdmp.Core/CommandExecution/IBasicActivateItems.cs index 08151a4cf8..3c7db33354 100644 --- a/Rdmp.Core/CommandExecution/IBasicActivateItems.cs +++ b/Rdmp.Core/CommandExecution/IBasicActivateItems.cs @@ -173,6 +173,10 @@ public interface IBasicActivateItems CohortCreationRequest GetCohortCreationRequest(ExternalCohortTable externalCohortTable, IProject project, string cohortInitialDescription); + + + CohortHoldoutLookupRequest GetCohortHoldoutLookupRequest(ExternalCohortTable externalCohortTable, IProject project, CohortIdentificationConfiguration cic); + /// /// Show all objects in RDMP (with search). If a single selection is made then invoke the callback /// diff --git a/Rdmp.Core/CommandLine/DatabaseCreation/NightmareDatasets.cs b/Rdmp.Core/CommandLine/DatabaseCreation/NightmareDatasets.cs index 4a295993b0..1e334414b9 100644 --- a/Rdmp.Core/CommandLine/DatabaseCreation/NightmareDatasets.cs +++ b/Rdmp.Core/CommandLine/DatabaseCreation/NightmareDatasets.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.IO; using BadMedicine; using BadMedicine.Datasets; @@ -19,8 +18,6 @@ namespace Rdmp.Core.CommandLine.DatabaseCreation; -[SuppressMessage("Security", "SCS0005:Weak random number generator.", - Justification = "We are generating random metadata, security does not enter into the equation")] internal class NightmareDatasets : DataGenerator { private IRDMPPlatformRepositoryServiceLocator _repos; diff --git a/Rdmp.Core/Curation/ANOEngineering/ForwardEngineerANOCataloguePlanManager.cs b/Rdmp.Core/Curation/ANOEngineering/ForwardEngineerANOCataloguePlanManager.cs index 864c90814e..85a860300a 100644 --- a/Rdmp.Core/Curation/ANOEngineering/ForwardEngineerANOCataloguePlanManager.cs +++ b/Rdmp.Core/Curation/ANOEngineering/ForwardEngineerANOCataloguePlanManager.cs @@ -82,9 +82,10 @@ public ForwardEngineerANOCataloguePlanManager(IRDMPPlatformRepositoryServiceLoca plan.SetToRecommendedPlan(); } - public ColumnInfoANOPlan GetPlanForColumnInfo(ColumnInfo col) => !Plans.ContainsKey(col) - ? throw new Exception($"No plan found for column {col}") - : Plans[col]; + public ColumnInfoANOPlan GetPlanForColumnInfo(ColumnInfo col) => + !Plans.TryGetValue(col, out var anoPlan) + ? throw new Exception($"No plan found for column {col}") + : anoPlan; public IExternalDatabaseServer GetIdentifierDumpServer() => Catalogue.CatalogueRepository.GetDefaultFor(PermissableDefaults.IdentifierDumpServer_ID); diff --git a/Rdmp.Core/Curation/Data/Cache/CacheLagPeriod.cs b/Rdmp.Core/Curation/Data/Cache/CacheLagPeriod.cs index 49f1ff1fc1..97c30945f0 100644 --- a/Rdmp.Core/Curation/Data/Cache/CacheLagPeriod.cs +++ b/Rdmp.Core/Curation/Data/Cache/CacheLagPeriod.cs @@ -10,7 +10,7 @@ namespace Rdmp.Core.Curation.Data.Cache; /// /// Describes the period of time for which data should not be fetched during caching (See ) in Months/Days. This allows for the fact that -/// data in the remote server is unlikley to be real time up to the second accurate and you might need to delay requesting data until it has been collected. +/// data in the remote server is unlikely to be real time up to the second accurate and you might need to delay requesting data until it has been collected. /// /// Serialises to/from simple string representation of duration + type, where type is month (m) or day (d) /// diff --git a/Rdmp.Core/Curation/Data/Catalogue.cs b/Rdmp.Core/Curation/Data/Catalogue.cs index 33def5648b..b55edee631 100644 --- a/Rdmp.Core/Curation/Data/Catalogue.cs +++ b/Rdmp.Core/Curation/Data/Catalogue.cs @@ -100,8 +100,8 @@ public string Acronym } /// - /// The full human readable name of the dataset. This should usually match the name of the underlying but might differ - /// if there are multiple tables powering the Catalogue or they don't have user accessible names. + /// The full human-readable name of the dataset. This should usually match the name of the underlying but might differ + /// if there are multiple tables powering the Catalogue, osr they don't have user accessible names. /// [Unique] [NotNull] diff --git a/Rdmp.Core/Curation/Data/Cohort/CohortAggregateContainer.cs b/Rdmp.Core/Curation/Data/Cohort/CohortAggregateContainer.cs index a013010c2d..757778a3ec 100644 --- a/Rdmp.Core/Curation/Data/Cohort/CohortAggregateContainer.cs +++ b/Rdmp.Core/Curation/Data/Cohort/CohortAggregateContainer.cs @@ -328,12 +328,12 @@ public CohortAggregateContainer CloneEntireTreeRecursively(ICheckNotifier notifi foreach (var j in usedJoins) { //for some reason the CohortIdentificationConfiguration didn't properly clone the joinable permission or didn't add it to the dictionary - if (!parentToCloneJoinablesDictionary.ContainsKey(j.JoinableCohortAggregateConfiguration)) + if (!parentToCloneJoinablesDictionary.TryGetValue(j.JoinableCohortAggregateConfiguration, out var + cloneJoinable)) throw new KeyNotFoundException( $"Configuration {configClone} uses Patient Index Table {j.AggregateConfiguration} but our dictionary did not have the key, why was that joinable not cloned?"); //we do have a clone copy of the joinable permission, set the clone aggregate - var cloneJoinable = parentToCloneJoinablesDictionary[j.JoinableCohortAggregateConfiguration]; var cloneJoinUse = cloneJoinable.AddUser(configClone); cloneJoinUse.JoinType = j.JoinType; diff --git a/Rdmp.Core/Curation/Data/ColumnInfo.cs b/Rdmp.Core/Curation/Data/ColumnInfo.cs index 7012eca9ec..c0f192138f 100644 --- a/Rdmp.Core/Curation/Data/ColumnInfo.cs +++ b/Rdmp.Core/Curation/Data/ColumnInfo.cs @@ -297,6 +297,18 @@ public ColumnInfo(ICatalogueRepository repository, string name, string type, ITa ClearAllInjections(); } + private int? _datasetID; + /// + /// The ID of the dataset this column information came from + /// + [DoNotExtractProperty] + public int? Dataset_ID + { + get => _datasetID; + set => SetField(ref _datasetID, value); + } + + internal ColumnInfo(ICatalogueRepository repository, DbDataReader r) : base(repository, r) { @@ -309,6 +321,8 @@ internal ColumnInfo(ICatalogueRepository repository, DbDataReader r) Description = r["Description"].ToString(); Collation = r["Collation"] as string; IgnoreInLoads = ObjectToNullableBool(r["IgnoreInLoads"]) ?? false; + if (r["Dataset_ID"] != DBNull.Value) + Dataset_ID = int.Parse(r["Dataset_ID"].ToString()); //try to turn string value in database into enum value if (Enum.TryParse(r["Status"].ToString(), out ColumnStatus dbStatus)) diff --git a/Rdmp.Core/Curation/Data/CommitInProgress.cs b/Rdmp.Core/Curation/Data/CommitInProgress.cs index 246e08f050..0496ebc179 100644 --- a/Rdmp.Core/Curation/Data/CommitInProgress.cs +++ b/Rdmp.Core/Curation/Data/CommitInProgress.cs @@ -97,16 +97,16 @@ private void Deleting(object sender, IMapsDirectlyToDatabaseTableEventArgs e) if (!Settings.UseTransactions) return; // one of the objects we are tracking has been deleted - if (originalStates.ContainsKey(e.Object)) + if (originalStates.TryGetValue(e.Object, out var inProgress)) { // change our understanding of this object - if (originalStates[e.Object].Type == MementoType.Add) + if (inProgress.Type == MementoType.Add) // ok user created this object during the commit then deleted it again... odd but fair enough // pretend it never existed originalStates.Remove(e.Object); else - originalStates[e.Object].Type = MementoType.Delete; + inProgress.Type = MementoType.Delete; } else { diff --git a/Rdmp.Core/Curation/Data/Dashboarding/PersistStringHelper.cs b/Rdmp.Core/Curation/Data/Dashboarding/PersistStringHelper.cs index cec26d8bf2..3853f2ac7e 100644 --- a/Rdmp.Core/Curation/Data/Dashboarding/PersistStringHelper.cs +++ b/Rdmp.Core/Curation/Data/Dashboarding/PersistStringHelper.cs @@ -12,6 +12,7 @@ using System.Xml.Linq; using Rdmp.Core.MapsDirectlyToDatabaseTable; using Rdmp.Core.Repositories; +using Rdmp.Core.ReusableLibraryCode.Annotations; namespace Rdmp.Core.Curation.Data.Dashboarding; @@ -194,6 +195,6 @@ public static string GetExtraText(string persistString) => !persistString.Contai /// /// /// - public static bool GetBool(Dictionary dict, string key, bool valueIfMissing) => - dict == null || !dict.ContainsKey(key) ? valueIfMissing : bool.Parse(dict[key]); + public static bool GetBool([CanBeNull] Dictionary dict, string key, bool valueIfMissing) => + dict?.TryGetValue(key,out var value)!=true ? valueIfMissing : bool.Parse(value); } \ No newline at end of file diff --git a/Rdmp.Core/Curation/Data/DataLoad/ProcessTask.cs b/Rdmp.Core/Curation/Data/DataLoad/ProcessTask.cs index ddf64cbcb8..27bc25e7a7 100644 --- a/Rdmp.Core/Curation/Data/DataLoad/ProcessTask.cs +++ b/Rdmp.Core/Curation/Data/DataLoad/ProcessTask.cs @@ -198,7 +198,9 @@ public void Check(ICheckNotifier notifier) case ProcessTaskType.SQLFile: CheckFileExistenceAndUniqueness(notifier); CheckForProblemsInSQLFile(notifier); - + break; + case ProcessTaskType.SQLBakFile: + CheckFileExistenceAndUniqueness(notifier); break; case ProcessTaskType.Attacher: break; @@ -374,6 +376,7 @@ public static bool IsCompatibleStage(ProcessTaskType type, LoadStage stage) { ProcessTaskType.Executable => true, ProcessTaskType.SQLFile => stage != LoadStage.GetFiles, + ProcessTaskType.SQLBakFile => stage != LoadStage.GetFiles, ProcessTaskType.Attacher => stage == LoadStage.Mounting, ProcessTaskType.DataProvider => true, ProcessTaskType.MutilateDataTable => stage != LoadStage.GetFiles, diff --git a/Rdmp.Core/Curation/Data/DataLoad/ProcessTaskType.cs b/Rdmp.Core/Curation/Data/DataLoad/ProcessTaskType.cs index d6a71be158..93d1383198 100644 --- a/Rdmp.Core/Curation/Data/DataLoad/ProcessTaskType.cs +++ b/Rdmp.Core/Curation/Data/DataLoad/ProcessTaskType.cs @@ -22,6 +22,11 @@ public enum ProcessTaskType /// SQLFile, + /// + /// ProcessTask is to import a SQL backup file directly to the server + /// + SQLBakFile, + /// /// ProcessTask is to instantiate the IAttacher class Type specified in Path and hydrate its [DemandsInitialization] properties with values matching /// ProcessTaskArguments and run it in the specified load stage in an AttacherRuntimeTask wrapper. diff --git a/Rdmp.Core/Curation/Data/Dataset.cs b/Rdmp.Core/Curation/Data/Dataset.cs new file mode 100644 index 0000000000..aac0df9eae --- /dev/null +++ b/Rdmp.Core/Curation/Data/Dataset.cs @@ -0,0 +1,79 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see .using Amazon.Auth.AccessControlPolicy; + +using Rdmp.Core.MapsDirectlyToDatabaseTable.Attributes; +using Rdmp.Core.Repositories; +using System; +using System.Collections.Generic; +using System.Data.Common; +using Rdmp.Core.MapsDirectlyToDatabaseTable; +using System.Diagnostics.CodeAnalysis; + +namespace Rdmp.Core.Curation.Data; + +/// + +public sealed class Dataset : DatabaseEntity, IDataset, IHasFolder +{ + private string _name; + private string _digitalObjectIdentifier; + private string _source; + private string _folder = FolderHelper.Root; + + /// + [DoNotImportDescriptions] + [UsefulProperty] + public string Folder + { + get => _folder; + set => SetField(ref _folder, FolderHelper.Adjust(value)); + } + + [Unique] + [NotNull] + public string Name + { + get => _name; + set => SetField(ref _name, value); + } + + [Unique] + public string DigitalObjectIdentifier + { + get => _digitalObjectIdentifier; + set => SetField(ref _digitalObjectIdentifier, value); + } + + public string Source + { + get => _source; + set => SetField(ref _source, value); + } + + public override string ToString() => Name; + + + public Dataset(ICatalogueRepository catalogueRepository, string name) + { + catalogueRepository.InsertAndHydrate(this, new Dictionary + { + {"Name", name }, + {"Folder", _folder } + }); + } + + public Dataset() { } + internal Dataset(ICatalogueRepository repository, DbDataReader r) + : base(repository, r) + { + Name = r["Name"].ToString(); + Folder = r["Folder"].ToString(); + if (r["DigitalObjectIdentifier"] != DBNull.Value) + DigitalObjectIdentifier = r["DigitalObjectIdentifier"].ToString(); + if (r["Source"] != DBNull.Value) + Source = r["Source"].ToString(); + } +} \ No newline at end of file diff --git a/Rdmp.Core/Curation/Data/EntityNaming/SuffixBasedNamer.cs b/Rdmp.Core/Curation/Data/EntityNaming/SuffixBasedNamer.cs index f4cb235a2e..d6d4ceafb9 100644 --- a/Rdmp.Core/Curation/Data/EntityNaming/SuffixBasedNamer.cs +++ b/Rdmp.Core/Curation/Data/EntityNaming/SuffixBasedNamer.cs @@ -37,7 +37,6 @@ public virtual string GetDatabaseName(string rootDatabaseName, LoadBubble stage) /// public virtual string GetName(string tableName, LoadBubble convention) => - !Suffixes.ContainsKey(convention) - ? throw new ArgumentException($"Do not have a suffix for convention: {convention}") - : tableName + Suffixes[convention]; + !Suffixes.TryGetValue(convention, out var s) ? throw new ArgumentException($"Do not have a suffix for convention: {convention}") + : $"{tableName}{s}"; } \ No newline at end of file diff --git a/Rdmp.Core/Curation/Data/ExternalDatabaseServer.cs b/Rdmp.Core/Curation/Data/ExternalDatabaseServer.cs index bd0270f441..4f5241b6f2 100644 --- a/Rdmp.Core/Curation/Data/ExternalDatabaseServer.cs +++ b/Rdmp.Core/Curation/Data/ExternalDatabaseServer.cs @@ -37,7 +37,7 @@ public class ExternalDatabaseServer : DatabaseEntity, IExternalDatabaseServer, I private readonly SelfCertifyingDataAccessPoint _selfCertifyingDataAccessPoint; /// - /// Human readable name for the server e.g. 'My Favourite Logging Database' + /// Human-readable name for the server e.g. 'My Favourite Logging Database' /// [Unique] [NotNull] @@ -271,7 +271,7 @@ public bool DiscoverExistence(DataAccessContext context, out string reason) => public override void DeleteInDatabase() { - + if (WasCreatedBy(new LoggingDatabasePatcher())){ //If you're trying to delete a logging server, remove all references to it first var catalogues = Repository.GetAllObjectsWhere("LiveLoggingServer_ID",base.ID); diff --git a/Rdmp.Core/Curation/Data/ExtractionFilterParameterSet.cs b/Rdmp.Core/Curation/Data/ExtractionFilterParameterSet.cs index 9b4d980122..d4f33e40e5 100644 --- a/Rdmp.Core/Curation/Data/ExtractionFilterParameterSet.cs +++ b/Rdmp.Core/Curation/Data/ExtractionFilterParameterSet.cs @@ -16,7 +16,7 @@ namespace Rdmp.Core.Curation.Data; /// /// Often an ExtractionFilter will have a parameter associated with it (or more than one). In this case it can be that you want to curate various values and give them -/// meaningful titles. For exmaple if you have a filter 'Hospitalised with condition X' which has parameter @ConditionList. Then you decide that you want to curate +/// meaningful titles. For example if you have a filter 'Hospitalised with condition X' which has parameter @ConditionList. Then you decide that you want to curate /// a list 'A101.23,B21.1' as 'People hospitalised with drug dependency'. This 'known meaningful parameter values set' is called a ExtractionFilterParameterSet. You /// can provide a name and a description for the concept. Then you create a value for each parameter in the associated filter. See ExtractionFilterParameterSetValue for /// the value recordings. @@ -38,7 +38,7 @@ public string Name } /// - /// Human readable description of what the parameter set identifies e.g. 'Diabetes Drugs' and any supporting information about how it works, quirks etc + /// Human-readable description of what the parameter set identifies e.g. 'Diabetes Drugs' and any supporting information about how it works, quirks etc /// public string Description { diff --git a/Rdmp.Core/Curation/Data/IDataset.cs b/Rdmp.Core/Curation/Data/IDataset.cs new file mode 100644 index 0000000000..a7853f2994 --- /dev/null +++ b/Rdmp.Core/Curation/Data/IDataset.cs @@ -0,0 +1,25 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using Rdmp.Core.MapsDirectlyToDatabaseTable; +using Rdmp.Core.Repositories; + +namespace Rdmp.Core.Curation.Data; + +/// +/// The core of datasets within RDMP. +/// Simple objects to link up catalogue data to DOI and datasets +/// +public interface IDataset: IMapsDirectlyToDatabaseTable +{ + /// + /// Returns where the object exists (e.g. database) as or null if the object does not exist in a catalogue repository. + /// + ICatalogueRepository CatalogueRepository { get; } + + string Name { get; } + string DigitalObjectIdentifier { get; } +} diff --git a/Rdmp.Core/Curation/Data/LoadModuleAssembly.cs b/Rdmp.Core/Curation/Data/LoadModuleAssembly.cs index 772daa0f69..07c00a752b 100644 --- a/Rdmp.Core/Curation/Data/LoadModuleAssembly.cs +++ b/Rdmp.Core/Curation/Data/LoadModuleAssembly.cs @@ -6,133 +6,41 @@ using System; using System.Collections.Generic; -using System.Data.Common; using System.IO; using System.Linq; -using System.Threading; using ICSharpCode.SharpZipLib.Zip; -using Rdmp.Core.CommandLine.Runners; -using Rdmp.Core.Curation.Data.ImportExport; -using Rdmp.Core.Curation.Data.Serialization; -using Rdmp.Core.MapsDirectlyToDatabaseTable; -using Rdmp.Core.MapsDirectlyToDatabaseTable.Attributes; -using Rdmp.Core.MapsDirectlyToDatabaseTable.Injection; -using Rdmp.Core.Repositories; -using YamlDotNet.Serialization; namespace Rdmp.Core.Curation.Data; /// -/// This entity stores the large binary blob for the class. The can be written to disk -/// as a nuget file which can be loaded at runtime to add plugin functionality for rdmp. +/// This entity wraps references to plugin .nupkg files on disk. /// -public class LoadModuleAssembly : DatabaseEntity, IInjectKnown +public sealed class LoadModuleAssembly { - #region Database Properties + internal static readonly List Assemblies=new(); + private readonly FileInfo _file; - private byte[] _bin; - private string _committer; - private DateTime _uploadDate; - private int _plugin_ID; - private Lazy _knownPlugin; - - - /// - /// The assembly (dll) file as a Byte[], use File.WriteAllBytes to write it to disk - /// - [YamlIgnore] - public byte[] Bin - { - get => _bin; - set => SetField(ref _bin, value); - } - - /// - /// The user who uploaded the dll - /// - public string Committer + private LoadModuleAssembly(FileInfo file) { - get => _committer; - set => SetField(ref _committer, value); + _file = file; } /// - /// The date the dll was uploaded + /// Unpack the plugin DLL files, excluding any Windows UI specific dlls when not running a Windows GUI /// - public DateTime UploadDate + internal static IEnumerable> GetContents(string path) { - get => _uploadDate; - set => SetField(ref _uploadDate, value); - } - - /// - /// The plugin this file forms a part of (each will usually have multiple dlls as part of its dependencies) - /// - [Relationship(typeof(Plugin), RelationshipType.SharedObject)] - public int Plugin_ID - { - get => _plugin_ID; - set => SetField(ref _plugin_ID, value); - } - - #endregion - - #region Relationships - - /// - [NoMappingToDatabase] - public Plugin Plugin => _knownPlugin.Value; + var info = new FileInfo(path); + if (!info.Exists || info.Length < 100) yield break; // Ignore missing or empty files - #endregion + var pluginStream = info.OpenRead(); + Assemblies.Add(new LoadModuleAssembly(info)); - public LoadModuleAssembly() - { - ClearAllInjections(); - } - - /// - /// Uploads the given dll file to the catalogue database ready for use as a plugin within RDMP (also uploads any pdb file in the same dir) - /// - /// - /// - /// - public LoadModuleAssembly(ICatalogueRepository repository, FileInfo f, Plugin plugin) - { - var dictionaryParameters = GetDictionaryParameters(f, plugin); - - //so we can reference it in fetch requests to check for duplication (normally Repository is set during hydration by the repo) - Repository = repository; - - Repository.InsertAndHydrate(this, dictionaryParameters); - ClearAllInjections(); - } - - internal LoadModuleAssembly(ICatalogueRepository repository, DbDataReader r) - : base(repository, r) - { - Bin = r["Bin"] as byte[]; - Committer = r["Committer"] as string; - UploadDate = Convert.ToDateTime(r["UploadDate"]); - Plugin_ID = Convert.ToInt32(r["Plugin_ID"]); - ClearAllInjections(); - } - - internal LoadModuleAssembly(ShareManager shareManager, ShareDefinition shareDefinition) - { - shareManager.UpsertAndHydrate(this, shareDefinition); - ClearAllInjections(); - } - - /// - /// Unpack the plugin DLL files, excluding any Windows specific dlls when not running on Windows - /// - internal static IEnumerable> GetContents(Stream pluginStream) - { var isWin = AppDomain.CurrentDomain.GetAssemblies() .Any(static a => a.FullName?.StartsWith("Rdmp.UI", StringComparison.Ordinal) == true); if (!pluginStream.CanSeek) - throw new ArgumentException("Seek needed", nameof(pluginStream)); + throw new ArgumentException("Seek needed", nameof(path)); using var zip = new ZipFile(pluginStream); foreach (var e in zip.Cast() @@ -148,86 +56,18 @@ internal static IEnumerable> GetContents(Stream } /// - /// Unpack the plugin DLL files, excluding any Windows specific dlls when not running on Windows - /// - internal IEnumerable> GetContents() - { - using var ms = new MemoryStream(Bin); - return GetContents(ms); - } - - /// - /// Downloads the plugin nupkg to the given directory + /// Copy the plugin nupkg to the given directory /// /// public string DownloadAssembly(DirectoryInfo downloadDirectory) { - var targetDirectory = downloadDirectory.FullName ?? - throw new Exception("Could not get currently executing assembly directory"); if (!downloadDirectory.Exists) downloadDirectory.Create(); - - var targetFile = Path.Combine(targetDirectory, Plugin.Name); - - //file already exists - if (File.Exists(targetFile)) - if (AreEqual(File.ReadAllBytes(targetFile), Bin)) - return targetFile; - - var timeout = 5000; - - TryAgain: - try - { - //if it has changed length or does not exist, write it out to the disk - File.WriteAllBytes(targetFile, Bin); - } - catch (Exception) - { - timeout -= 100; - Thread.Sleep(100); - - if (timeout <= 0) - throw; - - goto TryAgain; - } - + var targetFile=Path.Combine(downloadDirectory.FullName, _file.Name); + _file.CopyTo(targetFile,true); return targetFile; } - private static Dictionary GetDictionaryParameters(FileInfo f, Plugin plugin) - { - if (f.Extension != PackPluginRunner.PluginPackageSuffix) - throw new Exception($"Expected LoadModuleAssembly file to be a {PackPluginRunner.PluginPackageSuffix}"); - - var allBytes = File.ReadAllBytes(f.FullName); - - var dictionaryParameters = new Dictionary - { - { "Bin", allBytes }, - { "Committer", Environment.UserName }, - { "Plugin_ID", plugin.ID } - }; - - return dictionaryParameters; - } - - private static bool AreEqual(byte[] readAllBytes, byte[] dll) - { - return readAllBytes.Length == dll.Length && !dll.Where((t, i) => !readAllBytes[i].Equals(t)).Any(); - } - - public void InjectKnown(Plugin instance) - { - _knownPlugin = new Lazy(instance); - } - - /// - public override string ToString() => $"LoadModuleAssembly_{ID}"; - - public void ClearAllInjections() - { - _knownPlugin = new Lazy(() => Repository.GetObjectByID(Plugin_ID)); - } + public void Delete() => _file.Delete(); + public override string ToString() => _file.Name; } \ No newline at end of file diff --git a/Rdmp.Core/Curation/Data/Pipelines/IDataFlowPipelineEngine.cs b/Rdmp.Core/Curation/Data/Pipelines/IDataFlowPipelineEngine.cs index f253a0f5be..ed19aa462c 100644 --- a/Rdmp.Core/Curation/Data/Pipelines/IDataFlowPipelineEngine.cs +++ b/Rdmp.Core/Curation/Data/Pipelines/IDataFlowPipelineEngine.cs @@ -4,7 +4,9 @@ // RDMP 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 General Public License for more details. // You should have received a copy of the GNU General Public License along with RDMP. If not, see . +using System; using System.Collections.Generic; +using Rdmp.Core.CommandExecution; using Rdmp.Core.DataFlowPipeline; using Rdmp.Core.ReusableLibraryCode.Checks; @@ -31,8 +33,9 @@ public interface IDataFlowPipelineEngine : ICheckable /// Runs the source GetChunk once and passes it down through the other components to the destination /// /// + /// /// - bool ExecuteSinglePass(GracefulCancellationToken cancellationToken); + bool ExecuteSinglePass(GracefulCancellationToken cancellationToken, List> completionUIAlerts = null); /// /// Components can declare IPipelineRequirement, calling this method will PreInitialize all components with compatible IPipelineRequirements with the values diff --git a/Rdmp.Core/Curation/Data/Plugin.cs b/Rdmp.Core/Curation/Data/Plugin.cs index 1df5bc517d..bcfad6d350 100644 --- a/Rdmp.Core/Curation/Data/Plugin.cs +++ b/Rdmp.Core/Curation/Data/Plugin.cs @@ -4,15 +4,6 @@ // RDMP 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 General Public License for more details. // You should have received a copy of the GNU General Public License along with RDMP. If not, see . -using System; -using System.Collections.Generic; -using System.Data.Common; -using System.IO; -using System.Text.RegularExpressions; -using Rdmp.Core.Curation.Data.ImportExport; -using Rdmp.Core.Curation.Data.Serialization; -using Rdmp.Core.MapsDirectlyToDatabaseTable; -using Rdmp.Core.Repositories; using Rdmp.Core.ReusableLibraryCode.Annotations; namespace Rdmp.Core.Curation.Data; @@ -22,149 +13,13 @@ namespace Rdmp.Core.Curation.Data; /// stored in the RDMP platform databases and written to disk/loaded when executed by the RDMP client - this ensures that all users run the same /// version of the Plugin(s). /// -public class Plugin : DatabaseEntity, INamed +public class Plugin { #region Database Properties - private string _name; - private string _uploadedFromDirectory; - private Version _pluginVersion; - private Version _rdmpVersion; - /// [NotNull] - public string Name - { - get => _name; - set => SetField(ref _name, value); - } - - /// - /// Where the plugin files were uploaded from - /// - public string UploadedFromDirectory - { - get => _uploadedFromDirectory; - set => SetField(ref _uploadedFromDirectory, value); - } - - - /// - /// Returns without the verison e.g. "Rdmp.Dicom" from an ambigious name: - /// Rdmp.Dicom.0.0.1.nupkg - /// Rdmp.Dicom.nupkg - /// Rdmp.Dicom - /// - /// - public string GetShortName() - { - var regexSuffix = new Regex(@"(\.\d*)*(\.nupkg)?$"); - return regexSuffix.Replace(Name, ""); - } - - /// - /// The master version of the - /// Not currently used - /// - public Version PluginVersion - { - get => _pluginVersion; - set => SetField(ref _pluginVersion, value); - } - - /// - /// The version of RDMP which the plugin is compatible with. This is determined by looking at the dependencies tag in - /// the nuspec file of the nupkg being uploaded. - /// - public Version RdmpVersion - { - get => _rdmpVersion; - set => SetField(ref _rdmpVersion, value); - } - - #endregion - - public Plugin() - { - } - - /// - /// Defines a new collection of dlls that provide plugin functionality for RDMP - /// - /// - /// - /// - /// - public Plugin(ICatalogueRepository repository, FileInfo pluginZipFile, Version pluginVersion, Version rdmpVersion) - { - repository.InsertAndHydrate(this, new Dictionary - { - { "Name", pluginZipFile.Name }, - { "UploadedFromDirectory", pluginZipFile.DirectoryName }, - { "PluginVersion", pluginVersion ?? new Version(0, 0, 0, 0) }, - { "RdmpVersion", rdmpVersion ?? new Version(0, 0, 0, 0) } - }); - } - - internal Plugin(ICatalogueRepository repository, DbDataReader r) : base(repository, r) - { - Name = r["Name"].ToString(); - UploadedFromDirectory = r["UploadedFromDirectory"].ToString(); - - try - { - PluginVersion = new Version((string)r["PluginVersion"]); - } - catch (ArgumentException) - { - PluginVersion = - new Version( - "0.0.0.0"); //user hacked database and typed in 'I've got a lovely bunch of coconuts' into the version field? - } - - try - { - RdmpVersion = new Version((string)r["RdmpVersion"]); - } - catch (ArgumentException) - { - RdmpVersion = - new Version( - "0.0.0.0"); //user hacked database and typed in 'I've got a lovely bunch of coconuts' into the version field? - } - } - - internal Plugin(ShareManager shareManager, ShareDefinition shareDefinition) - { - shareManager.UpsertAndHydrate(this, shareDefinition); - } - - /// - public override string ToString() => Name; - - #region Relationships - - /// - /// Gets all the dlls and source code(if available) stored as in the catalogue database - /// - [NoMappingToDatabase] - public IEnumerable LoadModuleAssemblies => - Repository.GetAllObjectsWithParent(this); + public string Name { get; } #endregion - - /// - /// Returns a folder name suitable for storing the dlls for the plugin in as a subdirectory of - /// - /// - /// - /// - public string GetPluginDirectoryName(DirectoryInfo downloadDirectoryRoot) - { - var pluginName = Path.GetFileNameWithoutExtension(Name); - - return string.IsNullOrWhiteSpace(pluginName) - ? throw new Exception("Plugin doesn't have a valid name") - : Path.Combine(downloadDirectoryRoot.FullName, pluginName); - } } \ No newline at end of file diff --git a/Rdmp.Core/Curation/Data/TableInfo.cs b/Rdmp.Core/Curation/Data/TableInfo.cs index d7be2614b3..0b6498ea08 100644 --- a/Rdmp.Core/Curation/Data/TableInfo.cs +++ b/Rdmp.Core/Curation/Data/TableInfo.cs @@ -260,7 +260,7 @@ public string GetFullyQualifiedName() => public string GetDatabaseRuntimeName(LoadStage loadStage, INameDatabasesAndTablesDuringLoads namer = null) { var baseName = GetDatabaseRuntimeName(); - + namer ??= new FixedStagingDatabaseNamer(baseName); return namer.GetDatabaseName(baseName, loadStage.ToLoadBubble()); diff --git a/Rdmp.Core/DataExport/DataExtraction/Pipeline/SimpleFileExtractor.cs b/Rdmp.Core/DataExport/DataExtraction/Pipeline/SimpleFileExtractor.cs index 7a27ed4971..7b31947518 100644 --- a/Rdmp.Core/DataExport/DataExtraction/Pipeline/SimpleFileExtractor.cs +++ b/Rdmp.Core/DataExport/DataExtraction/Pipeline/SimpleFileExtractor.cs @@ -68,7 +68,7 @@ public override void Check(ICheckNotifier notifier) new CheckEventArgs($"PerPatient is true but Pattern {Pattern} did not contain token $p", CheckResult.Fail)); - if (!PerPatient && Pattern.IndexOf("$p", StringComparison.Ordinal) != -1) + if (!PerPatient && Pattern.Contains("$p")) notifier.OnCheckPerformed(new CheckEventArgs( $"PerPatient is false but Pattern {Pattern} contains token $p. This token will never be matched in MoveAll mode", CheckResult.Fail)); diff --git a/Rdmp.Core/DataExport/DataExtraction/Pipeline/Sources/ExecuteDatasetExtractionSource.cs b/Rdmp.Core/DataExport/DataExtraction/Pipeline/Sources/ExecuteDatasetExtractionSource.cs index 9eb1489763..b823562fd2 100644 --- a/Rdmp.Core/DataExport/DataExtraction/Pipeline/Sources/ExecuteDatasetExtractionSource.cs +++ b/Rdmp.Core/DataExport/DataExtraction/Pipeline/Sources/ExecuteDatasetExtractionSource.cs @@ -208,8 +208,12 @@ public virtual DataTable GetChunk(IDataLoadEventListener listener, GracefulCance { chunk = _hostedSource.GetChunk(listener, cancellationToken); + chunk = _peeker.AddPeekedRowsIfAny(chunk); + if (Request != null && Request.DatasetBundle.DataSet is not null && chunk is not null) + chunk.TableName = $"{Request.DatasetBundle.DataSet}"; + //if we are trying to distinct the records in memory based on release id if (DistinctStrategy == DistinctStrategy.OrderByAndDistinctInMemory) { @@ -556,10 +560,9 @@ public virtual DataTable TryGetPreview() //get up to 1000 records da.Fill(0, 1000, toReturn); - toReturn.EndLoadData(); + toReturn.EndLoadData(); con.Close(); - toReturn.EndLoadData(); return toReturn; } diff --git a/Rdmp.Core/DataFlowPipeline/DataFlowPipelineEngine.cs b/Rdmp.Core/DataFlowPipeline/DataFlowPipelineEngine.cs index 29b6fe86cc..3fcb9e4b82 100644 --- a/Rdmp.Core/DataFlowPipeline/DataFlowPipelineEngine.cs +++ b/Rdmp.Core/DataFlowPipeline/DataFlowPipelineEngine.cs @@ -9,6 +9,8 @@ using System.Collections.ObjectModel; using System.Data; using System.Linq; +using System.Threading; +using Rdmp.Core.CommandExecution; using Rdmp.Core.Curation.Data.Pipelines; using Rdmp.Core.DataFlowPipeline.Requirements; using Rdmp.Core.ReusableLibraryCode.Checks; @@ -91,6 +93,20 @@ public void Initialize(params object[] initializationObjects) initialized = true; } + private void UIAlert(string alert, IBasicActivateItems activator) + { + if (!activator.IsInteractive) return; + + new Thread(() => + { + // run as a separate thread to not halt the UI + activator.Show(alert); + }) + { + IsBackground = true + }.Start(); + } + /// public void ExecutePipeline(GracefulCancellationToken cancellationToken) { @@ -104,8 +120,9 @@ public void ExecutePipeline(GracefulCancellationToken cancellationToken) "Engine has not been initialized, call Initialize(DataFlowPipelineContext context, params object[] initializationObjects"); var hasMoreData = true; + List> uiAlerts = new(); while (!cancellationToken.IsCancellationRequested && hasMoreData) - hasMoreData = ExecuteSinglePass(cancellationToken); + hasMoreData = ExecuteSinglePass(cancellationToken, uiAlerts); if (cancellationToken.IsAbortRequested) { @@ -120,6 +137,8 @@ public void ExecutePipeline(GracefulCancellationToken cancellationToken) new NotifyEventArgs(ProgressEventType.Information, "Pipeline engine aborted")); return; } + foreach (var alert in uiAlerts.Distinct().Where(static alert => alert is not null)) + UIAlert(alert.Item1, alert.Item2); } catch (Exception e) { @@ -139,7 +158,7 @@ public void ExecutePipeline(GracefulCancellationToken cancellationToken) } catch (Exception e) { - //dispose crashing is only a dealbreaker if there wasn't already an exception in the pipeline + //dispose crashing is only a deal-breaker if there wasn't already an exception in the pipeline if (exception == null) throw; @@ -157,7 +176,7 @@ public void ExecutePipeline(GracefulCancellationToken cancellationToken) } catch (Exception e) { - //dispose crashing is only a dealbreaker if there wasn't already an exception in the pipeline + //dispose crashing is only a deal-breaker if there wasn't already an exception in the pipeline if (exception == null) throw; @@ -187,7 +206,7 @@ public void ExecutePipeline(GracefulCancellationToken cancellationToken) } /// - public bool ExecuteSinglePass(GracefulCancellationToken cancellationToken) + public bool ExecuteSinglePass(GracefulCancellationToken cancellationToken, List> completionUIAlerts = null) { if (!initialized) throw new Exception( @@ -207,7 +226,6 @@ public bool ExecuteSinglePass(GracefulCancellationToken cancellationToken) throw new InvalidOperationException( $"Error when attempting to get a chunk from the source component: {Source}", e); } - if (currentChunk == null) { _listener.OnNotify(this, @@ -216,25 +234,35 @@ public bool ExecuteSinglePass(GracefulCancellationToken cancellationToken) return false; } - foreach (var component in Components) - { - if (cancellationToken.IsAbortRequested) break; - currentChunk = component.ProcessPipelineData(currentChunk, _listener, cancellationToken); - } + try { + foreach (var component in Components) + { + if (cancellationToken.IsAbortRequested) break; - if (cancellationToken.IsAbortRequested) return true; - Destination.ProcessPipelineData(currentChunk, _listener, cancellationToken); + currentChunk = component.ProcessPipelineData(currentChunk, _listener, cancellationToken); + if (completionUIAlerts is not null && currentChunk is DataTable dt) + { + var uiAlert = (Tuple)dt.ExtendedProperties["AlertUIAtEndOfProcess"]; + completionUIAlerts.Add(uiAlert); + } + } - if (cancellationToken.IsAbortRequested) return true; + if (cancellationToken.IsAbortRequested) return true; - //if it is a DataTable call .Clear() because Dispose doesn't actually free up any memory - if (typeof(DataTable).IsAssignableFrom(typeof(T))) - ((DataTable)(object)currentChunk).Clear(); + Destination.ProcessPipelineData(currentChunk, _listener, cancellationToken); - - //if the chunk is something that can be disposed, dispose it (e.g. DataTable - to free up memory) - if (typeof(IDisposable).IsAssignableFrom(typeof(T))) - ((IDisposable)currentChunk).Dispose(); + if (cancellationToken.IsAbortRequested) return true; + } + finally { + //if it is a DataTable call .Clear() because Dispose doesn't actually free up any memory + if (currentChunk is DataTable dt2) + dt2.Clear(); + + //if the chunk is something that can be disposed, dispose it (e.g. DataTable - to free up memory) + if (currentChunk is IDisposable junk) + #pragma warning disable + junk.Dispose(); + } return true; } diff --git a/Rdmp.Core/DataLoad/Engine/LoadExecution/Components/Runtime/ExecuteSqlBakFileRuntimeTask.cs b/Rdmp.Core/DataLoad/Engine/LoadExecution/Components/Runtime/ExecuteSqlBakFileRuntimeTask.cs new file mode 100644 index 0000000000..cdc24bd766 --- /dev/null +++ b/Rdmp.Core/DataLoad/Engine/LoadExecution/Components/Runtime/ExecuteSqlBakFileRuntimeTask.cs @@ -0,0 +1,124 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using System; +using System.Data; +using System.IO; +using Microsoft.Data.SqlClient; +using Rdmp.Core.Curation.Data.DataLoad; +using Rdmp.Core.DataFlowPipeline; +using Rdmp.Core.DataLoad.Engine.Job; +using Rdmp.Core.DataLoad.Engine.LoadExecution.Components.Arguments; +using Rdmp.Core.ReusableLibraryCode.Checks; +using Rdmp.Core.ReusableLibraryCode.Progress; + +namespace Rdmp.Core.DataLoad.Engine.LoadExecution.Components.Runtime; + +/// +/// RuntimeTask that executes a single .bak file specified by the user in a ProcessTask with ProcessTaskType SQLBakFile. +/// +public class ExecuteSqlBakFileRuntimeTask : RuntimeTask +{ + public string Filepath; + private readonly IProcessTask _task; + + private LoadStage _loadStage; + + public ExecuteSqlBakFileRuntimeTask(IProcessTask task, RuntimeArgumentCollection args) : base(task, args) + { + _task = task; + Filepath = task.Path; + } + + public override ExitCodeType Run(IDataLoadJob job, GracefulCancellationToken cancellationToken) + { + var db = RuntimeArguments.StageSpecificArguments.DbInfo; + _loadStage = RuntimeArguments.StageSpecificArguments.LoadStage; + + if (!Exists()) + throw new Exception($"The sql bak file {Filepath} does not exist"); + + var fileOnlyCommand = $"RESTORE FILELISTONLY FROM DISK = '{Filepath}'"; + using var fileInfo = new DataTable(); + using var con = (SqlConnection)db.Server.GetConnection(); + using (var cmd = new SqlCommand(fileOnlyCommand, con)) + using (var da = new SqlDataAdapter(cmd)) + da.Fill(fileInfo); + var primaryFiles = fileInfo.Select("Type = 'D'"); + var logFiles = fileInfo.Select("Type = 'L'"); + if (primaryFiles.Length != 1 || logFiles.Length != 1) + { + //Something has gone wrong + return ExitCodeType.Error; + } + + + var primaryFile = primaryFiles[0]; + var logFile = logFiles[0]; + var primaryFilePhysicalName = primaryFile["PhysicalName"].ToString(); + var logFilePhysicalName = logFile["PhysicalName"].ToString(); + + if (File.Exists(primaryFilePhysicalName) || File.Exists(logFilePhysicalName)) + { + var timestamp = DateTime.Now.Millisecond.ToString(); + var primaryFileName = primaryFilePhysicalName[..^4]; + var primaryFileExtension = primaryFilePhysicalName[^4..]; + primaryFilePhysicalName = $"{primaryFileName}_{timestamp}{primaryFileExtension}"; + var logFileName = logFilePhysicalName[..^4]; + var logFileExtension = logFilePhysicalName[^4..]; + logFilePhysicalName = $"{logFileName}_{timestamp}{logFileExtension}"; + } + + var name = db.ToString(); + + var restoreCommand = @$" + use master; + ALTER DATABASE {name} SET SINGLE_USER WITH ROLLBACK IMMEDIATE; + RESTORE DATABASE {name} + FROM DISK = '{Filepath}' + WITH MOVE '{primaryFile["LogicalName"]}' TO '{primaryFilePhysicalName}', + MOVE '{logFile["LogicalName"]}' TO '{logFilePhysicalName}' , NOUNLOAD, REPLACE, STATS = 5; + ALTER DATABASE {name} SET MULTI_USER; + "; + + job.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, + $"Executing script {Filepath} ( against {db})")); + + var executer = new ExecuteSqlInDleStage(job, _loadStage); + return executer.Execute(restoreCommand, db); + } + + + public override bool Exists() => File.Exists(Filepath); + + public override void Abort(IDataLoadEventListener postLoadEventListener) + { + } + + public override void LoadCompletedSoDispose(ExitCodeType exitCode, IDataLoadEventListener postLoadEventListener) + { + } + + public override void Check(ICheckNotifier notifier) + { + if (string.IsNullOrWhiteSpace(Filepath)) + { + notifier.OnCheckPerformed( + new CheckEventArgs($"ExecuteSqlFileTask {_task} does not have a path specified", + CheckResult.Fail)); + return; + } + + if (!File.Exists(Filepath)) + notifier.OnCheckPerformed( + new CheckEventArgs( + $"File '{Filepath}' does not exist! (the only time this would be legal is if you have an exe or a freaky plugin that creates this file)", + CheckResult.Warning)); + else + notifier.OnCheckPerformed(new CheckEventArgs($"Found File '{Filepath}'", + CheckResult.Success)); + } +} \ No newline at end of file diff --git a/Rdmp.Core/DataLoad/Engine/LoadExecution/Components/Runtime/RuntimeTaskFactory.cs b/Rdmp.Core/DataLoad/Engine/LoadExecution/Components/Runtime/RuntimeTaskFactory.cs index 44b8db0d62..c3b356fdcf 100644 --- a/Rdmp.Core/DataLoad/Engine/LoadExecution/Components/Runtime/RuntimeTaskFactory.cs +++ b/Rdmp.Core/DataLoad/Engine/LoadExecution/Components/Runtime/RuntimeTaskFactory.cs @@ -35,6 +35,7 @@ public static RuntimeTask Create(IProcessTask task, IStageArgs stageArgs) ProcessTaskType.Attacher => new AttacherRuntimeTask(task, args), ProcessTaskType.DataProvider => new DataProviderRuntimeTask(task, args), ProcessTaskType.MutilateDataTable => new MutilateDataTablesRuntimeTask(task, args), + ProcessTaskType.SQLBakFile => new ExecuteSqlBakFileRuntimeTask(task, args), _ => throw new Exception($"Cannot create runtime task: Unknown process task type '{task.ProcessTaskType}'") }; } diff --git a/Rdmp.Core/DataLoad/Engine/Pipeline/Destinations/SqlBulkInsertDestination.cs b/Rdmp.Core/DataLoad/Engine/Pipeline/Destinations/SqlBulkInsertDestination.cs index a3ebe9ac4b..2f115af40e 100644 --- a/Rdmp.Core/DataLoad/Engine/Pipeline/Destinations/SqlBulkInsertDestination.cs +++ b/Rdmp.Core/DataLoad/Engine/Pipeline/Destinations/SqlBulkInsertDestination.cs @@ -152,7 +152,7 @@ public void Abort(IDataLoadEventListener listener) } private bool _isDisposed = false; - + private void CloseConnection(IDataLoadEventListener listener) { diff --git a/Rdmp.Core/DataLoad/Modules/Attachers/FixedWidthFormatFile.cs b/Rdmp.Core/DataLoad/Modules/Attachers/FixedWidthFormatFile.cs index 34e3866b04..64f06178ea 100644 --- a/Rdmp.Core/DataLoad/Modules/Attachers/FixedWidthFormatFile.cs +++ b/Rdmp.Core/DataLoad/Modules/Attachers/FixedWidthFormatFile.cs @@ -77,7 +77,7 @@ public FixedWidthFormatFile(FileInfo pathToFormatFile) public DataTable GetDataTableFromFlatFile(FileInfo f) { //setup the table - DataTable toReturn = new DataTable(); + var toReturn = new DataTable(); toReturn.BeginLoadData(); foreach (var fixedWidthColumn in FormatColumns) diff --git a/Rdmp.Core/DataLoad/Modules/DataFlowOperations/CohortSampler.cs b/Rdmp.Core/DataLoad/Modules/DataFlowOperations/CohortSampler.cs index 7f7b902e33..58ad558d25 100644 --- a/Rdmp.Core/DataLoad/Modules/DataFlowOperations/CohortSampler.cs +++ b/Rdmp.Core/DataLoad/Modules/DataFlowOperations/CohortSampler.cs @@ -98,11 +98,7 @@ public DataTable ProcessPipelineData(DataTable toProcess, IDataLoadEventListener // first order the values e.g. alphabetically so that even if the input is in a different order our // seeded random picks the same values. Se test TestCohortSampler_Repeatability_OrderIrrelevant var sorted = uniques.OrderBy(u => u); - -#pragma warning disable SCS0005 // Weak random number generator. var chosen = sorted.OrderBy(v => r.Next()).Take(SampleSize).ToList(); -#pragma warning restore SCS0005 // Weak random number generator. - if (chosen.Count < SampleSize && FailIfNotEnoughIdentifiers) throw new Exception( $"Cohort only contains {chosen.Count} unique identifiers. This is less than the requested sample size of {SampleSize} and {nameof(FailIfNotEnoughIdentifiers)} is true"); diff --git a/Rdmp.Core/DataLoad/Modules/DataFlowSources/ExcelDataFlowSource.cs b/Rdmp.Core/DataLoad/Modules/DataFlowSources/ExcelDataFlowSource.cs index 34ff3248d1..53d458e17b 100644 --- a/Rdmp.Core/DataLoad/Modules/DataFlowSources/ExcelDataFlowSource.cs +++ b/Rdmp.Core/DataLoad/Modules/DataFlowSources/ExcelDataFlowSource.cs @@ -21,6 +21,7 @@ using Rdmp.Core.DataFlowPipeline; using Rdmp.Core.DataFlowPipeline.Requirements; using Rdmp.Core.DataLoad.Modules.Exceptions; +using Rdmp.Core.ReusableLibraryCode.Annotations; using Rdmp.Core.ReusableLibraryCode.Checks; using Rdmp.Core.ReusableLibraryCode.Progress; @@ -198,7 +199,7 @@ public DataTable GetAllData(ISheet worksheet, IDataLoadEventListener listener) /// The cell whose value you want to retrieve /// Leave blank, used in recursion for dealing with Formula cells /// - private object GetCellValue(ICell cell, CellType treatAs = CellType.Unknown) + private object GetCellValue([CanBeNull] ICell cell, CellType treatAs = CellType.Unknown) { if (cell == null) return null; @@ -218,8 +219,8 @@ private object GetCellValue(ICell cell, CellType treatAs = CellType.Unknown) //some numerics are actually dates/times if (cell.CellStyle.DataFormat == 0) return cell.NumericCellValue; + var format = cell.CellStyle.GetDataFormatString(); - var f = new NumberFormat(format); if (IsDateWithoutTime(format)) return cell.DateCellValue.ToString("yyyy-MM-dd"); @@ -230,19 +231,17 @@ private object GetCellValue(ICell cell, CellType treatAs = CellType.Unknown) if (IsTimeWithoutDate(format)) return cell.DateCellValue.ToString("HH:mm:ss"); - return IsDateFormat(format) - ? f.Format(cell.DateCellValue, CultureInfo.InvariantCulture) - : f.Format(cell.NumericCellValue, CultureInfo.InvariantCulture); + return new NumberFormat(format).Format( + IsDateFormat(format) ? cell.DateCellValue : cell.NumericCellValue, CultureInfo.InvariantCulture); case CellType.String: - var v = cell.StringCellValue; - //if it is blank or 'null' then leave it null - if (string.IsNullOrWhiteSpace(v) || v.Trim().Equals("NULL", StringComparison.CurrentCultureIgnoreCase)) - return null; + return string.IsNullOrWhiteSpace(cell.StringCellValue) || + cell.StringCellValue.Trim().Equals("NULL", StringComparison.CurrentCultureIgnoreCase) + ? null + : cell.StringCellValue; - return cell.StringCellValue; case CellType.Formula: return GetCellValue(cell, cell.CachedFormulaResultType); case CellType.Blank: @@ -252,7 +251,7 @@ private object GetCellValue(ICell cell, CellType treatAs = CellType.Unknown) case CellType.Error: return null; default: - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(treatAs)); } } diff --git a/Rdmp.Core/DataLoad/Modules/FTP/FTPDownloader.cs b/Rdmp.Core/DataLoad/Modules/FTP/FTPDownloader.cs index 06a8fb5a30..c90631e536 100644 --- a/Rdmp.Core/DataLoad/Modules/FTP/FTPDownloader.cs +++ b/Rdmp.Core/DataLoad/Modules/FTP/FTPDownloader.cs @@ -4,17 +4,18 @@ // RDMP 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 General Public License for more details. // You should have received a copy of the GNU General Public License along with RDMP. If not, see . +#nullable enable + using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; -using System.Text; using System.Text.RegularExpressions; +using System.Threading; using FAnsi.Discovery; +using FluentFTP; using Rdmp.Core.Curation; using Rdmp.Core.Curation.Data; using Rdmp.Core.DataFlowPipeline; @@ -29,18 +30,18 @@ namespace Rdmp.Core.DataLoad.Modules.FTP; /// load component which downloads files from a remote FTP server to the ForLoading directory /// /// Attempts to connect to the FTP server and download all files in the landing folder of the FTP (make sure you really want everything in the -/// root folder - if not then configure redirection on the FTP so you land in the correct directory). Files are downloaded into the ForLoading folder +/// root folder - if not then configure redirection on the FTP, so you land in the correct directory). Files are downloaded into the ForLoading folder /// public class FTPDownloader : IPluginDataProvider { - protected string _host; - protected string _username; - protected string _password; - - private bool _useSSL = false; + private readonly Lazy _connection; + protected readonly List _filesRetrieved = new(); + private ILoadDirectory? _directory; - protected List _filesRetrieved = new(); - private ILoadDirectory _directory; + public FTPDownloader() + { + _connection = new Lazy(SetupFtp, LazyThreadSafetyMode.ExecutionAndPublication); + } [DemandsInitialization( "Determines the behaviour of the system when no files are found on the server. If true the entire data load process immediately stops with exit code LoadNotRequired, if false then the load proceeds as normal (useful if for example if you have multiple Attachers and some files are optional)")] @@ -48,7 +49,7 @@ public class FTPDownloader : IPluginDataProvider [DemandsInitialization( "The Regex expression to validate files on the FTP server against, only files matching the expression will be downloaded")] - public Regex FilePattern { get; set; } + public Regex? FilePattern { get; set; } [DemandsInitialization("The timeout to use when connecting to the FTP server in SECONDS")] public int TimeoutInSeconds { get; set; } @@ -60,10 +61,10 @@ public class FTPDownloader : IPluginDataProvider [DemandsInitialization( "The FTP server to connect to. Server should be specified with only IP:Port e.g. 127.0.0.1:20. You do not have to specify ftp:// at the start", Mandatory = true)] - public ExternalDatabaseServer FTPServer { get; set; } + public ExternalDatabaseServer? FTPServer { get; set; } [DemandsInitialization("The directory on the FTP server that you want to download files from")] - public string RemoteDirectory { get; set; } + public string? RemoteDirectory { get; set; } [DemandsInitialization("True to set keep alive", DefaultValue = true)] public bool KeepAlive { get; set; } @@ -76,38 +77,25 @@ public void Initialize(ILoadDirectory directory, DiscoveredDatabase dbInfo) public ExitCodeType Fetch(IDataLoadJob job, GracefulCancellationToken cancellationToken) { - SetupFTP(); - return DownloadFilesOnFTP(_directory, job); - } - - public static string GetDescription() => "See Description attribute of class"; - - public static IDataProvider Clone() => new FTPDownloader(); - - public bool Validate(ILoadDirectory destination) - { - SetupFTP(); - return GetFileList().Any(); + return DownloadFilesOnFTP(_directory ?? throw new InvalidOperationException("No output directory set"), job); } - private void SetupFTP() + private FtpClient SetupFtp() { - _host = FTPServer.Server; - _username = FTPServer.Username ?? "anonymous"; - _password = string.IsNullOrWhiteSpace(FTPServer.Password) ? "guest" : FTPServer.GetDecryptedPassword(); - - if (string.IsNullOrWhiteSpace(_host)) - throw new NullReferenceException( - $"FTPServer is not set up correctly it must have Server property filled in{FTPServer}"); + var host = FTPServer?.Server ?? throw new NullReferenceException("FTP server not set"); + var username = FTPServer.Username ?? "anonymous"; + var password = string.IsNullOrWhiteSpace(FTPServer.Password) ? "guest" : FTPServer.GetDecryptedPassword(); + var c = new FtpClient(host, username, password); + c.AutoConnect(); + return c; } private ExitCodeType DownloadFilesOnFTP(ILoadDirectory destination, IDataLoadEventListener listener) { - var files = GetFileList(); + var files = GetFileList().ToArray(); - listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, files.Aggregate( - "Identified the following files on the FTP server:", (s, f) => - $"{f},").TrimEnd(','))); + listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, + $"Identified the following files on the FTP server:{string.Join(',',files)}")); var forLoadingContainedCachedFiles = false; @@ -117,28 +105,29 @@ private ExitCodeType DownloadFilesOnFTP(ILoadDirectory destination, IDataLoadEve listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"File {file} was evaluated as {action}")); - if (action == SkipReason.DoNotSkip) + + switch (action) { - listener.OnNotify(this, - new NotifyEventArgs(ProgressEventType.Information, $"About to download {file}")); - Download(file, destination, listener); + case SkipReason.DoNotSkip: + listener.OnNotify(this, + new NotifyEventArgs(ProgressEventType.Information, $"About to download {file}")); + Download(file, destination); + break; + case SkipReason.InForLoading: + forLoadingContainedCachedFiles = true; + break; } - - if (action == SkipReason.InForLoading) - forLoadingContainedCachedFiles = true; } - //if no files were downloaded (and there were none skiped because they were in forLoading) and in that eventuality we have our flag set to return LoadNotRequired then do so - if (!forLoadingContainedCachedFiles && !_filesRetrieved.Any() && SendLoadNotRequiredIfFileNotFound) - { - listener.OnNotify(this, - new NotifyEventArgs(ProgressEventType.Information, - "Could not find any files on the remote server worth downloading, so returning LoadNotRequired")); - return ExitCodeType.OperationNotRequired; - } + // it was a success - even if no files were actually retrieved... hey that's what the user said, otherwise he would have set SendLoadNotRequiredIfFileNotFound + if (forLoadingContainedCachedFiles || _filesRetrieved.Any() || !SendLoadNotRequiredIfFileNotFound) + return ExitCodeType.Success; - //otherwise it was a success - even if no files were actually retrieved... hey that's what the user said, otherwise he would have set SendLoadNotRequiredIfFileNotFound - return ExitCodeType.Success; + // if no files were downloaded (and there were none skipped because they were in forLoading) and in that eventuality we have our flag set to return LoadNotRequired then do so + listener.OnNotify(this, + new NotifyEventArgs(ProgressEventType.Information, + "Could not find any files on the remote server worth downloading, so returning LoadNotRequired")); + return ExitCodeType.OperationNotRequired; } protected enum SkipReason @@ -151,145 +140,43 @@ protected enum SkipReason protected SkipReason GetSkipActionForFile(string file, ILoadDirectory destination) { - if (file.StartsWith(".")) + if (file.StartsWith(".",StringComparison.Ordinal)) return SkipReason.IsImaginaryFile; //if there is a regex pattern - if (FilePattern != null) - if (!FilePattern.IsMatch(file)) //and it does not match - return SkipReason.DidNotMatchPattern; //skip because it did not match pattern + if (FilePattern?.IsMatch(file) == false) //and it does not match + return SkipReason.DidNotMatchPattern; //skip because it did not match pattern //if the file on the FTP already exists in the forLoading directory, skip it return destination.ForLoading.GetFiles(file).Any() ? SkipReason.InForLoading : SkipReason.DoNotSkip; } - private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, - SslPolicyErrors sslpolicyerrors) => true; //any cert will do! yay + private static bool ValidateServerCertificate(object _1, X509Certificate _2, X509Chain _3, + SslPolicyErrors _4) => true; //any cert will do! yay - protected virtual string[] GetFileList() + protected virtual IEnumerable GetFileList() { - var result = new StringBuilder(); - WebResponse response = null; - StreamReader reader = null; - try - { - var uri = !string.IsNullOrWhiteSpace(RemoteDirectory) - ? $"ftp://{_host}/{RemoteDirectory}" - : $"ftp://{_host}"; - -#pragma warning disable SYSLIB0014 // Type or member is obsolete - var reqFTP = (FtpWebRequest)WebRequest.Create(new Uri(uri)); -#pragma warning restore SYSLIB0014 // Type or member is obsolete - reqFTP.UseBinary = true; - reqFTP.Credentials = new NetworkCredential(_username, _password); - reqFTP.Method = WebRequestMethods.Ftp.ListDirectory; - reqFTP.Timeout = TimeoutInSeconds * 1000; - reqFTP.KeepAlive = KeepAlive; - - reqFTP.Proxy = null; - reqFTP.KeepAlive = false; - reqFTP.UsePassive = true; - reqFTP.EnableSsl = _useSSL; - - //accept any certificates - ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate; - response = reqFTP.GetResponse(); - - reader = new StreamReader(response.GetResponseStream()); - var line = reader.ReadLine(); - while (line != null) - { - result.Append(line); - result.Append('\n'); - line = reader.ReadLine(); - } - - // to remove the trailing '\n' - result.Remove(result.ToString().LastIndexOf('\n'), 1); - return result.ToString().Split('\n'); - } - finally - { - reader?.Close(); - - response?.Close(); - } + return _connection.Value.GetNameListing().ToList().Where(_connection.Value.FileExists); } - protected virtual void Download(string file, ILoadDirectory destination, IDataLoadEventListener job) + protected virtual void Download(string file, ILoadDirectory destination) { - var s = new Stopwatch(); - s.Start(); - - var uri = !string.IsNullOrWhiteSpace(RemoteDirectory) - ? $"ftp://{_host}/{RemoteDirectory}/{file}" - : $"ftp://{_host}/{file}"; - - if (_useSSL) - uri = $"s{uri}"; - - var serverUri = new Uri(uri); - if (serverUri.Scheme != Uri.UriSchemeFtp) return; - -#pragma warning disable SYSLIB0014 // Type or member is obsolete - var reqFTP = (FtpWebRequest)WebRequest.Create(new Uri(uri)); -#pragma warning restore SYSLIB0014 // Type or member is obsolete - reqFTP.Credentials = new NetworkCredential(_username, _password); - reqFTP.KeepAlive = false; - reqFTP.Method = WebRequestMethods.Ftp.DownloadFile; - reqFTP.UseBinary = true; - reqFTP.Proxy = null; - reqFTP.UsePassive = true; - reqFTP.EnableSsl = _useSSL; - reqFTP.Timeout = TimeoutInSeconds * 1000; - - var response = (FtpWebResponse)reqFTP.GetResponse(); - var responseStream = response.GetResponseStream(); - var destinationFileName = Path.Combine(destination.ForLoading.FullName, file); + var remotePath = !string.IsNullOrWhiteSpace(RemoteDirectory) + ? $"{RemoteDirectory}/{file}" + : file; - using (var writeStream = new FileStream(destinationFileName, FileMode.Create)) - { - responseStream.CopyTo(writeStream); - writeStream.Close(); - } - - response.Close(); - - _filesRetrieved.Add(serverUri.ToString()); - s.Stop(); + var destinationFileName = Path.Combine(destination.ForLoading.FullName, file); + _connection.Value.DownloadFile(destinationFileName, remotePath); + _filesRetrieved.Add(remotePath); } public virtual void LoadCompletedSoDispose(ExitCodeType exitCode, IDataLoadEventListener postLoadEventListener) { - if (exitCode == ExitCodeType.Success && DeleteFilesOffFTPServerAfterSuccesfulDataLoad) - foreach (var file in _filesRetrieved) - { -#pragma warning disable SYSLIB0014 - // Type or member is obsolete - var reqFTP = (FtpWebRequest)WebRequest.Create(new Uri(file)); -#pragma warning restore SYSLIB0014 - // Type or member is obsolete - reqFTP.Credentials = new NetworkCredential(_username, _password); - reqFTP.KeepAlive = false; - reqFTP.Method = WebRequestMethods.Ftp.DeleteFile; - reqFTP.UseBinary = true; - reqFTP.Proxy = null; - reqFTP.UsePassive = true; - reqFTP.EnableSsl = _useSSL; - - var response = (FtpWebResponse)reqFTP.GetResponse(); - - if (response.StatusCode != FtpStatusCode.FileActionOK) - postLoadEventListener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Warning, - $"Attempt to delete file at URI {file} resulted in response with StatusCode = {response.StatusCode}")); - else - postLoadEventListener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, - $"Deleted FTP file at URI {file} status code was {response.StatusCode}")); - - response.Close(); - } + if (exitCode != ExitCodeType.Success || !DeleteFilesOffFTPServerAfterSuccesfulDataLoad) return; + + foreach (var file in _filesRetrieved) _connection.Value.DeleteFile(file); } @@ -297,7 +184,7 @@ public void Check(ICheckNotifier notifier) { try { - SetupFTP(); + SetupFtp(); } catch (Exception e) { diff --git a/Rdmp.Core/DataLoad/Modules/FTP/SFTPDownloader.cs b/Rdmp.Core/DataLoad/Modules/FTP/SFTPDownloader.cs index 3b507bb673..84dcd03765 100644 --- a/Rdmp.Core/DataLoad/Modules/FTP/SFTPDownloader.cs +++ b/Rdmp.Core/DataLoad/Modules/FTP/SFTPDownloader.cs @@ -5,9 +5,9 @@ // You should have received a copy of the GNU General Public License along with RDMP. If not, see . using System; -using System.Diagnostics; using System.IO; using System.Linq; +using System.Threading; using Rdmp.Core.Curation; using Rdmp.Core.Curation.Data; using Rdmp.Core.ReusableLibraryCode.Progress; @@ -18,7 +18,7 @@ namespace Rdmp.Core.DataLoad.Modules.FTP; /// /// load component which downloads files from a remote SFTP (Secure File Transfer Protocol) server to the ForLoading directory /// -/// Operates in the same way as except that it uses SSH. In addition this +/// Operates in the same way as except that it uses SSH. In addition, this /// class will not bother downloading any files that already exist in the forLoading directory (have the same name - file size is NOT checked) /// public class SFTPDownloader : FTPDownloader @@ -26,57 +26,48 @@ public class SFTPDownloader : FTPDownloader [DemandsInitialization("The keep-alive interval. In milliseconds. Requires KeepAlive to be set to take effect.")] public int KeepAliveIntervalMilliseconds { get; set; } - protected override void Download(string file, ILoadDirectory destination, IDataLoadEventListener job) - { - if (file.Contains('/') || file.Contains('\\')) - throw new Exception("Was not expecting a relative path here"); - - var s = new Stopwatch(); - s.Start(); + private readonly Lazy _connection; - using (var sftp = new SftpClient(_host, _username, _password)) - { - if (KeepAlive && KeepAliveIntervalMilliseconds > 0) - sftp.KeepAliveInterval = TimeSpan.FromMilliseconds(KeepAliveIntervalMilliseconds); - - sftp.ConnectionInfo.Timeout = new TimeSpan(0, 0, 0, TimeoutInSeconds); - sftp.Connect(); + public SFTPDownloader(Lazy connection) + { + _connection = new Lazy(SetupSftp,LazyThreadSafetyMode.ExecutionAndPublication); + } - //if there is a specified remote directory then reference it otherwise reference it locally (or however we were told about it from GetFileList()) - var fullFilePath = !string.IsNullOrWhiteSpace(RemoteDirectory) ? Path.Combine(RemoteDirectory, file) : file; + private SftpClient SetupSftp() + { + var host = FTPServer?.Server ?? throw new NullReferenceException("FTP server not set"); + var username = FTPServer.Username ?? "anonymous"; + var password = string.IsNullOrWhiteSpace(FTPServer.Password) ? "guest" : FTPServer.GetDecryptedPassword(); + var c = new SftpClient(host, username, password); + c.Connect(); + return c; + } - var destinationFilePath = Path.Combine(destination.ForLoading.FullName, file); - //register for events - void Callback(ulong totalBytes) => job.OnProgress(this, - new ProgressEventArgs(destinationFilePath, - new ProgressMeasurement((int)(totalBytes * 0.001), ProgressType.Kilobytes), s.Elapsed)); + protected override void Download(string file, ILoadDirectory destination) + { + if (file.Contains('/') || file.Contains('\\')) + throw new Exception("Was not expecting a relative path here"); - using (var fs = new FileStream(destinationFilePath, FileMode.CreateNew)) - { - //download - sftp.DownloadFile(fullFilePath, fs, Callback); - fs.Close(); - } + //if there is a specified remote directory then reference it otherwise reference it locally (or however we were told about it from GetFileList()) + var fullFilePath = !string.IsNullOrWhiteSpace(RemoteDirectory) ? Path.Combine(RemoteDirectory, file) : file; - _filesRetrieved.Add(fullFilePath); - } + var destinationFilePath = Path.Combine(destination.ForLoading.FullName, file); - s.Stop(); + using (var dest=File.Create(destinationFilePath)) + _connection.Value.DownloadFile(fullFilePath,dest); + _filesRetrieved.Add(fullFilePath); } public override void LoadCompletedSoDispose(ExitCodeType exitCode, IDataLoadEventListener postLoadEventListener) { if (exitCode != ExitCodeType.Success) return; - using var sftp = new SftpClient(_host, _username, _password); - sftp.ConnectionInfo.Timeout = new TimeSpan(0, 0, 0, TimeoutInSeconds); - sftp.Connect(); foreach (var retrievedFiles in _filesRetrieved) try { - sftp.DeleteFile(retrievedFiles); + _connection.Value.DeleteFile(retrievedFiles); postLoadEventListener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"Deleted SFTP file {retrievedFiles} from SFTP server")); } @@ -90,15 +81,8 @@ public override void LoadCompletedSoDispose(ExitCodeType exitCode, IDataLoadEven protected override string[] GetFileList() { - using var sftp = new SftpClient(_host, _username, _password); - sftp.ConnectionInfo.Timeout = new TimeSpan(0, 0, 0, TimeoutInSeconds); - sftp.Connect(); - - var directory = RemoteDirectory; - - if (string.IsNullOrWhiteSpace(directory)) - directory = "."; + var directory = string.IsNullOrWhiteSpace(RemoteDirectory) ? "." : RemoteDirectory; - return sftp.ListDirectory(directory).Select(d => d.Name).ToArray(); + return _connection.Value.ListDirectory(directory).Select(static d => d.Name).ToArray(); } } \ No newline at end of file diff --git a/Rdmp.Core/DataQualityEngine/Reports/CatalogueConstraintReport.cs b/Rdmp.Core/DataQualityEngine/Reports/CatalogueConstraintReport.cs index 5a13208cfa..d7df51dc20 100644 --- a/Rdmp.Core/DataQualityEngine/Reports/CatalogueConstraintReport.cs +++ b/Rdmp.Core/DataQualityEngine/Reports/CatalogueConstraintReport.cs @@ -173,7 +173,7 @@ public override void GenerateReport(ICatalogue c, IDataLoadEventListener listene if (pivotValue != null) { //if it is a novel - if (!byPivotCategoryCubesOverTime.ContainsKey(pivotValue)) + if (!byPivotCategoryCubesOverTime.TryGetValue(pivotValue, out var periodicityCubesOverTime)) { //we will need to expand the dictionaries if (byPivotCategoryCubesOverTime.Keys.Count > MaximumPivotValues) @@ -183,12 +183,13 @@ public override void GenerateReport(ICatalogue c, IDataLoadEventListener listene //expand both the time periodicity and the state results byPivotRowStatesOverDataLoadRunId.Add(pivotValue, new DQEStateOverDataLoadRunId(pivotValue)); - byPivotCategoryCubesOverTime.Add(pivotValue, new PeriodicityCubesOverTime(pivotValue)); + periodicityCubesOverTime = new PeriodicityCubesOverTime(pivotValue); + byPivotCategoryCubesOverTime.Add(pivotValue, periodicityCubesOverTime); } //now we are sure that the dictionaries have the category field we can increment it ProcessRecord(dqeRepository, dataLoadRunIDOfCurrentRecord, r, - byPivotCategoryCubesOverTime[pivotValue], byPivotRowStatesOverDataLoadRunId[pivotValue]); +periodicityCubesOverTime, byPivotRowStatesOverDataLoadRunId[pivotValue]); } if (progress % 5000 == 0) diff --git a/Rdmp.Core/DataQualityEngine/Reports/PeriodicityHelpers/PeriodicityCubesOverTime.cs b/Rdmp.Core/DataQualityEngine/Reports/PeriodicityHelpers/PeriodicityCubesOverTime.cs index b1e0eedf60..730234ed2b 100644 --- a/Rdmp.Core/DataQualityEngine/Reports/PeriodicityHelpers/PeriodicityCubesOverTime.cs +++ b/Rdmp.Core/DataQualityEngine/Reports/PeriodicityHelpers/PeriodicityCubesOverTime.cs @@ -40,30 +40,28 @@ public void IncrementHyperCube(int year, int month, Consequence? worstConsequenc PeriodicityCube newCube = null; //if year is missing - if (!hyperCube.ContainsKey(year)) + if (!hyperCube.TryGetValue(year, out var cubes)) { //create month dictionary var perMonth = new Dictionary { //add month user wants to month dictionary { month, newCube = new PeriodicityCube(year, month) } }; + cubes = perMonth; //add month dictionary to year dictionary - hyperCube.Add(year, perMonth); + hyperCube.Add(year, cubes); } //if month is missing - if (!hyperCube[year].ContainsKey(month)) - hyperCube[year] - .Add(month, newCube = new PeriodicityCube(year, month)); //add the month to the year dictionary - - //increment the cell - hyperCube[year][month].GetStateForConsequence(worstConsequenceInRow).CountOfRecords++; + if (!cubes.ContainsKey(month)) + cubes.Add(month, newCube = new PeriodicityCube(year, month)); //add the month to the year dictionary + cubes[month].GetStateForConsequence(worstConsequenceInRow).CountOfRecords++; if (newCube != null) allCubes.Add(newCube); } - public void CommitToDatabase(Evaluation evaluation) + internal void CommitToDatabase(Evaluation evaluation) { allCubes.ForEach(c => c.CommitToDatabase(evaluation, _pivotCategory)); } diff --git a/Rdmp.Core/Databases/CatalogueDatabase/runAfterCreateDatabase/CreateCatalogue.sql b/Rdmp.Core/Databases/CatalogueDatabase/runAfterCreateDatabase/CreateCatalogue.sql index 95818e0d03..ac7d12b279 100644 --- a/Rdmp.Core/Databases/CatalogueDatabase/runAfterCreateDatabase/CreateCatalogue.sql +++ b/Rdmp.Core/Databases/CatalogueDatabase/runAfterCreateDatabase/CreateCatalogue.sql @@ -893,6 +893,31 @@ CREATE TABLE [dbo].[TableInfo]( )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] + +GO +/****** Object: Table [dbo],[Dataset] ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +SET ANSI_PADDING ON +GO +CREATE TABLE [dbo].Dataset( + [ID] [int] IDENTITY(1,1) NOT NULL, + [Name] [varchar](256) NOT NULL, + [Folder] [nvarchar](1000) NOT NULL, + [DigitalObjectIdentifier] [varchar](256) NULL, + [Source] [varchar](256) NULL, + CONSTRAINT [PK_Dataset] PRIMARY KEY CLUSTERED +( + [ID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] +GO +ALTER TABLE [dbo].[ColumnInfo] ADD Dataset_ID [int] NULL +GO +ALTER TABLE [dbo].[ColumnInfo] ADD CONSTRAINT [FK_Column_Info_Dataset] FOREIGN KEY([Dataset_ID]) REFERENCES [dbo].[Dataset] ([ID]) ON DELETE CASCADE ON UPDATE CASCADE + GO SET ANSI_PADDING OFF GO @@ -1412,4 +1437,4 @@ GO insert into sysdiagrams(name, principal_id, diagram_id, version, definition) VALUES (N'Catalogue_Data_Diagram', 1, 1, 1, -0xD0CF11E0A1B11AE1000000000000000000000000000000003E000300FEFF0900060000000000000000000000020000000100000000000000001000005A00000001000000FEFFFFFF00000000000000005D000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFF5C000000030000000400000005000000060000000700000008000000090000000A0000000B0000000C0000000D0000000E0000000F000000100000001100000012000000130000001400000015000000160000001700000018000000FEFFFFFF1A0000001B0000001C0000001D0000001E0000001F000000200000002100000022000000230000002400000025000000260000002700000028000000290000002A0000002B0000002C0000002D0000002E0000002F000000300000003100000032000000330000003400000035000000360000003700000038000000390000003A0000003B0000003C0000003D0000003E0000003F000000400000004100000042000000430000004400000045000000460000004700000048000000490000004A0000004B0000004C0000004D0000004E0000004F00000050000000510000005200000053000000540000005500000056000000570000005800000059000000FEFFFFFFFEFFFFFF91000000FEFFFFFFFDFFFFFF5F000000600000006100000062000000630000006400000065000000660000006700000068000000690000006A0000006B0000006C0000006D0000006E0000006F000000700000007100000072000000730000007400000075000000760000007700000078000000790000007A0000007B0000007C0000007D0000007E0000007F0000008000000052006F006F007400200045006E00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500FFFFFFFFFFFFFFFF0200000000000000000000000000000000000000000000000000000000000000705AF83BF38BD0015B000000C00A0000000000006600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000201FFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000002000000322C0000000000006F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040002010100000004000000FFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000019000000AC80000000000000010043006F006D0070004F0062006A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000201FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000005F00000000000000000438000A1ED00D05000080D60000000F00FFFF5000000000000000D6000000007D0000E6930000175900001A9401001A4301000CCFFFFF7289FFFFDE805B10F195D011B0A000AA00BDCB5C000008003000000000020000030000003C006B0000000900000000000000D9E6B0E91C81D011AD5100A0C90F5739F43B7F847F61C74385352986E1D552F8A0327DB2D86295428D98273C25A2DA2D00002800430000000000000053444DD2011FD1118E63006097D2DF4834C9D2777977D811907000065B840D9C00002800430000000000000051444DD2011FD1118E63006097D2DF4834C9D2777977D811907000065B840D9C80000000382B000000FF01000170931500003800A50900000700008001000000AC020000008000000D0000805363684772696400A8480000E6FBFFFF436174616C6F6775654974656D07000000003400A50900000700008002000000A402000000800000090000805363684772696400A84800001E2D0000436174616C6F67756549746500008000A50900000700008003000000520000000180000058000080436F6E74726F6C00A74700004521000052656C6174696F6E736869702027464B5F436174616C6F6775655F4974656D735F446174615F436174616C6F67756527206265747765656E2027436174616C6F6775652720616E642027436174616C6F6775654974656D2700002800B50100000700008004000000310000007500000002800000436F6E74726F6C00ED490000E327000000003400A50900000700008005000000A402000000800000090000805363684772696400F4CFFFFF903300005461626C65496E666F49746500003400A50900000700008006000000A6020000008000000A0000805363684772696400FCD6FFFF6AFFFFFF436F6C756D6E496E666F746500007800A5090000070000800700000052000000018000004E000080436F6E74726F6C005BDFFFFF492A000052656C6174696F6E736869702027464B5F5461626C655F4974656D735F446174615F5461626C657327206265747765656E20275461626C65496E666F2720616E642027436F6C756D6E496E666F27000000002800B50100000700008008000000310000006700000002800000436F6E74726F6C00A1E1FFFF4E2F000000004000A5090000070000800D000000C20200000080000018000080536368477269640094110000A2E5FFFF436F6C756D6E496E666F5F436174616C6F6775654974656D00009400A509000007000080120000005A0000000180000069000080436F6E74726F6C0069FEFFFF51F6FFFF52656C6174696F6E736869702027464B5F436F6C756D6E496E666F5F436174616C6F6775654974656D5F436F6C756D6E496E666F27206265747765656E2027436F6C756D6E496E666F2720616E642027436F6C756D6E496E666F5F436174616C6F6775654974656D2700690000002800B50100000700008013000000310000007F00000002800000436F6E74726F6C00ABF6FFFFC5F5FFFF00009800A509000007000080160000006A000000018000006F000080436F6E74726F6C005B37000093F7FFFF52656C6174696F6E736869702027464B5F436F6C756D6E496E666F5F436174616C6F6775654974656D5F436174616C6F6775654974656D27206265747765656E2027436174616C6F6775654974656D2720616E642027436F6C756D6E496E666F5F436174616C6F6775654974656D270000002800B50100000700008017000000310000008500000002800000436F6E74726F6C005A29000075FAFFFF00003C00A50900000700008018000000B602000000800000120000805363684772696400FA7D00004A2E0000537570706F7274696E67446F63756D656E74756500008400A5090000070000801900000052000000018000005B000080436F6E74726F6C00F57000006331000052656C6174696F6E736869702027464B5F537570706F7274696E67446F63756D656E745F436174616C6F67756527206265747765656E2027436174616C6F6775652720616E642027537570706F7274696E67446F63756D656E74270000002800B5010000070000801A000000310000007100000002800000436F6E74726F6C004F6E0000A933000000004000A5090000070000801B000000BC020000008000001500008053636847726964007A0D0000E40C000045787472616374696F6E496E666F726D6174696F6E74656D0000A800A5090000070000802200000052000000018000007F000080436F6E74726F6C00391F000093F7FFFF52656C6174696F6E736869702027464B5F436F6C756D6E496E666F5F436174616C6F6775654974656D5F45787472616374696F6E496E666F726D6174696F6E27206265747765656E202745787472616374696F6E496E666F726D6174696F6E2720616E642027436F6C756D6E496E666F5F436174616C6F6775654974656D270000002800B50100000700008023000000310000009500000002800000436F6E74726F6C007F210000ED02000000003000A509000007000080240000009E02000000800000060000805363684772696400E2D2FFFF16DBFFFF4C6F6F6B7570640000007000A50900000700008027000000520000000180000045000080436F6E74726F6C0049E2FFFF49EDFFFF52656C6174696F6E736869702027464B5F4C6F6F6B75705F436F6C756D6E496E666F27206265747765656E2027436F6C756D6E496E666F2720616E6420274C6F6F6B757027D0135E00002800B50100000700008028000000310000005B00000002800000436F6E74726F6C008FE4FFFF0BF7FFFF00007000A50900000700008029000000520000000180000046000080436F6E74726F6C008FE7FFFF49EDFFFF52656C6174696F6E736869702027464B5F4C6F6F6B75705F436F6C756D6E496E666F3127206265747765656E2027436F6C756D6E496E666F2720616E6420274C6F6F6B757027135E00002800B5010000070000802A000000310000005D00000002800000436F6E74726F6C00D5E9FFFF0BF7FFFF00007000A5090000070000802B000000520000000180000046000080436F6E74726F6C005BDFFFFF49EDFFFF52656C6174696F6E736869702027464B5F4C6F6F6B75705F436F6C756D6E496E666F3227206265747765656E2027436F6C756D6E496E666F2720616E6420274C6F6F6B757027135E00002800B5010000070000802C000000310000005D00000002800000436F6E74726F6C00A1E1FFFF0BF7FFFF00003000A5090000070000802F000000A202000000800000080000805363684772696400A0ABFFFF12FDFFFF4A6F696E496E666F00007C00A50900000700008033000000520000000180000052000080436F6E74726F6C6F70D0FFFF95FFFFFF52656C6174696F6E736869702027464B5F4A6F696E496E666F5F436F6C756D6E496E666F5F4A6F696E4B65793127206265747765656E2027436F6C756D6E496E666F2720616E6420274A6F696E496E666F27654900002800B50100000700008034000000310000007100000002800000436F6E74726F6C6F9CD1FFFF25FFFFFF00007C00A50900000700008035000000520000000180000052000080436F6E74726F6C6F70D0FFFF4504000052656C6174696F6E736869702027464B5F4A6F696E496E666F5F436F6C756D6E496E666F5F4A6F696E4B65793227206265747765656E2027436F6C756D6E496E666F2720616E6420274A6F696E496E666F27654900002800B50100000700008036000000310000007100000002800000436F6E74726F6C6F9CD1FFFFD503000000003800A50900000700008038000000B20200000080000010000080536368477269646F12FDFFFFE835000045787472616374696F6E46696C74657200009800A5090000070000803900000052000000018000006F000080436F6E74726F6C6FEB1200001F2B000052656C6174696F6E736869702027464B5F45787472616374696F6E46696C7465725F45787472616374696F6E496E666F726D6174696F6E27206265747765656E202745787472616374696F6E496E666F726D6174696F6E2720616E64202745787472616374696F6E46696C746572270000002800B5010000070000803A000000310000008500000002800000436F6E74726F6C6F11FDFFFF3331000000004400A5090000070000803B000000C40200000080000019000080536368477269646F6AFFFFFFF654000045787472616374696F6E46696C746572506172616D657465720000000000A000A5090000070000803C000000520000000180000077000080436F6E74726F6C6F4D0B0000F64A000052656C6174696F6E736869702027464B5F45787472616374696F6E46696C746572506172616D657465725F45787472616374696F6E46696C74657227206265747765656E202745787472616374696F6E46696C7465722720616E64202745787472616374696F6E46696C746572506172616D65746572270000002800B5010000070000803D000000310000008D00000002800000436F6E74726F6C6F6DF3FFFFA550000000008C00A509000007000080400000005A0000000180000061000080436F6E74726F6C6F633100001F2B000052656C6174696F6E736869702027464B5F436174616C6F6775655F45787472616374696F6E496E666F726D6174696F6E27206265747765656E202745787472616374696F6E496E666F726D6174696F6E2720616E642027436174616C6F6775652700650000002800B50100000700008041000000310000007700000002800000436F6E74726F6C6F3E1E0000C76B000000004000A5090000070000804C000000C00200000080000017000080536368477269646F78D3FFFF22C0FFFF4C6F6F6B7570436F6D706F736974654A6F696E496E666F6D00008800A5090000070000805400000052000000018000005F000080436F6E74726F6C6F15DAFFFFC9D4FFFF52656C6174696F6E736869702027464B5F4C6F6F6B7570436F6D706F736974654A6F696E496E666F5F4C6F6F6B757027206265747765656E20274C6F6F6B75702720616E6420274C6F6F6B7570436F6D706F736974654A6F696E496E666F270000002800B50100000700008055000000310000007500000002800000436F6E74726F6C6F5BDCFFFFA1D8FFFF00009000A509000007000080560000006A0000000180000067000080436F6E74726F6C6F0FC8FFFF9DC8FFFF52656C6174696F6E736869702027464B5F4C6F6F6B7570436F6D706F736974654A6F696E496E666F5F436F6C756D6E496E666F27206265747765656E2027436F6C756D6E496E666F2720616E6420274C6F6F6B7570436F6D706F736974654A6F696E496E666F270000002800B50100000700008057000000310000007D00000002800000436F6E74726F6C6FEAC9FFFF9AE8FFFF00009400A509000007000080590000006A000000018000006A000080436F6E74726F6C6F57C1FFFF19C5FFFF52656C6174696F6E736869702027464B5F4C6F6F6B7570436F6D706F736974654A6F696E496E666F5F436F6C756D6E496E666F5F464B27206265747765656E2027436F6C756D6E496E666F2720616E6420274C6F6F6B7570436F6D706F736974654A6F696E496E666F276C7400002800B5010000070000805A000000310000008300000002800000436F6E74726F6C6F32C3FFFF08E5FFFF00003C00A5090000070000805C000000B60200000080000012000080536368477269646FDAAC0000D20F0000537570706F7274696E6753514C5461626C656E4900008400A5090000070000805D00000062000000018000005B000080436F6E74726F6C6FF5700000551F000052656C6174696F6E736869702027464B5F537570706F7274696E6753514C5461626C655F436174616C6F67756527206265747765656E2027436174616C6F6775652720616E642027537570706F7274696E6753514C5461626C65276E00002800B5010000070000805E000000310000007100000002800000436F6E74726F6C6F217200005131000000004000A5090000070000805F000000BE0200000080000016000080536368477269646FC201000086A7FFFF416767726567617465436F6E66696775726174696F6E6F6D00004000A50900000700008060000000C20200000080000018000080536368477269646F5C2B00006CA3FFFF41676772656761746546696C746572436F6E7461696E657200004400A50900000700008063000000C8020000008000001B000080536368477269646F7A580000FA9CFFFF41676772656761746546696C746572537562436F6E7461696E6572000000B400A5090000070000806400000052000000018000008B000080436F6E74726F6C6F6C4C000047A8FFFF52656C6174696F6E736869702027464B5F41676772656761746546696C746572537562436F6E7461696E65725F41676772656761746546696C746572436F6E7461696E657227206265747765656E202741676772656761746546696C746572436F6E7461696E65722720616E64202741676772656761746546696C746572537562436F6E7461696E6572270000002800B5010000070000806500000031000000A100000002800000436F6E74726F6C6FED4200008DAAFFFF0000B400A5090000070000806600000052000000018000008C000080436F6E74726F6C6F6C4C00006BA2FFFF52656C6174696F6E736869702027464B5F41676772656761746546696C746572537562436F6E7461696E65725F41676772656761746546696C746572436F6E7461696E65723127206265747765656E202741676772656761746546696C746572436F6E7461696E65722720616E64202741676772656761746546696C746572537562436F6E7461696E65722700002800B5010000070000806700000031000000A300000002800000436F6E74726F6C6F96420000FBA1FFFF00003800A5090000070000806E000000B0020000008000000F000080536368477269646F1059000050B0FFFF41676772656761746546696C7465727200009C00A5090000070000806F000000520000000180000073000080436F6E74726F6C6F6C4C00004FAFFFFF52656C6174696F6E736869702027464B5F41676772656761746546696C7465725F41676772656761746546696C746572436F6E7461696E657227206265747765656E202741676772656761746546696C746572436F6E7461696E65722720616E64202741676772656761746546696C746572277400002800B50100000700008070000000310000008900000002800000436F6E74726F6C6F55440000DFAEFFFF00003C00A50900000700008071000000B60200000080000012000080536368477269646FB42D000000B5FFFF41676772656761746544696D656E73696F6E74610000A000A50900000700008072000000520000000180000075000080436F6E74726F6C6FCC2200002BB5FFFF52656C6174696F6E736869702027464B5F41676772656761746544696D656E73696F6E5F416767726567617465436F6E66696775726174696F6E27206265747765656E2027416767726567617465436F6E66696775726174696F6E2720616E64202741676772656761746544696D656E73696F6E2772270000002800B50100000700008073000000310000008B00000002800000436F6E74726F6C6F351B000071B7FFFF0000AC00A50900000700008074000000520000000180000081000080436F6E74726F6C6FCC22000085A6FFFF52656C6174696F6E736869702027464B5F416767726567617465436F6E66696775726174696F6E5F41676772656761746546696C746572436F6E7461696E657227206265747765656E202741676772656761746546696C746572436F6E7461696E65722720616E642027416767726567617465436F6E66696775726174696F6E2700000000002800B50100000700008075000000310000009700000002800000436F6E74726F6C6FE818000015A6FFFF00004000A50900000700008076000000C20200000080000018000080536368477269646FD683000012B2FFFF41676772656761746546696C746572506172616D6574657200009C00A50900000700008077000000520000000180000073000080436F6E74726F6C6F1A7A000011B1FFFF52656C6174696F6E736869702027464B5F41676772656761746546696C746572506172616D657465725F41676772656761746546696C74657227206265747765656E202741676772656761746546696C7465722720616E64202741676772656761746546696C746572506172616D65746572276E00002800B50100000700008078000000310000008900000002800000436F6E74726F6C6FF072000057B3FFFF00003C00A5090000070000807C000000B60200000080000012000080536368477269646FF27600000CE5FFFF436174616C6F6775654974656D4973737565616D00008C00A509000007000080810000005A0000000180000063000080436F6E74726F6C6FD9600000F9F3FFFF52656C6174696F6E736869702027464B5F436174616C6F6775654974656D49737375655F436174616C6F6775654974656D27206265747765656E2027436174616C6F6775654974656D2720616E642027436174616C6F6775654974656D4973737565276E00002800B50100000700008082000000310000007900000002800000436F6E74726F6C6F8062000023F6FFFF00003800A50900000700008083000000B0020000008000000F000080536368477269646FF4B0000070CCFFFF497373756553797374656D557365727200009800A509000007000080840000005A000000018000006D000080436F6E74726F6C6F48A400004CDFFFFF52656C6174696F6E736869702027464B5F436174616C6F6775654974656D49737375655F4F776E65725F497373756553797374656D5573657227206265747765656E2027497373756553797374656D557365722720616E642027436174616C6F6775654974656D49737375652772270000002800B50100000700008085000000310000008900000002800000436F6E74726F6C6FF09700007CE3FFFF00009800A509000007000080860000005A0000000180000070000080436F6E74726F6C6F619A0000ABDAFFFF52656C6174696F6E736869702027464B5F436174616C6F6775654974656D49737375655F5265706F727465725F497373756553797374656D5573657227206265747765656E2027497373756553797374656D557365722720616E642027436174616C6F6775654974656D49737375652700002800B50100000700008087000000310000008F00000002800000436F6E74726F6C6F4B9200003BDAFFFF00003000A50900000700008088000000A20200000080000008000080536368477269646FC694FFFF56130000414E4F5461626C6500007400A5090000070000808B000000520000000180000049000080436F6E74726F6C65D6B5FFFF5512000052656C6174696F6E736869702027464B5F436F6C756D6E496E666F5F414E4F5461626C6527206265747765656E2027414E4F5461626C652720616E642027436F6C756D6E496E666F27496E6600002800B5010000070000808C000000310000005F00000002800000436F6E74726F6C65D8BFFFFF9B14000000004000A5090000070000808D000000BE0200000080000016000080536368477269646586A7FFFF302A00005072654C6F6164446973636172646564436F6C756D6E657200008C00A5090000070000808E000000520000000180000063000080436F6E74726F6C6596C8FFFF8F32000052656C6174696F6E736869702027464B5F5072654C6F6164446973636172646564436F6C756D6E5F5461626C65496E666F27206265747765656E20275461626C65496E666F2720616E6420275072654C6F6164446973636172646564436F6C756D6E276E00002800B5010000070000808F000000310000007900000002800000436F6E74726F6C6519C2FFFF1F32000000003C00A50900000700008091000000B80200000080000013000080536368477269646536D80000565E000050726F636573735461736B417267756D656E747500008C00A50900000700008094000000520000000180000061000080436F6E74726F6C6572D00000555D000052656C6174696F6E736869702027464B5F50726F636573735461736B417267756D656E745F50726F636573735461736B27206265747765656E202750726F636573735461736B2720616E64202750726F636573735461736B417267756D656E74276E276E00002800B50100000700008095000000310000007700000002800000436F6E74726F6C6544CA0000E55C000000003400A50900000700008090000000A8020000008000000B00008053636847726964659CAE0000D25A000050726F636573735461736B5500009C00A509000007000080960000005A0000000180000073000080436F6E74726F6C65F837000065C9FFFF52656C6174696F6E736869702027464B5F41676772656761746544696D656E73696F6E5F45787472616374696F6E496E666F726D6174696F6E27206265747765656E202745787472616374696F6E496E666F726D6174696F6E2720616E64202741676772656761746544696D656E73696F6E276E00002800B50100000700008097000000310000008900000002800000436F6E74726F6C658D4000008BF0FFFF00007800A5090000070000809A0000005A000000018000004D000080436F6E74726F6C65F5700000E87C000052656C6174696F6E736869702027464B5F50726F636573735461736B5F436174616C6F67756527206265747765656E2027436174616C6F6775652720616E64202750726F636573735461736B2727000000002800B5010000070000809B000000310000006300000002800000436F6E74726F6C65E99E00009592000000002400A5010000070000809C0000007100000002800000436F6E74726F6C65C47200005355000000003C00A5090000070000809D000000B60200000080000012000080536368477269646592B80000383100004C6F61644D6F64756C65417373656D626C79747500003400A5090000070000809E000000AA020000008000000C0000805363684772696465D8BD0000408300004C6F61645363686564756C6500004000A509000007000080A2000000BE0200000080000016000080536368477269646536F7FFFF0E6A000045787465726E616C4461746162617365536572766572657200008C00A509000007000080A30000005A0000000180000063000080436F6E74726F6C6539E1FFFF8E56000052656C6174696F6E736869702027464B5F5461626C65496E666F5F45787465726E616C446174616261736553657276657227206265747765656E202745787465726E616C44617461626173655365727665722720616E6420275461626C65496E666F276E00002800B501000007000080A4000000310000007900000002800000436F6E74726F6C6544CDFFFFAB6D000000008C00A509000007000080A60000005A0000000180000063000080436F6E74726F6C65B51B00006780000052656C6174696F6E736869702027464B5F436174616C6F6775655F45787465726E616C446174616261736553657276657227206265747765656E202745787465726E616C44617461626173655365727665722720616E642027436174616C6F677565276E00002800B501000007000080A7000000310000007900000002800000436F6E74726F6C65F50F0000B79D000000008C00A509000007000080A80000005A0000000180000064000080436F6E74726F6C65D91500006780000052656C6174696F6E736869702027464B5F436174616C6F6775655F45787465726E616C44617461626173655365727665723127206265747765656E202745787465726E616C44617461626173655365727665722720616E642027436174616C6F6775652700002800B501000007000080A9000000310000007B00000002800000436F6E74726F6C65B4090000FDA2000000008C00A509000007000080AA0000005A0000000180000061000080436F6E74726F6C65B3A3FFFF5723000052656C6174696F6E736869702027464B5F414E4F5461626C655F45787465726E616C446174616261736553657276657227206265747765656E202745787465726E616C44617461626173655365727665722720616E642027414E4F5461626C652775652700002800B501000007000080AB000000310000007700000002800000436F6E74726F6C65DDA5FFFF9268000000003800A509000007000080AC000000B2020000008000001000008053636847726964659E9D0000F69F00004C6F6164506572696F646963616C6C790000A000A509000007000080AF000000520000000180000075000080436F6E74726F6C65CC2200004DC0FFFF52656C6174696F6E736869702027464B5F416767726567617465436F6E66696775726174696F6E5F41676772656761746544696D656E73696F6E27206265747765656E202741676772656761746544696D656E73696F6E2720616E642027416767726567617465436F6E66696775726174696F6E2772270000002800B501000007000080B0000000310000008B00000002800000436F6E74726F6C655F1B0000DDBFFFFF00003400A509000007000080BD000000AA020000008000000C0000805363684772696465AA820000345300004C6F61644D6574616461746100007800A509000007000080BE00000052000000018000004F000080436F6E74726F6C65F57000005F53000052656C6174696F6E736869702027464B5F436174616C6F6775655F4C6F61644D6574616461746127206265747765656E20274C6F61644D657461646174612720616E642027436174616C6F677565270000002800B501000007000080BF000000310000006500000002800000436F6E74726F6C6566720000EF52000000008800A509000007000080C000000062000000018000005D000080436F6E74726F6C65FA9C0000CF85000052656C6174696F6E736869702027464B5F4C6F6164506572696F646963616C6C795F4C6F61644D6574616461746127206265747765656E20274C6F61644D657461646174612720616E6420274C6F6164506572696F646963616C6C79276F270000002800B501000007000080C1000000310000007300000002800000436F6E74726F6C65D98A00000695000000007C00A509000007000080C2000000520000000180000053000080436F6E74726F6C65659D0000A369000052656C6174696F6E736869702027464B5F50726F636573735461736B5F4C6F61644D6574616461746127206265747765656E20274C6F61644D657461646174612720616E64202750726F636573735461736B274900002800B501000007000080C3000000310000006900000002800000436F6E74726F6C65079E0000E96B000000008000A509000007000080C4000000620000000180000055000080436F6E74726F6C65659D0000517F000052656C6174696F6E736869702027464B5F4C6F61645363686564756C655F4C6F61644D6574616461746127206265747765656E20274C6F61644D657461646174612720616E6420274C6F61645363686564756C6527656D2700002800B501000007000080C5000000310000006B00000002800000436F6E74726F6C6581AA0000CF81000000004400A509000007000080C6000000C6020000008000001A000080536368477269646530750000CA9E0000444C4557696E646F777353657276696365457863657074696F6E720000009C00A509000007000080C7000000520000000180000071000080436F6E74726F6C65A98100005C86000052656C6174696F6E736869702027464B5F444C4557696E646F777353657276696365457863657074696F6E5F4C6F61644D6574616461746127206265747765656E20274C6F61644D657461646174612720616E642027444C4557696E646F777353657276696365457863657074696F6E27696F6E00002800B501000007000080C8000000310000008700000002800000436F6E74726F6C65FC6700004293000000008800A509000007000080C90000006A000000018000005E000080436F6E74726F6C65ED9700005C86000052656C6174696F6E736869702027464B5F4C6F6164506572696F646963616C6C795F4C6F61644D657461646174613127206265747765656E20274C6F61644D657461646174612720616E6420274C6F6164506572696F646963616C6C7927270000002800B501000007000080CA000000310000007500000002800000436F6E74726F6C65E7840000C995000000004400A509000007000080CB000000C8020000008000001B000080536368477269646562430000F4CFFFFF416767726567617465436F6E74696E756F75734461746541786973000000A800A509000007000080CC00000052000000018000007F000080436F6E74726F6C656142000069C9FFFF52656C6174696F6E736869702027464B5F416767726567617465436F6E74696E756F757344617465417869735F41676772656761746544696D656E73696F6E27206265747765656E202741676772656761746544696D656E73696F6E2720616E642027416767726567617465436F6E74696E756F75734461746541786973270000002800B501000007000080CD000000310000009500000002800000436F6E74726F6C65C22400005ECDFFFF00003C00A509000007000080D0000000B802000000800000130000805363684772696465B80B0000C8CEFFFF416767726567617465466F726365644A6F696E760000A000A509000007000080D10000005A0000000180000077000080436F6E74726F6C65DB04000016C9FFFF52656C6174696F6E736869702027464B5F416767726567617465466F726365644A6F696E5F416767726567617465436F6E66696775726174696F6E27206265747765656E2027416767726567617465436F6E66696775726174696F6E2720616E642027416767726567617465466F726365644A6F696E270000002800B501000007000080D2000000310000008D00000002800000436F6E74726F6C6564EAFFFFE9CFFFFF00008800A509000007000080D300000062000000018000005D000080436F6E74726F6C6582F8FFFF1FDDFFFF52656C6174696F6E736869702027464B5F416767726567617465466F726365644A6F696E5F5461626C65496E666F27206265747765656E20275461626C65496E666F2720616E642027416767726567617465466F726365644A6F696E2727270000002800B501000007000080D4000000310000007300000002800000436F6E74726F6C65360800002416000000008C00A509000007000080D50000007A0000000180000063000080436F6E74726F6C65AD21000012C9FFFF52656C6174696F6E736869702027464B5F416767726567617465436F6E66696775726174696F6E5F436174616C6F67756527206265747765656E2027436174616C6F6775652720616E642027416767726567617465436F6E66696775726174696F6E272700002800B501000007000080D6000000310000007900000002800000436F6E74726F6C656B3D00003DECFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002143341208000000A72900001A28000078563412070000001401000043006100740061006C006F006700750065004900740065006D00000073000000000010400100000000000000000000000E000000050000001801000000000000000000000000000000000000F8000000000000000500000000000000000000000200000000000000009492400000000000000000000000000094924000000000000000400400000020000000300000000000000000000000008C924000000000000010400000000000000040000000000000004000000000000000000100000000000000050000000000000040000000010000000000000000000040000000000000104004000000200000002000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000A72900001A280000000000002D0100000D0000000C000000070000001C010000F70800005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000411700003F230000000000000C0000000C00000002000000020000001C010000E60A00000000000001000000F21300009408000000000000020000000200000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000006400000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000E00000043006100740061006C006F006700750065004900740065006D000000214334120800000079290000BC7E000078563412070000001401000043006100740061006C006F00670075006500000067007500650000000000870AC03D66020500000000000000020000000000000000000000000100000001000000000000484B75575034A75728307C57484B755763006F006D00700075007400650064005F0063006F006C0075006D006E007300200063006D0063006501006453C20F00E05A6B16109AA70A6F0062006A006500630074005F006900640020003D00200063006F006C002E006F0062006A006500630074005F0069006400200061006E006400200063006D0063002E0063006F006C0075006D006E005F006900640020003D00200063006F006C00000000000000000000000000000005000000540000002C0000002C0000002C00000034000000000000000000000079290000BC7E0000000000002D0100000D0000000C000000070000001C0100002F0D00005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000411700000341000000000000180000000C00000002000000020000001C010000D70A00000000000001000000F21300004E06000000000000010000000100000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000005C00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000A00000043006100740061006C006F00670075006500000002000B003E4900001E2D00003E490000002400000000000002000000F0F0F00000000000000000000000000000000000010000000400000000000000ED490000E3270000BA1400005801000032000000010000020000BA14000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61210046004B005F0043006100740061006C006F006700750065005F004900740065006D0073005F0044006100740061005F0043006100740061006C006F006700750065002143341208000000BA290000B92500007856341207000000140100005400610062006C00650049006E0066006F00000073000000540020006E0061006D0065002C002000760061006C00750065002000460052004F004D0020007300790073002E0065007800740065006E006400650064005F00700072006F0070006500720074006900650073002000570048004500520045002000280063006C0061007300730020003D00200031002900200041004E004400200028006D0061006A006F0072005F006900640020003D0020004F0042004A004500430054005F004900440028004E0027005B00640062006F005D002E005B005400610062006C0065005F0031005D00270029002900000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000BA290000B9250000000000002D010000080000000C000000070000001C010000F70800005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000AF1C0000A823000000000000060000000600000002000000020000001C010000F20D00000000000001000000F21300004E06000000000000010000000100000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000005C00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000A0000005400610062006C00650049006E0066006F0000002143341208000000C42E00009A2D000078563412070000001401000043006F006C0075006D006E0049006E0066006F0000000000540020006E0061006D0065002C002000760061006C00750065002000460052004F004D0020007300790073002E0065007800740065006E006400650064005F00700072006F0070006500720074006900650073002000570048004500520045002000280063006C0061007300730020003D00200031002900200041004E004400200028006D0061006A006F0072005F006900640020003D0020004F0042004A004500430054005F004900440028004E0027005B00640062006F005D002E005B005400610062006C0065005F0031005D00270029002900000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000C42E00009A2D0000000000002D010000080000000C000000070000001C010000F50A00005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000411700005D14000000000000060000000600000002000000020000001C010000E60A00000000000001000000F21300009408000000000000020000000200000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000005E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000B00000043006F006C0075006D006E0049006E0066006F00000002000B00F2E0FFFF90330000F2E0FFFF042D00000000000002000000F0F0F00000000000000000000000000000000000010000000800000000000000A1E1FFFF4E2F00001C10000058010000380000000100000200001C10000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D611A0046004B005F005400610062006C0065005F004900740065006D0073005F0044006100740061005F005400610062006C00650073002143341208000000BA290000AC14000078563412070000001401000043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D0000000000050000001801000000000000000000000000000000000000F800000000000000050000000000000000000000020000000000000000D09D4000000000000000000000000000D09D400000000000000040040000002000000030000000000000000000000000C89D4000000000000010400000000000000040000000000000004000000000000000000100000000000000050000000000000040000000010000000000000000000040000000000000104004000000200000002000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000BA290000AC140000000000002D0100000D0000000C000000070000001C010000F70800005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000F21300000804000000000000000000000000000002000000020000001C010000F70800000000000001000000F21300000804000000000000000000000000000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000007A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001900000043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D00000003000B00000000006AFFFFFF00000000CCF7FFFF94110000CCF7FFFF0000000002000000F0F0F00000000000000000000000000000000000010000001300000000000000ABF6FFFFC5F5FFFFC51700005801000058000000010000020000C517000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61260046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F0043006F006C0075006D006E0049006E0066006F0005000B00A84800007CFCFFFFBF4000007CFCFFFFBF40000097FCFFFFD638000097FCFFFFD63800004EFAFFFF0000000002000000F0F0F000000000000000000000000000000000000100000017000000000000005A29000075FAFFFF92190000580100001D0000000100000200009219000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61290046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F0043006100740061006C006F006700750065004900740065006D0021433412080000003D2200005D1E000078563412070000001401000053007500700070006F007200740069006E00670044006F00630075006D0065006E0074000000000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003D2200005D1E0000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001300000053007500700070006F007200740069006E00670044006F00630075006D0065006E007400000002000B0021720000FA320000FA7D0000FA3200000000000002000000F0F0F00000000000000000000000000000000000010000001A000000000000004F6E0000A93300007C13000058010000320000000100000200007C13000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D611F0046004B005F0053007500700070006F007200740069006E00670044006F00630075006D0065006E0074005F0043006100740061006C006F006700750065002143341208000000AA2B0000F2200000785634120700000014010000450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E000000000000000E000000050000001801000000000000000000000000000000000000E800000000000000050000000000000000000000010000000000000000002A400000000000000000040000002000000020000000000000000000000000002E4000000000000000400000000000000040000000000000004000000000000000000100000000000000050000000000000040000000010000000000000000002E400000000000003640040000002000000020000000000000000000000000002A400000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000AA2B0000F2200000000000002D0100000D0000000C000000070000001C01000060090000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007400000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000016000000450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E00000002000B00D0200000E40C0000D02000004EFAFFFF0000000002000000F0F0F000000000000000000000000000000000000100000023000000000000007F210000ED020000671D00005801000032000000010000020000671D000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61310046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0021433412080000001C260000EE1400007856341207000000140100004C006F006F006B0075007000000000000001000010010000440000000200000001000000C800000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000001C260000EE140000000000002D0100000D0000000C000000070000001C010000160800009F06000094020000390300003A02000065040000DD040000EE020000DD04000036060000380400000000000001000000661200000804000000000000000000000000000002000000020000001C010000160800000000000001000000661200000804000000000000000000000000000002000000020000001C010000160800000100000000000000661200000804000000000000000000000000000002000000020000001C010000160800000000000000000000E42D00001224000000000000000000000D00000004000000040000001C010000160800008D090000DC05000078563412040000005600000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000070000004C006F006F006B0075007000000002000B00E0E3FFFF6AFFFFFFE0E3FFFF04F0FFFF0000000002000000F0F0F000000000000000000000000000000000000100000028000000000000008FE4FFFF0BF7FFFFBB0C00005801000032000000010000020000BB0C000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61140046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F0002000B0026E9FFFF6AFFFFFF26E9FFFF04F0FFFF0000000002000000F0F0F00000000000000000000000000000000000010000002A00000000000000D5E9FFFF0BF7FFFF680D00005801000032000000010000020000680D000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61150046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F00310002000B00F2E0FFFF6AFFFFFFF2E0FFFF04F0FFFF0000000002000000F0F0F00000000000000000000000000000000000010000002C00000000000000A1E1FFFF0BF7FFFF680D00005801000032000000010000020000680D000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61150046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F0032002143341208000000FC250000301500007856341207000000140100004A006F0069006E0049006E0066006F0000006E0064006F00770073002E0046006F0072006D0073002C002000560065007200730069006F006E003D0034002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00620037003700610035006300350036003100390033003400650030003800390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000FC25000030150000000000002D0100000D0000000C000000070000001C010000160800005406000094020000390300003A02000065040000DD040000EE020000DD04000036060000380400000000000001000000661200000804000000000000000000000000000002000000020000001C010000160800000000000001000000661200000804000000000000000000000000000002000000020000001C010000160800000100000000000000661200000804000000000000000000000000000002000000020000001C010000160800000000000000000000E42D00001224000000000000000000000D00000004000000040000001C010000160800008D090000DC05000078563412040000005A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000090000004A006F0069006E0049006E0066006F00000002000B00FCD6FFFF2C0100009CD1FFFF2C0100000000000002000000F0F0F000000000000000000000000000000000000100000034000000000000009CD1FFFF25FFFFFFD01200005801000064000000010000020000D012000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D611F0046004B005F004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F004A006F0069006E004B0065007900310002000B00FCD6FFFFDC0500009CD1FFFFDC0500000000000002000000F0F0F000000000000000000000000000000000000100000036000000000000009CD1FFFFD5030000D01200005801000064000000010000020000D012000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D611F0046004B005F004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F004A006F0069006E004B00650079003200214334120800000066230000C5170000785634120700000014010000450078007400720061006300740069006F006E00460069006C0074006500720000002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D0062003700370061003500630035003600310039003300340065003000380039000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C00000034000000000000000000000066230000C5170000000000002D0100000D0000000C000000070000001C010000070800009204000094020000390300003A02000029040000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000011000000450078007400720061006300740069006F006E00460069006C00740065007200000002000B0082140000D62D000082140000E83500000000000002000000F0F0F00000000000000000000000000000000000010000003A0000000000000011FDFFFF33310000C21600005801000032000000010000020000C216000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61290046004B005F00450078007400720061006300740069006F006E00460069006C007400650072005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E002143341208000000EA1F00007A120000785634120700000014010000450078007400720061006300740069006F006E00460069006C0074006500720050006100720061006D006500740065007200000069006F006E003D0034002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00620037003700610035006300350036003100390033003400650030003800390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000EA1F00007A120000000000002D0100000D0000000C000000070000001C010000090600009204000094020000390300003A02000029040000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007C00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001A000000450078007400720061006300740069006F006E00460069006C0074006500720050006100720061006D006500740065007200000002000B00E40C0000AD4D0000E40C0000F65400000000000002000000F0F0F00000000000000000000000000000000000010000003D000000000000006DF3FFFFA5500000C81800005801000032000000010000020000C818000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612D0046004B005F00450078007400720061006300740069006F006E00460069006C0074006500720050006100720061006D0065007400650072005F00450078007400720061006300740069006F006E00460069006C0074006500720003000B00FA320000D62D0000FA320000F0870000A8480000F08700000000000002000000F0F0F000000000000000000000000000000000000100000041000000000000003E1E0000C76B00000D14000058010000370000000100000200000D14000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61220046004B005F0043006100740061006C006F006700750065005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E00214334120800000056250000621700007856341207000000140100004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F000000680050006100720073006500720043006C00690065006E0074002C002000560065007200730069006F006E003D00310031002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00380039003800340035006400630064003800300038003000630063003900310000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000005625000062170000000000002D010000070000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000042700004710000000000000040000000400000002000000020000001C010000CE1300000000000001000000D91000006806000000000000010000000100000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007800000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000180000004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F00000002000B00ACDBFFFF16DBFFFFACDBFFFF84D7FFFF0000000002000000F0F0F000000000000000000000000000000000000100000055000000000000005BDCFFFFA1D8FFFF6414000058010000320000000100000200006414000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61210046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F004C006F006F006B007500700005000B006EDDFFFF6AFFFFFF6EDDFFFF07F9FFFF3BC9FFFF07F9FFFF3BC9FFFF18CAFFFF78D3FFFF18CAFFFF0000000002000000F0F0F00000000000000000000000000000000000010000005700000000000000EAC9FFFF9AE8FFFFC21600005801000032000000010000020000C216000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61250046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F0005000B0054D9FFFF6AFFFFFF54D9FFFFDDFBFFFF83C2FFFFDDFBFFFF83C2FFFF94C6FFFF78D3FFFF94C6FFFF0000000002000000F0F0F00000000000000000000000000000000000010000005A0000000000000032C3FFFF08E5FFFFC81800005801000032000000010000020000C818000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61280046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F0046004B0021433412080000003D2200005B1A000078563412070000001401000053007500700070006F007200740069006E006700530051004C005400610062006C00650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003D2200005B1A0000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001300000053007500700070006F007200740069006E006700530051004C005400610062006C006500000004000B0021720000A2300000FB7A0000A2300000FB7A0000D0200000DAAC0000D02000000000000002000000F0F0F00000000000000000000000000000000000010000005E0000000000000021720000513100002613000058010000000000000100000200002613000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D611F0046004B005F0053007500700070006F007200740069006E006700530051004C005400610062006C0065005F0043006100740061006C006F006700750065002143341208000000362200004724000078563412070000001401000041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E000000000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003622000047240000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007600000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001700000041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E00000021433412080000003C2200005F0F0000785634120700000014010000410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E0065007200000000000200000000001066000000010000200000005A66D11F3372CF63785FCA7F40C69EA7DCEDA7CC247BCFBB00C38E42D74AECAA000000000E800000000200002000000022DD4B17FD42971A525C6C9C486DCAF55C6C488516735862E36E352C2D42E2C460000000A7DE800C07B35B3F0D6263AC81AE6E31CA8A493A12274568746645EF462AD47FD8892C9460826B6F5F558A0E75CC4E4AC5561556A9455D20A14B4EE450E669AB1E892532D8D21B364B2F844052BF0F8ECA46A54A000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C2200005F0F0000000000002D0100000D0000000C000000070000001C010000500A0000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000019000000410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E0065007200000021433412080000003C220000CC100000785634120700000014010000410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E006500720000006E003D0034002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00620037003700610035006300350036003100390033003400650030003800390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C220000CC100000000000002D0100000D0000000C000000070000001C010000300C0000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000008000000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001C000000410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E0065007200000002000B00984D0000DEA9FFFF7A580000DEA9FFFF0000000002000000F0F0F00000000000000000000000000000000000010000006500000000000000ED4200008DAAFFFF3820000058010000320000000100000200003820000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61370046004B005F00410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E00650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720002000B00984D000002A4FFFF7A58000002A4FFFF0000000002000000F0F0F0000000000000000000000000000000000001000000670000000000000096420000FBA1FFFFE52000005801000032000000010000020000E520000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61380046004B005F00410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E00650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E00650072003100214334120800000036220000CF1C0000785634120700000014010000410067006700720065006700610074006500460069006C0074006500720000007600650072002E004200610074006300680050006100720073006500720043006C00690065006E0074002C002000560065007200730069006F006E003D00310031002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00380039003800340035006400630064003800300038003000630063003900310000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C00000034000000000000000000000036220000CF1C0000000000002D010000070000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD040000360600003804000000000000010000000B2400005015000000000000050000000500000002000000020000001C0100002A1200000000000001000000D9100000AF08000000000000020000000200000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006800000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000010000000410067006700720065006700610074006500460069006C00740065007200000002000B00984D0000E6B0FFFF10590000E6B0FFFF0000000002000000F0F0F0000000000000000000000000000000000001000000700000000000000055440000DFAEFFFFE51800005801000045000000010000020000E518000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612B0046004B005F00410067006700720065006700610074006500460069006C007400650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720021433412080000007829000020170000785634120700000014010000410067006700720065006700610074006500440069006D0065006E00730069006F006E000000674797F9A80390A9CEBA040000000200000000001066000000010000200000005A66D11F3372CF63785FCA7F40C69EA7DCEDA7CC247BCFBB00C38E42D74AECAA000000000E800000000200002000000022DD4B17FD42971A525C6C9C486DCAF55C6C488516735862E36E352C2D42E2C460000000A7DE800C07B35B3F0D6263AC81AE6E31CA8A493A12274568746645EF462AD47FD8892C9460826B6F5F558A0E75CC4E4AC5561556A9455D20A14B4EE450E669AB1E892532D8D21B364B2F844052BF0F8ECA46A54A000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000007829000020170000000000002D0100000D0000000C000000070000001C0100005F0A0000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000013000000410067006700720065006700610074006500440069006D0065006E00730069006F006E00000002000B00F8230000C2B6FFFFB42D0000C2B6FFFF0000000002000000F0F0F00000000000000000000000000000000000010000007300000000000000351B000071B7FFFFED1A00005801000033000000010000020000ED1A000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612C0046004B005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E0002000B005C2B00001CA8FFFFF82300001CA8FFFF0000000002000000F0F0F00000000000000000000000000000000000010000007500000000000000E818000015A6FFFF831D00005801000032000000010000020000831D000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61320046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720021433412080000003C2200000E150000785634120700000014010000410067006700720065006700610074006500460069006C0074006500720050006100720061006D006500740065007200000000000200000000001066000000010000200000005A66D11F3372CF63785FCA7F40C69EA7DCEDA7CC247BCFBB00C38E42D74AECAA000000000E800000000200002000000022DD4B17FD42971A525C6C9C486DCAF55C6C488516735862E36E352C2D42E2C460000000A7DE800C07B35B3F0D6263AC81AE6E31CA8A493A12274568746645EF462AD47FD8892C9460826B6F5F558A0E75CC4E4AC5561556A9455D20A14B4EE450E669AB1E892532D8D21B364B2F844052BF0F8ECA46A54A000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C2200000E150000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000019000000410067006700720065006700610074006500460069006C0074006500720050006100720061006D006500740065007200000002000B00467B0000A8B2FFFFD6830000A8B2FFFF0000000002000000F0F0F00000000000000000000000000000000000010000007800000000000000F072000057B3FFFF3C19000058010000320000000100000200003C19000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612B0046004B005F00410067006700720065006700610074006500460069006C0074006500720050006100720061006D0065007400650072005F00410067006700720065006700610074006500460069006C007400650072002143341208000000822E0000641F000078563412070000001401000043006100740061006C006F006700750065004900740065006D004900730073007500650000002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D0062003700370061003500630035003600310039003300340065003000380039000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000822E0000641F0000000000002D010000090000000C000000070000001C0100006C0C0000DC05000094020000390300003A020000DE030000DD040000EE020000DD040000360600003804000000000000010000003E260000E717000000000000070000000700000002000000020000001C010000561300000000000001000000D91000006806000000000000010000000100000002000000020000001C010000260700000100000000000000D91000009E03000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001300000043006100740061006C006F006700750065004900740065006D0049007300730075006500000003000B0070620000E6FBFFFF7062000074F5FFFFF276000074F5FFFF0000000002000000F0F0F000000000000000000000000000000000000100000082000000000000008062000023F6FFFFA11500005801000032000000010000020000A115000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61230046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F0043006100740061006C006F006700750065004900740065006D0021433412080000003C2200009315000078563412070000001401000049007300730075006500530079007300740065006D005500730065007200000001000000C800000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C22000093150000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006800000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001000000049007300730075006500530079007300740065006D005500730065007200000003000B00E2B3000003E2FFFFE2B3000040EDFFFF74A5000040EDFFFF0000000002000000F0F0F00000000000000000000000000000000000010000008500000000000000F09700007CE3FFFF431B00005801000007000000010000020000431B000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612B0046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F004F0077006E00650072005F0049007300730075006500530079007300740065006D00550073006500720003000B00F4B0000042DCFFFFDC9B000042DCFFFFDC9B00000CE5FFFF0000000002000000F0F0F000000000000000000000000000000000000100000087000000000000004B9200003BDAFFFF801C00005801000007000000010000020000801C000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612E0046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F005200650070006F0072007400650072005F0049007300730075006500530079007300740065006D00550073006500720021433412080000003C220000BC12000078563412070000001401000041004E004F005400610062006C00650000006E0066006F00000000000200000001000000C800000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C220000BC120000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000005A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000900000041004E004F005400610062006C006500000002000B0002B7FFFFEC130000FCD6FFFFEC1300000000000002000000F0F0F00000000000000000000000000000000000010000008C00000000000000D8BFFFFF9B1400004E0E000058010000320000000100000200004E0E000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61160046004B005F0043006F006C0075006D006E0049006E0066006F005F0041004E004F005400610062006C00650021433412080000003C2200007B1A00007856341207000000140100005000720065004C006F006100640044006900730063006100720064006500640043006F006C0075006D006E0000000000040000000200000000001066000000010000200000005A66D11F3372CF63785FCA7F40C69EA7DCEDA7CC247BCFBB00C38E42D74AECAA000000000E800000000200002000000022DD4B17FD42971A525C6C9C486DCAF55C6C488516735862E36E352C2D42E2C460000000A7DE800C07B35B3F0D6263AC81AE6E31CA8A493A12274568746645EF462AD47FD8892C9460826B6F5F558A0E75CC4E4AC5561556A9455D20A14B4EE450E669AB1E892532D8D21B364B2F844052BF0F8ECA46A54A000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C2200007B1A0000000000002D0100000D0000000C000000070000001C01000052080000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007600000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000170000005000720065004C006F006100640044006900730063006100720064006500640043006F006C0075006D006E00000002000B00F4CFFFFF26340000C2C9FFFF263400000000000002000000F0F0F00000000000000000000000000000000000010000008F0000000000000019C2FFFF1F3200008415000058010000320000000100000200008415000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61230046004B005F005000720065004C006F006100640044006900730063006100720064006500640043006F006C0075006D006E005F005400610062006C00650049006E0066006F0021433412080000009A290000A51B0000785634120700000014010000500072006F0063006500730073005400610073006B0041007200670075006D0065006E00740000002C002000560065007200730069006F006E003D0034002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00620037003700610035006300350036003100390033003400650030003800390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000009A290000A51B0000000000002D0100000D0000000C000000070000001C010000F70800005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000F21300000804000000000000000000000000000002000000020000001C010000F70800000000000001000000F21300000804000000000000000000000000000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000007000000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000014000000500072006F0063006500730073005400610073006B0041007200670075006D0065006E007400000002000B009ED10000EC5E000036D80000EC5E00000000000002000000F0F0F0000000000000000000000000000000000001000000950000000000000044CA0000E55C00004B15000058010000320000000100000200004B15000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61220046004B005F00500072006F0063006500730073005400610073006B0041007200670075006D0065006E0074005F00500072006F0063006500730073005400610073006B00214334120800000002230000D1240000785634120700000014010000500072006F0063006500730073005400610073006B0000006700720061006D002000460069006C00650073002000280078003800360029002F004D006900630072006F0073006F00660074002000530051004C0020005300650072007600650072002F003100310030002F0054006F006F006C0073002F00420069006E006E002F004D0061006E006100670065006D0065006E007400530074007500640069006F002F004900440045002F00500072006900760061007400650041007300730065006D0062006C006900650073002F004F0062006A006500630074004500780070006C006F007200650072005200000000000000000000000000000005000000540000002C0000002C0000002C00000034000000000000000000000002230000D1240000000000002D0100000D0000000C000000070000001C010000450600002805000094020000390300003A02000066030000DD040000EE020000DD040000360600003804000000000000010000004C0F00000804000000000000000000000000000002000000020000001C0100004506000000000000010000004C0F00000804000000000000000000000000000002000000020000001C0100004506000001000000000000004C0F00000804000000000000000000000000000002000000020000001C010000450600000000000000000000CB2400007C24000000000000000000000D00000004000000040000001C01000045060000710700009204000078563412040000006000000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000C000000500072006F0063006500730073005400610073006B00000003000B00243900007A0D0000DE3F00007A0D0000DE3F000020CCFFFF0000000002000000F0F0F000000000000000000000000000000000000100000097000000000000008D4000008BF0FFFFAF1900005801000032000000010000020000AF19000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612B0046004B005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0003000B0021720000E691000092B80000E691000092B80000A37F00000000000002000000F0F0F00000000000000000000000000000000000010000009B00000000000000E99E000095920000DF0E00005801000032000000010000020000DF0E000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61180046004B005F00500072006F0063006500730073005400610073006B005F0043006100740061006C006F0067007500650000020000F90C0000160900000200640000000500008000000000000000003A00010000009001C0D40100085365676F652055491E004E0065007600650072002000430041005300430041004400450020000D000A00440045004C0045005400450020000D000A0048006500720065002100214334120800000036220000472400007856341207000000140100004C006F00610064004D006F00640075006C00650041007300730065006D0062006C0079000000000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003622000047240000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000130000004C006F00610064004D006F00640075006C00650041007300730065006D0062006C007900000021433412080000009E390000252700007856341207000000140100004C006F00610064005300630068006500640075006C00650000005300650072007600650072002E004200610074006300680050006100720073006500720043006C00690065006E0074002C002000560065007200730069006F006E003D00310031002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00380039003800340035006400630064003800300038003000630063003900310000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000009E39000025270000000000002D0100000D0000000C000000070000001C010000C50D0000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000104F0000B1240000000000000B0000000B00000002000000020000001C0100007B2A00000000000001000000D9100000AF08000000000000020000000200000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006200000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000D0000004C006F00610064005300630068006500640075006C006500000021433412080000007829000010190000785634120700000014010000450078007400650072006E0061006C0044006100740061006200610073006500530065007200760065007200000000007501000000000000140000000000000000000000010000000400000075010000430000004700000004000000000000000600000004000000750100001400000047000000010000000300000005000000E4FFFFFF750100001400000047000000000000000300000005000000E8FFFFFF7501000014000000470000000200000003000000050000000800000075010000530000005C0100000400000000000000060000000800000075010000530000005C01000001000000030000000500000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000007829000010190000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007600000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000017000000450078007400650072006E0061006C0044006100740061006200610073006500530065007200760065007200000003000B0036F7FFFFFC6C0000B4E2FFFFFC6C0000B4E2FFFF495900000000000002000000F0F0F0000000000000000000000000000000000001000000A40000000000000044CDFFFFAB6D00002D15000058010000320000000100000200002D15000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61230046004B005F005400610062006C00650049006E0066006F005F00450078007400650072006E0061006C004400610074006100620061007300650053006500720076006500720003000B004C1D00001E8300004C1D0000089D0000A8480000089D00000000000002000000F0F0F0000000000000000000000000000000000001000000A700000000000000F50F0000B79D00008415000058010000320000000100000200008415000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61230046004B005F0043006100740061006C006F006700750065005F00450078007400650072006E0061006C004400610074006100620061007300650053006500720076006500720003000B00701700001E830000701700004EA20000A84800004EA200000000000002000000F0F0F0000000000000000000000000000000000001000000A900000000000000B4090000FDA200003116000058010000320000000100000200003116000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61240046004B005F0043006100740061006C006F006700750065005F00450078007400650072006E0061006C0044006100740061006200610073006500530065007200760065007200310003000B0036F7FFFF546F00002EA5FFFF546F00002EA5FFFF122600000000000002000000F0F0F0000000000000000000000000000000000001000000AB00000000000000DDA5FFFF926800006715000058010000380000000100000200006715000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61220046004B005F0041004E004F005400610062006C0065005F00450078007400650072006E0061006C00440061007400610062006100730065005300650072007600650072002143341208000000C61B0000E61700007856341207000000140100004C006F006100640050006500720069006F0064006900630061006C006C0079000000440026004400570044004F0052004A005800480003001000030026004400570044004F0052004A005800480042002700440057004400420027004C0044004A00550044005000000080400000004100001041000000410000C040000040400000C0400000E04000008040000040400000E040000080400000C0400000E0400000E04000008040000000410000C040000080400000C040000000410000C040000080400000C040000040400000E0400000E0400000E0400000C040000040400000A04000004040000000410000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000C61B0000E6170000000000002D0100000D0000000C000000070000001C010000890D0000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000110000004C006F006100640050006500720069006F0064006900630061006C006C007900000002000B00B42D0000E4C1FFFFF8230000E4C1FFFF0000000002000000F0F0F0000000000000000000000000000000000001000000B0000000000000005F1B0000DDBFFFFFED1A00005801000032000000010000020000ED1A000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D612C0046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E002143341208000000E71B0000DF3500007856341207000000140100004C006F00610064004D0065007400610064006100740061000000954000000000000010400100000000000000000000000E000000050000001801000000000000000000000000000000000000F800000000000000050000000000000000000000020000000000000000C0954000000000000000000000000000C095400000000000000040040000002000000030000000000000000000000000B8954000000000000010400000000000000040000000000000004000000000000000000100000000000000050000000000000040000000010000000000000000000040000000000000104004000000200000002000000000000000000000000100000005000000540000002C0000002C0000002C0000003400000000000000000000003622000047240000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000E71B0000DF35000000000000140000000C00000002000000020000001C0100007A0D00000000000001000000D91000006806000000000000010000000100000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006200000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000D0000004C006F00610064004D006500740061006400610074006100000002000B00AA820000F654000021720000F65400000000000002000000F0F0F0000000000000000000000000000000000001000000BF0000000000000066720000EF520000FF0F00005801000032000000010000020000FF0F000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61190046004B005F0043006100740061006C006F006700750065005F004C006F00610064004D00650074006100640061007400610004000B00919E000086880000919E000084940000CA9E000084940000CA9E0000F69F00000200000002000000F0F0F0000000000000000000000000000000000001000000C100000000000000D98A0000069500000913000058010000320000000100000200000913000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61200046004B005F004C006F006100640050006500720069006F0064006900630061006C006C0079005F004C006F00610064004D00650074006100640061007400610002000B00919E00003A6B00009CAE00003A6B00000000000002000000F0F0F0000000000000000000000000000000000001000000C300000000000000079E0000E96B00001F11000058010000320000000100000200001F11000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D611B0046004B005F00500072006F0063006500730073005400610073006B005F004C006F00610064004D00650074006100640061007400610004000B00919E0000E88000008EA90000E88000008EA90000D6830000D8BD0000D68300000000000002000000F0F0F0000000000000000000000000000000000001000000C50000000000000081AA0000CF810000E91100005801000032000000010000020000E911000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D611C0046004B005F004C006F00610064005300630068006500640075006C0065005F004C006F00610064004D0065007400610064006100740061002143341208000000362200003A1A000078563412070000001401000044004C004500570069006E0064006F0077007300530065007200760069006300650045007800630065007000740069006F006E000000720073006500720043006C00690065006E0074002C002000560065007200730069006F006E003D00310031002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00380039003800340035006400630064003800300038003000630063003900310000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000362200003A1A0000000000002D010000080000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000621700007B1A000000000000060000000600000002000000020000001C010000E60A00000000000001000000D91000006806000000000000010000000100000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001B00000044004C004500570069006E0064006F0077007300530065007200760069006300650045007800630065007000740069006F006E00000002000B00408300001389000040830000CA9E00000000000002000000F0F0F0000000000000000000000000000000000001000000C800000000000000FC67000042930000951A00005801000032000000010000020000951A000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D612A0046004B005F0044004C004500570069006E0064006F0077007300530065007200760069006300650045007800630065007000740069006F006E005F004C006F00610064004D00650074006100640061007400610005000B00849900001389000084990000849400004C990000849400004C9900008CA000009E9D00008CA000000000000002000000F0F0F0000000000000000000000000000000000001000000CA00000000000000E7840000C9950000B61300005801000033000000010000020000B613000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61210046004B005F004C006F006100640050006500720069006F0064006900630061006C006C0079005F004C006F00610064004D00650074006100640061007400610031002143341208000000112E00007116000078563412070000001401000041006700670072006500670061007400650043006F006E00740069006E0075006F0075007300440061007400650041007800690073000000010000002CF19F123CF19F1204000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A891B10B000400000000000074F19F120400000000000000000000000000000000000000000000000000000080457D121884AC0B00000000AA550000E0F09F1210000000604578120C0000000500000094DF7B007CDF7B00C4F19F1200000000D5FFAA55001000000C00000000000000A891B10B0000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000112E000071160000000000002D0100000D0000000C000000070000001C010000F7080000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000008000000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001C00000041006700670072006500670061007400650043006F006E00740069006E0075006F007500730044006100740065004100780069007300000002000B00F843000020CCFFFFF8430000F4CFFFFF0200000002000000F0F0F0000000000000000000000000000000000001000000CD00000000000000C22400005ECDFFFF871E00005801000032000000010000020000871E000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61310046004B005F0041006700670072006500670061007400650043006F006E00740069006E0075006F0075007300440061007400650041007800690073005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E0021433412080000003D2200006910000078563412070000001401000041006700670072006500670061007400650046006F0072006300650064004A006F0069006E00000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003D22000069100000000000002D0100000D0000000C000000070000001C01000015090000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007000000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001400000041006700670072006500670061007400650046006F0072006300650064004A006F0069006E00000003000B0072060000CDCBFFFF720600005ECFFFFFB80B00005ECFFFFF0000000002000000F0F0F0000000000000000000000000000000000001000000D20000000000000064EAFFFFE9CFFFFF5F1B000058010000270000000100000200005F1B000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D612D0046004B005F0041006700670072006500670061007400650046006F0072006300650064004A006F0069006E005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E0004000B00AEF9FFFF263400008707000026340000870700009ADEFFFFB80B00009ADEFFFF0000000002000000F0F0F0000000000000000000000000000000000001000000D40000000000000036080000241600007C130000580100002B0000000100000200007C13000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61200046004B005F0041006700670072006500670061007400650046006F0072006300650064004A006F0069006E005F005400610062006C00650049006E0066006F0007000B00A8480000B42D0000F2430000B42D0000F243000020280000BC3C000020280000BC3C00005DCDFFFF282300005DCDFFFF28230000CDCBFFFF0000000002000000F0F0F0000000000000000000000000000000000001000000D6000000000000006B3D00003DECFFFF4B15000058010000380000000100000200004B15000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61230046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F0043006100740061006C006F006700750065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000FEFFFFFFFEFFFFFF0400000005000000060000000700000008000000090000000A0000000B0000000C0000000D0000000E0000000F000000100000001100000012000000130000001400000015000000160000001700000018000000190000001A0000001B0000001C0000001D0000001E0000001F00000020000000210000002200000023000000240000002500000026000000270000002800000029000000FEFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0100FEFF030A0000FFFFFFFF00000000000000000000000000000000170000004D6963726F736F66742044445320466F726D20322E300010000000456D626564646564204F626A6563740000000000F439B271000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010003000000000000000C0000000B0000004E61BC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000DBE6B0E91C81D011AD5100A0C90F573900000200D062F43BF38BD0010202000010484500000000000000000000000000000000007A0100004400610074006100200053006F0075007200630065003D006A0061006E00750073003B0049006E0069007400690061006C00200043006100740061006C006F0067003D0053007000720069006E00740046006F0075007200440061007400610043006100740061006C006F006700750065003B0049006E00740065006700720061007400650064002000530065006300750072006900740079003D0054007200750065003B004D0075006C007400690070006C00650041006300740069007600650052006500730075006C00740053006500740073003D00460061006C00730065003B005000610063006B00650074002000530069007A0065003D0034003000390036003B0041000300440064007300530074007200650061006D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160002000300000006000000FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000005E0000007A6500000000000053006300680065006D00610020005500440056002000440065006600610075006C0074000000000000000000000000000000000000000000000000000000000026000200FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000020000001600000000000000440053005200450046002D0053004300480045004D0041002D0043004F004E00540045004E0054005300000000000000000000000000000000000000000000002C0002010500000007000000FFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000003000000A40900000000000053006300680065006D00610020005500440056002000440065006600610075006C007400200050006F007300740020005600360000000000000000000000000036000200FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000002A00000012000000000000008100000082000000830000008400000085000000860000008700000088000000890000008A0000008B0000008C0000008D0000008E0000008F00000090000000FEFFFFFF92000000930000009400000095000000FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C0000000CCFFFFF7289FFFF0100260000007300630068005F006C006100620065006C0073005F00760069007300690062006C0065000000010000000B0000001E000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000010000000100000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003200390035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003700390030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C0031003600360035000000020000000200000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0033003300370035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003700370035000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C0031003600360035000000030000000300000000000000540000000103737401000000640062006F00000046004B005F0043006100740061006C006F006700750065005F004900740065006D0073005F0044006100740061005F0043006100740061006C006F0067007500650000000000000000000000C40200000000040000000400000003000000080000000100650DC800650D0000000000000000AD070000000000050000000500000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003200390035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0033003500370030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C0031003600360035000000060000000600000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003800300035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003700390030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C00310036003600350000000700000007000000000000004600000001038A7601000000640062006F00000046004B005F005400610062006C0065005F004900740065006D0073005F0044006100740061005F005400610062006C006500730000000000000000000000C40200000000080000000800000007000000080000000100650D8800650D0000000000000000AD0700000000000D0000000D00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003200390035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C00310036003600350000001200000012000000000000005E00000001FF5F5E01000000640062006F00000046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F0043006F006C0075006D006E0049006E0066006F0000000000000000000000C40200000000130000001300000012000000080000000100650D4800650D0000000000000000AD0700000000001600000016000000000000006400000001016F0001000000640062006F00000046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F0043006100740061006C006F006700750065004900740065006D0000000000000000000000C40200000000170000001700000016000000080000000100650D0800650D0000000000000000AD070000000000180000001800000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000001900000019000000000000005000000001FF5F5E01000000640062006F00000046004B005F0053007500700070006F007200740069006E00670044006F00630075006D0065006E0074005F0043006100740061006C006F0067007500650000000000000000000000C402000000001A0000001A000000190000000800000001FF640DC8FF640D0000000000000000AD0700000000001B0000001B00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003400300030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000220000002200000000000000740000000102000001000000640062006F00000046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0000000000000000000000C402000000002300000023000000220000000800000001FF640D88FF640D0000000000000000AD070000000000240000002400000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003000370030002C0031002C0031003600390035002C0035002C0031003100320035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003000370030002C00310032002C0032003400340035002C00310031002C00310035003000300000002700000027000000000000003A0000000106000001000000640062006F00000046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F0000000000000000000000C402000000002800000028000000270000000800000001FF640D48FF640D0000000000000000AD0700000000002900000029000000000000003C0000000107000001000000640062006F00000046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F00310000000000000000000000C402000000002A0000002A000000290000000800000001FF640D08FF640D0000000000000000AD0700000000002B0000002B000000000000003C0000000105000001000000640062006F00000046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F00320000000000000000000000C402000000002C0000002C0000002B0000000800000001FE640DC8FE640D0000000000000000AD0700000000002F0000002F00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003000370030002C0031002C0031003600320030002C0035002C0031003100320035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003000370030002C00310032002C0032003400340035002C00310031002C00310035003000300000003300000033000000000000005000000001FF5F5E01000000640062006F00000046004B005F004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F004A006F0069006E004B0065007900310000000000000000000000C402000000003400000034000000330000000800000001FE640D88FE640D0000000000000000AD0700000000003500000035000000000000005000000001FF5F5E01000000640062006F00000046004B005F004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F004A006F0069006E004B0065007900320000000000000000000000C402000000003600000036000000350000000800000001FE640D48FE640D0000000000000000AD070000000000380000003800000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003000350035002C0031002C0031003100370030002C0035002C0031003000360035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000003900000039000000000000006400000001006F0001000000640062006F00000046004B005F00450078007400720061006300740069006F006E00460069006C007400650072005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0000000000000000000000C402000000003A0000003A000000390000000800000001FE640D08FE640D0000000000000000AD0700000000003B0000003B00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0031003500340035002C0031002C0031003100370030002C0035002C0031003000360035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000003C0000003C000000000000006C000000011A5F5E01000000640062006F00000046004B005F00450078007400720061006300740069006F006E00460069006C0074006500720050006100720061006D0065007400650072005F00450078007400720061006300740069006F006E00460069006C0074006500720000000000000000000000C402000000003D0000003D0000003C0000000800000001FD640DC8FD640D0000000000000000AD070000000000400000004000000000000000560000000103737401000000640062006F00000046004B005F0043006100740061006C006F006700750065005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0000000000000000000000C402000000004100000041000000400000000800000001FD640D88FD640D0000000000000000AD0700000000004C0000004C00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0035003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000540000005400000000000000540000000103737401000000640062006F00000046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F004C006F006F006B007500700000000000000000000000C402000000005500000055000000540000000800000001FD640D48FD640D0000000000000000AD0700000000005600000056000000000000005C00000001FF5F5E01000000640062006F00000046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F0000000000000000000000C402000000005700000057000000560000000800000001FD640D08FD640D0000000000000000AD0700000000005900000059000000000000006200000001006F0001000000640062006F00000046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F0046004B0000000000000000000000C402000000005A0000005A000000590000000800000001FC640DC8FC640D0000000000000000AD0700000000005C0000005C00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000005D0000005D000000000000005000000001FF5F5E01000000640062006F00000046004B005F0053007500700070006F007200740069006E006700530051004C005400610062006C0065005F0043006100740061006C006F0067007500650000000000000000000000C402000000005E0000005E0000005D0000000800000001FC640D88FC640D0000000000000000AD0700000000005F0000005F00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000600000006000000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003600340030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000630000006300000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0033003100320030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000640000006400000000000000800000000106401001000000640062006F00000046004B005F00410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E00650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720000000000000000000000C402000000006500000065000000640000000800000001FC640D48FC640D0000000000000000AD0700000000006600000066000000000000008200000001FF690001000000640062006F00000046004B005F00410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E00650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E0065007200310000000000000000000000C402000000006700000067000000660000000800000001F57115C8F571150000000000000000AD0700000000006E0000006E00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0034003600350030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000006F0000006F000000000000006800000001006F0001000000640062006F00000046004B005F00410067006700720065006700610074006500460069006C007400650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720000000000000000000000C4020000000070000000700000006F0000000800000001F5711588F571150000000000000000AD070000000000710000007100000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003600350035002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000007200000072000000000000006A000000011A5F5E01000000640062006F00000046004B005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E0000000000000000000000C402000000007300000073000000720000000800000001F5711548F571150000000000000000AD070000000000740000007400000000000000760000000102000001000000640062006F00000046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720000000000000000000000C402000000007500000075000000740000000800000001F5711508F571150000000000000000AD070000000000760000007600000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000007700000077000000000000006800000001016F0001000000640062006F00000046004B005F00410067006700720065006700610074006500460069006C0074006500720050006100720061006D0065007400650072005F00410067006700720065006700610074006500460069006C0074006500720000000000000000000000C402000000007800000078000000770000000800000001F47115C8F471150000000000000000AD0700000000007C0000007C00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0033003100380030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0034003900350030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000810000008100000000000000580000000103737401000000640062006F00000046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F0043006100740061006C006F006700750065004900740065006D0000000000000000000000C402000000008200000082000000810000000800000001F4711588F471150000000000000000AD070000000000830000008300000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000008400000084000000000000006800000001016F0001000000640062006F00000046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F004F0077006E00650072005F0049007300730075006500530079007300740065006D00550073006500720000000000000000000000C402000000008500000085000000840000000800000001F4711548F471150000000000000000AD0700000000008600000086000000000000006E000000011A5F5E01000000640062006F00000046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F005200650070006F0072007400650072005F0049007300730075006500530079007300740065006D00550073006500720000000000000000000000C402000000008700000087000000860000000800000001F4711508F471150000000000000000AD070000000000880000008800000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000008B0000008B000000000000003E0000000105000001000000640062006F00000046004B005F0043006F006C0075006D006E0049006E0066006F005F0041004E004F005400610062006C00650000000000000000000000C402000000008C0000008C0000008B0000000800000001F37115C8F371150000000000000000AD0700000000008D0000008D00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003100330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000008E0000008E00000000000000580000000102737401000000640062006F00000046004B005F005000720065004C006F006100640044006900730063006100720064006500640043006F006C0075006D006E005F005400610062006C00650049006E0066006F0000000000000000000000C402000000008F0000008F0000008E0000000800000001F3711588F371150000000000000000AD070000000000900000009000000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003600300035002C0031002C0031003300320030002C0035002C003800370030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003600300035000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003600300035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003600300035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003600300035002C00310032002C0031003900300035002C00310031002C0031003100370030000000910000009100000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003200390035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C0031003600360035000000940000009400000000000000560000000101737401000000640062006F00000046004B005F00500072006F0063006500730073005400610073006B0041007200670075006D0065006E0074005F00500072006F0063006500730073005400610073006B0000000000000000000000C402000000009500000095000000940000000800000001F3711548F371150000000000000000AD0700000000009600000096000000000000006800000001016F0001000000640062006F00000046004B005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0000000000000000000000C402000000009700000097000000960000000800000001F3711508F371150000000000000000AD0700000000009A0000009A000000000000004200000001038A7601000000640062006F00000046004B005F00500072006F0063006500730073005400610073006B005F0043006100740061006C006F0067007500650000000000000000000000C402000000009B0000009B0000009A0000000800000001F27115C8F271150000000000000000AD0700000000009C0000009C000000000000000800000001F2711588F271150000000000000000E40700000000009D0000009D00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000009E0000009E00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0033003500320035002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008002000000032002C0030002C003200380034002C0030002C00310030003800370035000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000A2000000A200000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000A3000000A300000000000000580000000103737401000000640062006F00000046004B005F005400610062006C00650049006E0066006F005F00450078007400650072006E0061006C004400610074006100620061007300650053006500720076006500720000000000000000000000C40200000000A4000000A4000000A30000000800000001F2711548F271150000000000000000AD070000000000A6000000A600000000000000580000000103737401000000640062006F00000046004B005F0043006100740061006C006F006700750065005F00450078007400650072006E0061006C004400610074006100620061007300650053006500720076006500720000000000000000000000C40200000000A7000000A7000000A60000000800000001F2711508F271150000000000000000AD070000000000A8000000A8000000000000005A00000001075F5E01000000640062006F00000046004B005F0043006100740061006C006F006700750065005F00450078007400650072006E0061006C0044006100740061006200610073006500530065007200760065007200310000000000000000000000C40200000000A9000000A9000000A80000000800000001F17115C8F171150000000000000000AD070000000000AA000000AA00000000000000560000000103737401000000640062006F00000046004B005F0041004E004F005400610062006C0065005F00450078007400650072006E0061006C004400610074006100620061007300650053006500720076006500720000000000000000000000C40200000000AB000000AB000000AA0000000800000001F1711588F171150000000000000000AD070000000000AC000000AC00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0033003400360035002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000AF000000AF000000000000006A000000011A5F5E01000000640062006F00000046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E0000000000000000000000C40200000000B0000000B0000000AF0000000800000001F1711548F171150000000000000000AD070000000000BD000000BD00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000031000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0033003400350030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000BE000000BE000000000000004400000001038A7601000000640062006F00000046004B005F0043006100740061006C006F006700750065005F004C006F00610064004D00650074006100640061007400610000000000000000000000C40200000000BF000000BF000000BE0000000800000001F1711508F171150000000000000000AD070000000000C0000000C000000000000000520000000103737401000000640062006F00000046004B005F004C006F006100640050006500720069006F0064006900630061006C006C0079005F004C006F00610064004D00650074006100640061007400610000000000000000000000C40200000000C1000000C1000000C00000000800000001F07115C8F071150000000000000000AD070000000000C2000000C2000000000000004800000001038A7601000000640062006F00000046004B005F00500072006F0063006500730073005400610073006B005F004C006F00610064004D00650074006100640061007400610000000000000000000000C40200000000C3000000C3000000C20000000800000001F0711588F071150000000000000000AD070000000000C4000000C4000000000000004A00000001FF5F5E01000000640062006F00000046004B005F004C006F00610064005300630068006500640075006C0065005F004C006F00610064004D00650074006100640061007400610000000000000000000000C40200000000C5000000C5000000C40000000800000001F0711548F071150000000000000000AD070000000000C6000000C600000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003700390030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000C7000000C7000000000000006600000001006F0001000000640062006F00000046004B005F0044004C004500570069006E0064006F0077007300530065007200760069006300650045007800630065007000740069006F006E005F004C006F00610064004D00650074006100640061007400610000000000000000000000C40200000000C8000000C8000000C70000000800000001F0711508F071150000000000000000AD070000000000C9000000C900000000000000540000000103737401000000640062006F00000046004B005F004C006F006100640050006500720069006F0064006900630061006C006C0079005F004C006F00610064004D006500740061006400610074006100310000000000000000000000C40200000000CA000000CA000000C90000000800000001EF7115C8EF71150000000000000000AD070000000000CB000000CB00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003200390035002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000CC000000CC00000000000000740000000102000001000000640062006F00000046004B005F0041006700670072006500670061007400650043006F006E00740069006E0075006F0075007300440061007400650041007800690073005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E0000000000000000000000C40200000000CD000000CD000000CC0000000800000001EF711588EF71150000000000000000AD070000000000D0000000D000000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003300320035002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000D1000000D1000000000000006C000000011A5F5E01000000640062006F00000046004B005F0041006700670072006500670061007400650046006F0072006300650064004A006F0069006E005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E0000000000000000000000C40200000000D2000000D2000000D10000000800000001EF711548EF71150000000000000000AD070000000000D3000000D300000000000000520000000100737401000000640062006F00000046004B005F0041006700670072006500670061007400650046006F0072006300650064004A006F0069006E005F005400610062006C00650049006E0066006F0000000000000000000000C40200000000D4000000D4000000D30000000800000001B5511558B551150000000000000000AD070000000000D5000000D500000000000000580000000103737401000000640062006F00000046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F0043006100740061006C006F0067007500650000000000000000000000C40200000000D6000000D6000000D50000000800000001337715E03377150000000000000000AD0F0000010000EB00000081000000010000007C00000056000000D200000016000000010000000D0000008C00000085000000D5000000020000005F0000008C000000710000005D000000020000005C00000097000000AA0000001900000002000000180000009F0000008000000003000000020000000100000000000000010000009A0000000200000090000000E30100002100000007000000050000000600000038000000210000008E000000050000008D0000008C00000093000000D300000005000000D00000008D000000A600000012000000060000000D0000008A000000C80000002700000006000000240000002A000000390000002900000006000000240000003C0000004B0000002B0000000600000024000000200000002F00000033000000060000002F000000A20000008D00000035000000060000002F000000B20000009D00000056000000060000004C000000140000009C00000059000000060000004C0000000600000090000000960000001B00000071000000930000003D000000220000001B0000000D0000004000000033000000390000001B00000038000000170000004E000000400000001B000000020000007F000000C001000054000000240000004C0000001C0000001B0000003C000000380000003B000000350000002C000000720000005F00000071000000A500000090000000D10000005F000000D00000000F0000007200000074000000600000005F00000080000000730000006F000000600000006E0000009F000000720000006600000060000000630000007300000088000000640000006000000063000000870000009C000000770000006E000000760000007900000072000000AF000000710000005F000000B6000000CB000000CC00000071000000CB0000004B0000000000000084000000830000007C00000009000000B700000086000000830000007C000000A60000007C0000008B000000880000000600000073000000E2000000940000009000000091000000830000008C000000AA000000A2000000880000009C00000037000000A8000000A2000000020000006D0000001A020000A6000000A2000000020000008100000008020000A3000000A200000005000000940000003F000000C9000000BD000000AC0000004D0000005C000000BE000000BD000000020000006000000013010000C0000000BD000000AC0000001101000002000000C2000000BD00000090000000AD000000AC000000C4000000BD0000009E000000F7000000C2000000C7000000BD000000C6000000010000002E0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000700070006C00690063006100740069006F006E0020004E0061006D0065003D0022004D006900630072006F0073006F00660074002000530051004C00200053006500720076006500720020004D0061006E006100670065006D0065006E0074002000530074007500640069006F0022000000008005002E00000043006100740061006C006F006700750065005F0044006100740061005F004400690061006700720061006D000000000226002800000041006700670072006500670061007400650046006F0072006300650064004A006F0069006E00000008000000640062006F000000000226003800000041006700670072006500670061007400650043006F006E00740069006E0075006F007500730044006100740065004100780069007300000008000000640062006F000000000226003600000044004C004500570069006E0064006F0077007300530065007200760069006300650045007800630065007000740069006F006E00000008000000640062006F000000000226001A0000004C006F00610064004D006500740061006400610074006100000008000000640062006F00000000022600220000004C006F006100640050006500720069006F0064006900630061006C006C007900000008000000640062006F000000000226002E000000450078007400650072006E0061006C0044006100740061006200610073006500530065007200760065007200000008000000640062006F000000000226001A0000004C006F00610064005300630068006500640075006C006500000008000000640062006F00000000022600260000004C006F00610064004D006F00640075006C00650041007300730065006D0062006C007900000008000000640062006F0000000002260028000000500072006F0063006500730073005400610073006B0041007200670075006D0065006E007400000008000000640062006F0000000002260018000000500072006F0063006500730073005400610073006B00000008000000640062006F000000000226002E0000005000720065004C006F006100640044006900730063006100720064006500640043006F006C0075006D006E00000008000000640062006F000000000226001200000041004E004F005400610062006C006500000008000000640062006F000000000226002000000049007300730075006500530079007300740065006D005500730065007200000008000000640062006F000000000226002600000043006100740061006C006F006700750065004900740065006D0049007300730075006500000008000000640062006F0000000002260032000000410067006700720065006700610074006500460069006C0074006500720050006100720061006D006500740065007200000008000000640062006F0000000002260026000000410067006700720065006700610074006500440069006D0065006E00730069006F006E00000008000000640062006F0000000002260020000000410067006700720065006700610074006500460069006C00740065007200000008000000640062006F0000000002260038000000410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E0065007200000008000000640062006F0000000002260032000000410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E0065007200000008000000640062006F000000000226002E00000041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E00000008000000640062006F000000000226002600000053007500700070006F007200740069006E006700530051004C005400610062006C006500000008000000640062006F00000000022600300000004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F00000008000000640062006F0000000002260034000000450078007400720061006300740069006F006E00460069006C0074006500720050006100720061006D006500740065007200000008000000640062006F0000000002260022000000450078007400720061006300740069006F006E00460069006C00740065007200000008000000640062006F00000000022600120000004A006F0069006E0049006E0066006F00000008000000640062006F000000000226000E0000004C006F006F006B0075007000000008000000640062006F000000000226002C000000450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E00000008000000640062006F000000000226002600000053007500700070006F007200740069006E00670044006F00630075006D0065006E007400000008000000640062006F000000000226003200000043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D00000008000000640062006F000000000226001600000043006F006C0075006D006E0049006E0066006F00000008000000640062006F00000000022600140000005400610062006C00650049006E0066006F00000008000000640062006F000000000226001400000043006100740061006C006F00670075006500000008000000640062006F000000000224001C00000043006100740061006C006F006700750065004900740065006D00000008000000640062006F00000001000000D68509B3BB6BF2459AB8371664F0327008004E0000007B00310036003300340043004400440037002D0030003800380038002D0034003200450033002D0039004600410032002D004200360044003300320035003600330042003900310044007D00000000000000000000000000000000000000000000000000000000000000010003000000000000000C0000000B00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000062885214) \ No newline at end of file +0xD0CF11E0A1B11AE1000000000000000000000000000000003E000300FEFF0900060000000000000000000000020000000100000000000000001000005A00000001000000FEFFFFFF00000000000000005D000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFF5C000000030000000400000005000000060000000700000008000000090000000A0000000B0000000C0000000D0000000E0000000F000000100000001100000012000000130000001400000015000000160000001700000018000000FEFFFFFF1A0000001B0000001C0000001D0000001E0000001F000000200000002100000022000000230000002400000025000000260000002700000028000000290000002A0000002B0000002C0000002D0000002E0000002F000000300000003100000032000000330000003400000035000000360000003700000038000000390000003A0000003B0000003C0000003D0000003E0000003F000000400000004100000042000000430000004400000045000000460000004700000048000000490000004A0000004B0000004C0000004D0000004E0000004F00000050000000510000005200000053000000540000005500000056000000570000005800000059000000FEFFFFFFFEFFFFFF91000000FEFFFFFFFDFFFFFF5F000000600000006100000062000000630000006400000065000000660000006700000068000000690000006A0000006B0000006C0000006D0000006E0000006F000000700000007100000072000000730000007400000075000000760000007700000078000000790000007A0000007B0000007C0000007D0000007E0000007F0000008000000052006F006F007400200045006E00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500FFFFFFFFFFFFFFFF0200000000000000000000000000000000000000000000000000000000000000705AF83BF38BD0015B000000C00A0000000000006600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000201FFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000002000000322C0000000000006F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040002010100000004000000FFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000019000000AC80000000000000010043006F006D0070004F0062006A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000201FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000005F00000000000000000438000A1ED00D05000080D60000000F00FFFF5000000000000000D6000000007D0000E6930000175900001A9401001A4301000CCFFFFF7289FFFFDE805B10F195D011B0A000AA00BDCB5C000008003000000000020000030000003C006B0000000900000000000000D9E6B0E91C81D011AD5100A0C90F5739F43B7F847F61C74385352986E1D552F8A0327DB2D86295428D98273C25A2DA2D00002800430000000000000053444DD2011FD1118E63006097D2DF4834C9D2777977D811907000065B840D9C00002800430000000000000051444DD2011FD1118E63006097D2DF4834C9D2777977D811907000065B840D9C80000000382B000000FF01000170931500003800A50900000700008001000000AC020000008000000D0000805363684772696400A8480000E6FBFFFF436174616C6F6775654974656D07000000003400A50900000700008002000000A402000000800000090000805363684772696400A84800001E2D0000436174616C6F67756549746500008000A50900000700008003000000520000000180000058000080436F6E74726F6C00A74700004521000052656C6174696F6E736869702027464B5F436174616C6F6775655F4974656D735F446174615F436174616C6F67756527206265747765656E2027436174616C6F6775652720616E642027436174616C6F6775654974656D2700002800B50100000700008004000000310000007500000002800000436F6E74726F6C00ED490000E327000000003400A50900000700008005000000A402000000800000090000805363684772696400F4CFFFFF903300005461626C65496E666F49746500003400A50900000700008006000000A6020000008000000A0000805363684772696400FCD6FFFF6AFFFFFF436F6C756D6E496E666F746500007800A5090000070000800700000052000000018000004E000080436F6E74726F6C005BDFFFFF492A000052656C6174696F6E736869702027464B5F5461626C655F4974656D735F446174615F5461626C657327206265747765656E20275461626C65496E666F2720616E642027436F6C756D6E496E666F27000000002800B50100000700008008000000310000006700000002800000436F6E74726F6C00A1E1FFFF4E2F000000004000A5090000070000800D000000C20200000080000018000080536368477269640094110000A2E5FFFF436F6C756D6E496E666F5F436174616C6F6775654974656D00009400A509000007000080120000005A0000000180000069000080436F6E74726F6C0069FEFFFF51F6FFFF52656C6174696F6E736869702027464B5F436F6C756D6E496E666F5F436174616C6F6775654974656D5F436F6C756D6E496E666F27206265747765656E2027436F6C756D6E496E666F2720616E642027436F6C756D6E496E666F5F436174616C6F6775654974656D2700690000002800B50100000700008013000000310000007F00000002800000436F6E74726F6C00ABF6FFFFC5F5FFFF00009800A509000007000080160000006A000000018000006F000080436F6E74726F6C005B37000093F7FFFF52656C6174696F6E736869702027464B5F436F6C756D6E496E666F5F436174616C6F6775654974656D5F436174616C6F6775654974656D27206265747765656E2027436174616C6F6775654974656D2720616E642027436F6C756D6E496E666F5F436174616C6F6775654974656D270000002800B50100000700008017000000310000008500000002800000436F6E74726F6C005A29000075FAFFFF00003C00A50900000700008018000000B602000000800000120000805363684772696400FA7D00004A2E0000537570706F7274696E67446F63756D656E74756500008400A5090000070000801900000052000000018000005B000080436F6E74726F6C00F57000006331000052656C6174696F6E736869702027464B5F537570706F7274696E67446F63756D656E745F436174616C6F67756527206265747765656E2027436174616C6F6775652720616E642027537570706F7274696E67446F63756D656E74270000002800B5010000070000801A000000310000007100000002800000436F6E74726F6C004F6E0000A933000000004000A5090000070000801B000000BC020000008000001500008053636847726964007A0D0000E40C000045787472616374696F6E496E666F726D6174696F6E74656D0000A800A5090000070000802200000052000000018000007F000080436F6E74726F6C00391F000093F7FFFF52656C6174696F6E736869702027464B5F436F6C756D6E496E666F5F436174616C6F6775654974656D5F45787472616374696F6E496E666F726D6174696F6E27206265747765656E202745787472616374696F6E496E666F726D6174696F6E2720616E642027436F6C756D6E496E666F5F436174616C6F6775654974656D270000002800B50100000700008023000000310000009500000002800000436F6E74726F6C007F210000ED02000000003000A509000007000080240000009E02000000800000060000805363684772696400E2D2FFFF16DBFFFF4C6F6F6B7570640000007000A50900000700008027000000520000000180000045000080436F6E74726F6C0049E2FFFF49EDFFFF52656C6174696F6E736869702027464B5F4C6F6F6B75705F436F6C756D6E496E666F27206265747765656E2027436F6C756D6E496E666F2720616E6420274C6F6F6B757027D0135E00002800B50100000700008028000000310000005B00000002800000436F6E74726F6C008FE4FFFF0BF7FFFF00007000A50900000700008029000000520000000180000046000080436F6E74726F6C008FE7FFFF49EDFFFF52656C6174696F6E736869702027464B5F4C6F6F6B75705F436F6C756D6E496E666F3127206265747765656E2027436F6C756D6E496E666F2720616E6420274C6F6F6B757027135E00002800B5010000070000802A000000310000005D00000002800000436F6E74726F6C00D5E9FFFF0BF7FFFF00007000A5090000070000802B000000520000000180000046000080436F6E74726F6C005BDFFFFF49EDFFFF52656C6174696F6E736869702027464B5F4C6F6F6B75705F436F6C756D6E496E666F3227206265747765656E2027436F6C756D6E496E666F2720616E6420274C6F6F6B757027135E00002800B5010000070000802C000000310000005D00000002800000436F6E74726F6C00A1E1FFFF0BF7FFFF00003000A5090000070000802F000000A202000000800000080000805363684772696400A0ABFFFF12FDFFFF4A6F696E496E666F00007C00A50900000700008033000000520000000180000052000080436F6E74726F6C6F70D0FFFF95FFFFFF52656C6174696F6E736869702027464B5F4A6F696E496E666F5F436F6C756D6E496E666F5F4A6F696E4B65793127206265747765656E2027436F6C756D6E496E666F2720616E6420274A6F696E496E666F27654900002800B50100000700008034000000310000007100000002800000436F6E74726F6C6F9CD1FFFF25FFFFFF00007C00A50900000700008035000000520000000180000052000080436F6E74726F6C6F70D0FFFF4504000052656C6174696F6E736869702027464B5F4A6F696E496E666F5F436F6C756D6E496E666F5F4A6F696E4B65793227206265747765656E2027436F6C756D6E496E666F2720616E6420274A6F696E496E666F27654900002800B50100000700008036000000310000007100000002800000436F6E74726F6C6F9CD1FFFFD503000000003800A50900000700008038000000B20200000080000010000080536368477269646F12FDFFFFE835000045787472616374696F6E46696C74657200009800A5090000070000803900000052000000018000006F000080436F6E74726F6C6FEB1200001F2B000052656C6174696F6E736869702027464B5F45787472616374696F6E46696C7465725F45787472616374696F6E496E666F726D6174696F6E27206265747765656E202745787472616374696F6E496E666F726D6174696F6E2720616E64202745787472616374696F6E46696C746572270000002800B5010000070000803A000000310000008500000002800000436F6E74726F6C6F11FDFFFF3331000000004400A5090000070000803B000000C40200000080000019000080536368477269646F6AFFFFFFF654000045787472616374696F6E46696C746572506172616D657465720000000000A000A5090000070000803C000000520000000180000077000080436F6E74726F6C6F4D0B0000F64A000052656C6174696F6E736869702027464B5F45787472616374696F6E46696C746572506172616D657465725F45787472616374696F6E46696C74657227206265747765656E202745787472616374696F6E46696C7465722720616E64202745787472616374696F6E46696C746572506172616D65746572270000002800B5010000070000803D000000310000008D00000002800000436F6E74726F6C6F6DF3FFFFA550000000008C00A509000007000080400000005A0000000180000061000080436F6E74726F6C6F633100001F2B000052656C6174696F6E736869702027464B5F436174616C6F6775655F45787472616374696F6E496E666F726D6174696F6E27206265747765656E202745787472616374696F6E496E666F726D6174696F6E2720616E642027436174616C6F6775652700650000002800B50100000700008041000000310000007700000002800000436F6E74726F6C6F3E1E0000C76B000000004000A5090000070000804C000000C00200000080000017000080536368477269646F78D3FFFF22C0FFFF4C6F6F6B7570436F6D706F736974654A6F696E496E666F6D00008800A5090000070000805400000052000000018000005F000080436F6E74726F6C6F15DAFFFFC9D4FFFF52656C6174696F6E736869702027464B5F4C6F6F6B7570436F6D706F736974654A6F696E496E666F5F4C6F6F6B757027206265747765656E20274C6F6F6B75702720616E6420274C6F6F6B7570436F6D706F736974654A6F696E496E666F270000002800B50100000700008055000000310000007500000002800000436F6E74726F6C6F5BDCFFFFA1D8FFFF00009000A509000007000080560000006A0000000180000067000080436F6E74726F6C6F0FC8FFFF9DC8FFFF52656C6174696F6E736869702027464B5F4C6F6F6B7570436F6D706F736974654A6F696E496E666F5F436F6C756D6E496E666F27206265747765656E2027436F6C756D6E496E666F2720616E6420274C6F6F6B7570436F6D706F736974654A6F696E496E666F270000002800B50100000700008057000000310000007D00000002800000436F6E74726F6C6FEAC9FFFF9AE8FFFF00009400A509000007000080590000006A000000018000006A000080436F6E74726F6C6F57C1FFFF19C5FFFF52656C6174696F6E736869702027464B5F4C6F6F6B7570436F6D706F736974654A6F696E496E666F5F436F6C756D6E496E666F5F464B27206265747765656E2027436F6C756D6E496E666F2720616E6420274C6F6F6B7570436F6D706F736974654A6F696E496E666F276C7400002800B5010000070000805A000000310000008300000002800000436F6E74726F6C6F32C3FFFF08E5FFFF00003C00A5090000070000805C000000B60200000080000012000080536368477269646FDAAC0000D20F0000537570706F7274696E6753514C5461626C656E4900008400A5090000070000805D00000062000000018000005B000080436F6E74726F6C6FF5700000551F000052656C6174696F6E736869702027464B5F537570706F7274696E6753514C5461626C655F436174616C6F67756527206265747765656E2027436174616C6F6775652720616E642027537570706F7274696E6753514C5461626C65276E00002800B5010000070000805E000000310000007100000002800000436F6E74726F6C6F217200005131000000004000A5090000070000805F000000BE0200000080000016000080536368477269646FC201000086A7FFFF416767726567617465436F6E66696775726174696F6E6F6D00004000A50900000700008060000000C20200000080000018000080536368477269646F5C2B00006CA3FFFF41676772656761746546696C746572436F6E7461696E657200004400A50900000700008063000000C8020000008000001B000080536368477269646F7A580000FA9CFFFF41676772656761746546696C746572537562436F6E7461696E6572000000B400A5090000070000806400000052000000018000008B000080436F6E74726F6C6F6C4C000047A8FFFF52656C6174696F6E736869702027464B5F41676772656761746546696C746572537562436F6E7461696E65725F41676772656761746546696C746572436F6E7461696E657227206265747765656E202741676772656761746546696C746572436F6E7461696E65722720616E64202741676772656761746546696C746572537562436F6E7461696E6572270000002800B5010000070000806500000031000000A100000002800000436F6E74726F6C6FED4200008DAAFFFF0000B400A5090000070000806600000052000000018000008C000080436F6E74726F6C6F6C4C00006BA2FFFF52656C6174696F6E736869702027464B5F41676772656761746546696C746572537562436F6E7461696E65725F41676772656761746546696C746572436F6E7461696E65723127206265747765656E202741676772656761746546696C746572436F6E7461696E65722720616E64202741676772656761746546696C746572537562436F6E7461696E65722700002800B5010000070000806700000031000000A300000002800000436F6E74726F6C6F96420000FBA1FFFF00003800A5090000070000806E000000B0020000008000000F000080536368477269646F1059000050B0FFFF41676772656761746546696C7465727200009C00A5090000070000806F000000520000000180000073000080436F6E74726F6C6F6C4C00004FAFFFFF52656C6174696F6E736869702027464B5F41676772656761746546696C7465725F41676772656761746546696C746572436F6E7461696E657227206265747765656E202741676772656761746546696C746572436F6E7461696E65722720616E64202741676772656761746546696C746572277400002800B50100000700008070000000310000008900000002800000436F6E74726F6C6F55440000DFAEFFFF00003C00A50900000700008071000000B60200000080000012000080536368477269646FB42D000000B5FFFF41676772656761746544696D656E73696F6E74610000A000A50900000700008072000000520000000180000075000080436F6E74726F6C6FCC2200002BB5FFFF52656C6174696F6E736869702027464B5F41676772656761746544696D656E73696F6E5F416767726567617465436F6E66696775726174696F6E27206265747765656E2027416767726567617465436F6E66696775726174696F6E2720616E64202741676772656761746544696D656E73696F6E2772270000002800B50100000700008073000000310000008B00000002800000436F6E74726F6C6F351B000071B7FFFF0000AC00A50900000700008074000000520000000180000081000080436F6E74726F6C6FCC22000085A6FFFF52656C6174696F6E736869702027464B5F416767726567617465436F6E66696775726174696F6E5F41676772656761746546696C746572436F6E7461696E657227206265747765656E202741676772656761746546696C746572436F6E7461696E65722720616E642027416767726567617465436F6E66696775726174696F6E2700000000002800B50100000700008075000000310000009700000002800000436F6E74726F6C6FE818000015A6FFFF00004000A50900000700008076000000C20200000080000018000080536368477269646FD683000012B2FFFF41676772656761746546696C746572506172616D6574657200009C00A50900000700008077000000520000000180000073000080436F6E74726F6C6F1A7A000011B1FFFF52656C6174696F6E736869702027464B5F41676772656761746546696C746572506172616D657465725F41676772656761746546696C74657227206265747765656E202741676772656761746546696C7465722720616E64202741676772656761746546696C746572506172616D65746572276E00002800B50100000700008078000000310000008900000002800000436F6E74726F6C6FF072000057B3FFFF00003C00A5090000070000807C000000B60200000080000012000080536368477269646FF27600000CE5FFFF436174616C6F6775654974656D4973737565616D00008C00A509000007000080810000005A0000000180000063000080436F6E74726F6C6FD9600000F9F3FFFF52656C6174696F6E736869702027464B5F436174616C6F6775654974656D49737375655F436174616C6F6775654974656D27206265747765656E2027436174616C6F6775654974656D2720616E642027436174616C6F6775654974656D4973737565276E00002800B50100000700008082000000310000007900000002800000436F6E74726F6C6F8062000023F6FFFF00003800A50900000700008083000000B0020000008000000F000080536368477269646FF4B0000070CCFFFF497373756553797374656D557365727200009800A509000007000080840000005A000000018000006D000080436F6E74726F6C6F48A400004CDFFFFF52656C6174696F6E736869702027464B5F436174616C6F6775654974656D49737375655F4F776E65725F497373756553797374656D5573657227206265747765656E2027497373756553797374656D557365722720616E642027436174616C6F6775654974656D49737375652772270000002800B50100000700008085000000310000008900000002800000436F6E74726F6C6FF09700007CE3FFFF00009800A509000007000080860000005A0000000180000070000080436F6E74726F6C6F619A0000ABDAFFFF52656C6174696F6E736869702027464B5F436174616C6F6775654974656D49737375655F5265706F727465725F497373756553797374656D5573657227206265747765656E2027497373756553797374656D557365722720616E642027436174616C6F6775654974656D49737375652700002800B50100000700008087000000310000008F00000002800000436F6E74726F6C6F4B9200003BDAFFFF00003000A50900000700008088000000A20200000080000008000080536368477269646FC694FFFF56130000414E4F5461626C6500007400A5090000070000808B000000520000000180000049000080436F6E74726F6C65D6B5FFFF5512000052656C6174696F6E736869702027464B5F436F6C756D6E496E666F5F414E4F5461626C6527206265747765656E2027414E4F5461626C652720616E642027436F6C756D6E496E666F27496E6600002800B5010000070000808C000000310000005F00000002800000436F6E74726F6C65D8BFFFFF9B14000000004000A5090000070000808D000000BE0200000080000016000080536368477269646586A7FFFF302A00005072654C6F6164446973636172646564436F6C756D6E657200008C00A5090000070000808E000000520000000180000063000080436F6E74726F6C6596C8FFFF8F32000052656C6174696F6E736869702027464B5F5072654C6F6164446973636172646564436F6C756D6E5F5461626C65496E666F27206265747765656E20275461626C65496E666F2720616E6420275072654C6F6164446973636172646564436F6C756D6E276E00002800B5010000070000808F000000310000007900000002800000436F6E74726F6C6519C2FFFF1F32000000003C00A50900000700008091000000B80200000080000013000080536368477269646536D80000565E000050726F636573735461736B417267756D656E747500008C00A50900000700008094000000520000000180000061000080436F6E74726F6C6572D00000555D000052656C6174696F6E736869702027464B5F50726F636573735461736B417267756D656E745F50726F636573735461736B27206265747765656E202750726F636573735461736B2720616E64202750726F636573735461736B417267756D656E74276E276E00002800B50100000700008095000000310000007700000002800000436F6E74726F6C6544CA0000E55C000000003400A50900000700008090000000A8020000008000000B00008053636847726964659CAE0000D25A000050726F636573735461736B5500009C00A509000007000080960000005A0000000180000073000080436F6E74726F6C65F837000065C9FFFF52656C6174696F6E736869702027464B5F41676772656761746544696D656E73696F6E5F45787472616374696F6E496E666F726D6174696F6E27206265747765656E202745787472616374696F6E496E666F726D6174696F6E2720616E64202741676772656761746544696D656E73696F6E276E00002800B50100000700008097000000310000008900000002800000436F6E74726F6C658D4000008BF0FFFF00007800A5090000070000809A0000005A000000018000004D000080436F6E74726F6C65F5700000E87C000052656C6174696F6E736869702027464B5F50726F636573735461736B5F436174616C6F67756527206265747765656E2027436174616C6F6775652720616E64202750726F636573735461736B2727000000002800B5010000070000809B000000310000006300000002800000436F6E74726F6C65E99E00009592000000002400A5010000070000809C0000007100000002800000436F6E74726F6C65C47200005355000000003C00A5090000070000809D000000B60200000080000012000080536368477269646592B80000383100004C6F61644D6F64756C65417373656D626C79747500003400A5090000070000809E000000AA020000008000000C0000805363684772696465D8BD0000408300004C6F61645363686564756C6500004000A509000007000080A2000000BE0200000080000016000080536368477269646536F7FFFF0E6A000045787465726E616C4461746162617365536572766572657200008C00A509000007000080A30000005A0000000180000063000080436F6E74726F6C6539E1FFFF8E56000052656C6174696F6E736869702027464B5F5461626C65496E666F5F45787465726E616C446174616261736553657276657227206265747765656E202745787465726E616C44617461626173655365727665722720616E6420275461626C65496E666F276E00002800B501000007000080A4000000310000007900000002800000436F6E74726F6C6544CDFFFFAB6D000000008C00A509000007000080A60000005A0000000180000063000080436F6E74726F6C65B51B00006780000052656C6174696F6E736869702027464B5F436174616C6F6775655F45787465726E616C446174616261736553657276657227206265747765656E202745787465726E616C44617461626173655365727665722720616E642027436174616C6F677565276E00002800B501000007000080A7000000310000007900000002800000436F6E74726F6C65F50F0000B79D000000008C00A509000007000080A80000005A0000000180000064000080436F6E74726F6C65D91500006780000052656C6174696F6E736869702027464B5F436174616C6F6775655F45787465726E616C44617461626173655365727665723127206265747765656E202745787465726E616C44617461626173655365727665722720616E642027436174616C6F6775652700002800B501000007000080A9000000310000007B00000002800000436F6E74726F6C65B4090000FDA2000000008C00A509000007000080AA0000005A0000000180000061000080436F6E74726F6C65B3A3FFFF5723000052656C6174696F6E736869702027464B5F414E4F5461626C655F45787465726E616C446174616261736553657276657227206265747765656E202745787465726E616C44617461626173655365727665722720616E642027414E4F5461626C652775652700002800B501000007000080AB000000310000007700000002800000436F6E74726F6C65DDA5FFFF9268000000003800A509000007000080AC000000B2020000008000001000008053636847726964659E9D0000F69F00004C6F6164506572696F646963616C6C790000A000A509000007000080AF000000520000000180000075000080436F6E74726F6C65CC2200004DC0FFFF52656C6174696F6E736869702027464B5F416767726567617465436F6E66696775726174696F6E5F41676772656761746544696D656E73696F6E27206265747765656E202741676772656761746544696D656E73696F6E2720616E642027416767726567617465436F6E66696775726174696F6E2772270000002800B501000007000080B0000000310000008B00000002800000436F6E74726F6C655F1B0000DDBFFFFF00003400A509000007000080BD000000AA020000008000000C0000805363684772696465AA820000345300004C6F61644D6574616461746100007800A509000007000080BE00000052000000018000004F000080436F6E74726F6C65F57000005F53000052656C6174696F6E736869702027464B5F436174616C6F6775655F4C6F61644D6574616461746127206265747765656E20274C6F61644D657461646174612720616E642027436174616C6F677565270000002800B501000007000080BF000000310000006500000002800000436F6E74726F6C6566720000EF52000000008800A509000007000080C000000062000000018000005D000080436F6E74726F6C65FA9C0000CF85000052656C6174696F6E736869702027464B5F4C6F6164506572696F646963616C6C795F4C6F61644D6574616461746127206265747765656E20274C6F61644D657461646174612720616E6420274C6F6164506572696F646963616C6C79276F270000002800B501000007000080C1000000310000007300000002800000436F6E74726F6C65D98A00000695000000007C00A509000007000080C2000000520000000180000053000080436F6E74726F6C65659D0000A369000052656C6174696F6E736869702027464B5F50726F636573735461736B5F4C6F61644D6574616461746127206265747765656E20274C6F61644D657461646174612720616E64202750726F636573735461736B274900002800B501000007000080C3000000310000006900000002800000436F6E74726F6C65079E0000E96B000000008000A509000007000080C4000000620000000180000055000080436F6E74726F6C65659D0000517F000052656C6174696F6E736869702027464B5F4C6F61645363686564756C655F4C6F61644D6574616461746127206265747765656E20274C6F61644D657461646174612720616E6420274C6F61645363686564756C6527656D2700002800B501000007000080C5000000310000006B00000002800000436F6E74726F6C6581AA0000CF81000000004400A509000007000080C6000000C6020000008000001A000080536368477269646530750000CA9E0000444C4557696E646F777353657276696365457863657074696F6E720000009C00A509000007000080C7000000520000000180000071000080436F6E74726F6C65A98100005C86000052656C6174696F6E736869702027464B5F444C4557696E646F777353657276696365457863657074696F6E5F4C6F61644D6574616461746127206265747765656E20274C6F61644D657461646174612720616E642027444C4557696E646F777353657276696365457863657074696F6E27696F6E00002800B501000007000080C8000000310000008700000002800000436F6E74726F6C65FC6700004293000000008800A509000007000080C90000006A000000018000005E000080436F6E74726F6C65ED9700005C86000052656C6174696F6E736869702027464B5F4C6F6164506572696F646963616C6C795F4C6F61644D657461646174613127206265747765656E20274C6F61644D657461646174612720616E6420274C6F6164506572696F646963616C6C7927270000002800B501000007000080CA000000310000007500000002800000436F6E74726F6C65E7840000C995000000004400A509000007000080CB000000C8020000008000001B000080536368477269646562430000F4CFFFFF416767726567617465436F6E74696E756F75734461746541786973000000A800A509000007000080CC00000052000000018000007F000080436F6E74726F6C656142000069C9FFFF52656C6174696F6E736869702027464B5F416767726567617465436F6E74696E756F757344617465417869735F41676772656761746544696D656E73696F6E27206265747765656E202741676772656761746544696D656E73696F6E2720616E642027416767726567617465436F6E74696E756F75734461746541786973270000002800B501000007000080CD000000310000009500000002800000436F6E74726F6C65C22400005ECDFFFF00003C00A509000007000080D0000000B802000000800000130000805363684772696465B80B0000C8CEFFFF416767726567617465466F726365644A6F696E760000A000A509000007000080D10000005A0000000180000077000080436F6E74726F6C65DB04000016C9FFFF52656C6174696F6E736869702027464B5F416767726567617465466F726365644A6F696E5F416767726567617465436F6E66696775726174696F6E27206265747765656E2027416767726567617465436F6E66696775726174696F6E2720616E642027416767726567617465466F726365644A6F696E270000002800B501000007000080D2000000310000008D00000002800000436F6E74726F6C6564EAFFFFE9CFFFFF00008800A509000007000080D300000062000000018000005D000080436F6E74726F6C6582F8FFFF1FDDFFFF52656C6174696F6E736869702027464B5F416767726567617465466F726365644A6F696E5F5461626C65496E666F27206265747765656E20275461626C65496E666F2720616E642027416767726567617465466F726365644A6F696E2727270000002800B501000007000080D4000000310000007300000002800000436F6E74726F6C65360800002416000000008C00A509000007000080D50000007A0000000180000063000080436F6E74726F6C65AD21000012C9FFFF52656C6174696F6E736869702027464B5F416767726567617465436F6E66696775726174696F6E5F436174616C6F67756527206265747765656E2027436174616C6F6775652720616E642027416767726567617465436F6E66696775726174696F6E272700002800B501000007000080D6000000310000007900000002800000436F6E74726F6C656B3D00003DECFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002143341208000000A72900001A28000078563412070000001401000043006100740061006C006F006700750065004900740065006D00000073000000000010400100000000000000000000000E000000050000001801000000000000000000000000000000000000F8000000000000000500000000000000000000000200000000000000009492400000000000000000000000000094924000000000000000400400000020000000300000000000000000000000008C924000000000000010400000000000000040000000000000004000000000000000000100000000000000050000000000000040000000010000000000000000000040000000000000104004000000200000002000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000A72900001A280000000000002D0100000D0000000C000000070000001C010000F70800005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000411700003F230000000000000C0000000C00000002000000020000001C010000E60A00000000000001000000F21300009408000000000000020000000200000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000006400000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000E00000043006100740061006C006F006700750065004900740065006D000000214334120800000079290000BC7E000078563412070000001401000043006100740061006C006F00670075006500000067007500650000000000870AC03D66020500000000000000020000000000000000000000000100000001000000000000484B75575034A75728307C57484B755763006F006D00700075007400650064005F0063006F006C0075006D006E007300200063006D0063006501006453C20F00E05A6B16109AA70A6F0062006A006500630074005F006900640020003D00200063006F006C002E006F0062006A006500630074005F0069006400200061006E006400200063006D0063002E0063006F006C0075006D006E005F006900640020003D00200063006F006C00000000000000000000000000000005000000540000002C0000002C0000002C00000034000000000000000000000079290000BC7E0000000000002D0100000D0000000C000000070000001C0100002F0D00005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000411700000341000000000000180000000C00000002000000020000001C010000D70A00000000000001000000F21300004E06000000000000010000000100000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000005C00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000A00000043006100740061006C006F00670075006500000002000B003E4900001E2D00003E490000002400000000000002000000F0F0F00000000000000000000000000000000000010000000400000000000000ED490000E3270000BA1400005801000032000000010000020000BA14000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61210046004B005F0043006100740061006C006F006700750065005F004900740065006D0073005F0044006100740061005F0043006100740061006C006F006700750065002143341208000000BA290000B92500007856341207000000140100005400610062006C00650049006E0066006F00000073000000540020006E0061006D0065002C002000760061006C00750065002000460052004F004D0020007300790073002E0065007800740065006E006400650064005F00700072006F0070006500720074006900650073002000570048004500520045002000280063006C0061007300730020003D00200031002900200041004E004400200028006D0061006A006F0072005F006900640020003D0020004F0042004A004500430054005F004900440028004E0027005B00640062006F005D002E005B005400610062006C0065005F0031005D00270029002900000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000BA290000B9250000000000002D010000080000000C000000070000001C010000F70800005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000AF1C0000A823000000000000060000000600000002000000020000001C010000F20D00000000000001000000F21300004E06000000000000010000000100000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000005C00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000A0000005400610062006C00650049006E0066006F0000002143341208000000C42E00009A2D000078563412070000001401000043006F006C0075006D006E0049006E0066006F0000000000540020006E0061006D0065002C002000760061006C00750065002000460052004F004D0020007300790073002E0065007800740065006E006400650064005F00700072006F0070006500720074006900650073002000570048004500520045002000280063006C0061007300730020003D00200031002900200041004E004400200028006D0061006A006F0072005F006900640020003D0020004F0042004A004500430054005F004900440028004E0027005B00640062006F005D002E005B005400610062006C0065005F0031005D00270029002900000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000C42E00009A2D0000000000002D010000080000000C000000070000001C010000F50A00005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000411700005D14000000000000060000000600000002000000020000001C010000E60A00000000000001000000F21300009408000000000000020000000200000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000005E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000B00000043006F006C0075006D006E0049006E0066006F00000002000B00F2E0FFFF90330000F2E0FFFF042D00000000000002000000F0F0F00000000000000000000000000000000000010000000800000000000000A1E1FFFF4E2F00001C10000058010000380000000100000200001C10000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D611A0046004B005F005400610062006C0065005F004900740065006D0073005F0044006100740061005F005400610062006C00650073002143341208000000BA290000AC14000078563412070000001401000043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D0000000000050000001801000000000000000000000000000000000000F800000000000000050000000000000000000000020000000000000000D09D4000000000000000000000000000D09D400000000000000040040000002000000030000000000000000000000000C89D4000000000000010400000000000000040000000000000004000000000000000000100000000000000050000000000000040000000010000000000000000000040000000000000104004000000200000002000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000BA290000AC140000000000002D0100000D0000000C000000070000001C010000F70800005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000F21300000804000000000000000000000000000002000000020000001C010000F70800000000000001000000F21300000804000000000000000000000000000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000007A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001900000043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D00000003000B00000000006AFFFFFF00000000CCF7FFFF94110000CCF7FFFF0000000002000000F0F0F00000000000000000000000000000000000010000001300000000000000ABF6FFFFC5F5FFFFC51700005801000058000000010000020000C517000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61260046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F0043006F006C0075006D006E0049006E0066006F0005000B00A84800007CFCFFFFBF4000007CFCFFFFBF40000097FCFFFFD638000097FCFFFFD63800004EFAFFFF0000000002000000F0F0F000000000000000000000000000000000000100000017000000000000005A29000075FAFFFF92190000580100001D0000000100000200009219000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61290046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F0043006100740061006C006F006700750065004900740065006D0021433412080000003D2200005D1E000078563412070000001401000053007500700070006F007200740069006E00670044006F00630075006D0065006E0074000000000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003D2200005D1E0000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001300000053007500700070006F007200740069006E00670044006F00630075006D0065006E007400000002000B0021720000FA320000FA7D0000FA3200000000000002000000F0F0F00000000000000000000000000000000000010000001A000000000000004F6E0000A93300007C13000058010000320000000100000200007C13000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D611F0046004B005F0053007500700070006F007200740069006E00670044006F00630075006D0065006E0074005F0043006100740061006C006F006700750065002143341208000000AA2B0000F2200000785634120700000014010000450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E000000000000000E000000050000001801000000000000000000000000000000000000E800000000000000050000000000000000000000010000000000000000002A400000000000000000040000002000000020000000000000000000000000002E4000000000000000400000000000000040000000000000004000000000000000000100000000000000050000000000000040000000010000000000000000002E400000000000003640040000002000000020000000000000000000000000002A400000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000AA2B0000F2200000000000002D0100000D0000000C000000070000001C01000060090000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007400000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000016000000450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E00000002000B00D0200000E40C0000D02000004EFAFFFF0000000002000000F0F0F000000000000000000000000000000000000100000023000000000000007F210000ED020000671D00005801000032000000010000020000671D000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61310046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0021433412080000001C260000EE1400007856341207000000140100004C006F006F006B0075007000000000000001000010010000440000000200000001000000C800000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000001C260000EE140000000000002D0100000D0000000C000000070000001C010000160800009F06000094020000390300003A02000065040000DD040000EE020000DD04000036060000380400000000000001000000661200000804000000000000000000000000000002000000020000001C010000160800000000000001000000661200000804000000000000000000000000000002000000020000001C010000160800000100000000000000661200000804000000000000000000000000000002000000020000001C010000160800000000000000000000E42D00001224000000000000000000000D00000004000000040000001C010000160800008D090000DC05000078563412040000005600000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000070000004C006F006F006B0075007000000002000B00E0E3FFFF6AFFFFFFE0E3FFFF04F0FFFF0000000002000000F0F0F000000000000000000000000000000000000100000028000000000000008FE4FFFF0BF7FFFFBB0C00005801000032000000010000020000BB0C000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61140046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F0002000B0026E9FFFF6AFFFFFF26E9FFFF04F0FFFF0000000002000000F0F0F00000000000000000000000000000000000010000002A00000000000000D5E9FFFF0BF7FFFF680D00005801000032000000010000020000680D000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61150046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F00310002000B00F2E0FFFF6AFFFFFFF2E0FFFF04F0FFFF0000000002000000F0F0F00000000000000000000000000000000000010000002C00000000000000A1E1FFFF0BF7FFFF680D00005801000032000000010000020000680D000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61150046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F0032002143341208000000FC250000301500007856341207000000140100004A006F0069006E0049006E0066006F0000006E0064006F00770073002E0046006F0072006D0073002C002000560065007200730069006F006E003D0034002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00620037003700610035006300350036003100390033003400650030003800390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000FC25000030150000000000002D0100000D0000000C000000070000001C010000160800005406000094020000390300003A02000065040000DD040000EE020000DD04000036060000380400000000000001000000661200000804000000000000000000000000000002000000020000001C010000160800000000000001000000661200000804000000000000000000000000000002000000020000001C010000160800000100000000000000661200000804000000000000000000000000000002000000020000001C010000160800000000000000000000E42D00001224000000000000000000000D00000004000000040000001C010000160800008D090000DC05000078563412040000005A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000090000004A006F0069006E0049006E0066006F00000002000B00FCD6FFFF2C0100009CD1FFFF2C0100000000000002000000F0F0F000000000000000000000000000000000000100000034000000000000009CD1FFFF25FFFFFFD01200005801000064000000010000020000D012000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D611F0046004B005F004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F004A006F0069006E004B0065007900310002000B00FCD6FFFFDC0500009CD1FFFFDC0500000000000002000000F0F0F000000000000000000000000000000000000100000036000000000000009CD1FFFFD5030000D01200005801000064000000010000020000D012000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D611F0046004B005F004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F004A006F0069006E004B00650079003200214334120800000066230000C5170000785634120700000014010000450078007400720061006300740069006F006E00460069006C0074006500720000002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D0062003700370061003500630035003600310039003300340065003000380039000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C00000034000000000000000000000066230000C5170000000000002D0100000D0000000C000000070000001C010000070800009204000094020000390300003A02000029040000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000011000000450078007400720061006300740069006F006E00460069006C00740065007200000002000B0082140000D62D000082140000E83500000000000002000000F0F0F00000000000000000000000000000000000010000003A0000000000000011FDFFFF33310000C21600005801000032000000010000020000C216000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61290046004B005F00450078007400720061006300740069006F006E00460069006C007400650072005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E002143341208000000EA1F00007A120000785634120700000014010000450078007400720061006300740069006F006E00460069006C0074006500720050006100720061006D006500740065007200000069006F006E003D0034002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00620037003700610035006300350036003100390033003400650030003800390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000EA1F00007A120000000000002D0100000D0000000C000000070000001C010000090600009204000094020000390300003A02000029040000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007C00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001A000000450078007400720061006300740069006F006E00460069006C0074006500720050006100720061006D006500740065007200000002000B00E40C0000AD4D0000E40C0000F65400000000000002000000F0F0F00000000000000000000000000000000000010000003D000000000000006DF3FFFFA5500000C81800005801000032000000010000020000C818000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612D0046004B005F00450078007400720061006300740069006F006E00460069006C0074006500720050006100720061006D0065007400650072005F00450078007400720061006300740069006F006E00460069006C0074006500720003000B00FA320000D62D0000FA320000F0870000A8480000F08700000000000002000000F0F0F000000000000000000000000000000000000100000041000000000000003E1E0000C76B00000D14000058010000370000000100000200000D14000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61220046004B005F0043006100740061006C006F006700750065005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E00214334120800000056250000621700007856341207000000140100004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F000000680050006100720073006500720043006C00690065006E0074002C002000560065007200730069006F006E003D00310031002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00380039003800340035006400630064003800300038003000630063003900310000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000005625000062170000000000002D010000070000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000042700004710000000000000040000000400000002000000020000001C010000CE1300000000000001000000D91000006806000000000000010000000100000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007800000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000180000004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F00000002000B00ACDBFFFF16DBFFFFACDBFFFF84D7FFFF0000000002000000F0F0F000000000000000000000000000000000000100000055000000000000005BDCFFFFA1D8FFFF6414000058010000320000000100000200006414000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61210046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F004C006F006F006B007500700005000B006EDDFFFF6AFFFFFF6EDDFFFF07F9FFFF3BC9FFFF07F9FFFF3BC9FFFF18CAFFFF78D3FFFF18CAFFFF0000000002000000F0F0F00000000000000000000000000000000000010000005700000000000000EAC9FFFF9AE8FFFFC21600005801000032000000010000020000C216000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61250046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F0005000B0054D9FFFF6AFFFFFF54D9FFFFDDFBFFFF83C2FFFFDDFBFFFF83C2FFFF94C6FFFF78D3FFFF94C6FFFF0000000002000000F0F0F00000000000000000000000000000000000010000005A0000000000000032C3FFFF08E5FFFFC81800005801000032000000010000020000C818000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61280046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F0046004B0021433412080000003D2200005B1A000078563412070000001401000053007500700070006F007200740069006E006700530051004C005400610062006C00650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003D2200005B1A0000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001300000053007500700070006F007200740069006E006700530051004C005400610062006C006500000004000B0021720000A2300000FB7A0000A2300000FB7A0000D0200000DAAC0000D02000000000000002000000F0F0F00000000000000000000000000000000000010000005E0000000000000021720000513100002613000058010000000000000100000200002613000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D611F0046004B005F0053007500700070006F007200740069006E006700530051004C005400610062006C0065005F0043006100740061006C006F006700750065002143341208000000362200004724000078563412070000001401000041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E000000000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003622000047240000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007600000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001700000041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E00000021433412080000003C2200005F0F0000785634120700000014010000410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E0065007200000000000200000000001066000000010000200000005A66D11F3372CF63785FCA7F40C69EA7DCEDA7CC247BCFBB00C38E42D74AECAA000000000E800000000200002000000022DD4B17FD42971A525C6C9C486DCAF55C6C488516735862E36E352C2D42E2C460000000A7DE800C07B35B3F0D6263AC81AE6E31CA8A493A12274568746645EF462AD47FD8892C9460826B6F5F558A0E75CC4E4AC5561556A9455D20A14B4EE450E669AB1E892532D8D21B364B2F844052BF0F8ECA46A54A000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C2200005F0F0000000000002D0100000D0000000C000000070000001C010000500A0000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000019000000410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E0065007200000021433412080000003C220000CC100000785634120700000014010000410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E006500720000006E003D0034002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00620037003700610035006300350036003100390033003400650030003800390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C220000CC100000000000002D0100000D0000000C000000070000001C010000300C0000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000008000000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001C000000410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E0065007200000002000B00984D0000DEA9FFFF7A580000DEA9FFFF0000000002000000F0F0F00000000000000000000000000000000000010000006500000000000000ED4200008DAAFFFF3820000058010000320000000100000200003820000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61370046004B005F00410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E00650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720002000B00984D000002A4FFFF7A58000002A4FFFF0000000002000000F0F0F0000000000000000000000000000000000001000000670000000000000096420000FBA1FFFFE52000005801000032000000010000020000E520000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61380046004B005F00410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E00650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E00650072003100214334120800000036220000CF1C0000785634120700000014010000410067006700720065006700610074006500460069006C0074006500720000007600650072002E004200610074006300680050006100720073006500720043006C00690065006E0074002C002000560065007200730069006F006E003D00310031002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00380039003800340035006400630064003800300038003000630063003900310000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C00000034000000000000000000000036220000CF1C0000000000002D010000070000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD040000360600003804000000000000010000000B2400005015000000000000050000000500000002000000020000001C0100002A1200000000000001000000D9100000AF08000000000000020000000200000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006800000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000010000000410067006700720065006700610074006500460069006C00740065007200000002000B00984D0000E6B0FFFF10590000E6B0FFFF0000000002000000F0F0F0000000000000000000000000000000000001000000700000000000000055440000DFAEFFFFE51800005801000045000000010000020000E518000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612B0046004B005F00410067006700720065006700610074006500460069006C007400650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720021433412080000007829000020170000785634120700000014010000410067006700720065006700610074006500440069006D0065006E00730069006F006E000000674797F9A80390A9CEBA040000000200000000001066000000010000200000005A66D11F3372CF63785FCA7F40C69EA7DCEDA7CC247BCFBB00C38E42D74AECAA000000000E800000000200002000000022DD4B17FD42971A525C6C9C486DCAF55C6C488516735862E36E352C2D42E2C460000000A7DE800C07B35B3F0D6263AC81AE6E31CA8A493A12274568746645EF462AD47FD8892C9460826B6F5F558A0E75CC4E4AC5561556A9455D20A14B4EE450E669AB1E892532D8D21B364B2F844052BF0F8ECA46A54A000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000007829000020170000000000002D0100000D0000000C000000070000001C0100005F0A0000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000013000000410067006700720065006700610074006500440069006D0065006E00730069006F006E00000002000B00F8230000C2B6FFFFB42D0000C2B6FFFF0000000002000000F0F0F00000000000000000000000000000000000010000007300000000000000351B000071B7FFFFED1A00005801000033000000010000020000ED1A000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612C0046004B005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E0002000B005C2B00001CA8FFFFF82300001CA8FFFF0000000002000000F0F0F00000000000000000000000000000000000010000007500000000000000E818000015A6FFFF831D00005801000032000000010000020000831D000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61320046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720021433412080000003C2200000E150000785634120700000014010000410067006700720065006700610074006500460069006C0074006500720050006100720061006D006500740065007200000000000200000000001066000000010000200000005A66D11F3372CF63785FCA7F40C69EA7DCEDA7CC247BCFBB00C38E42D74AECAA000000000E800000000200002000000022DD4B17FD42971A525C6C9C486DCAF55C6C488516735862E36E352C2D42E2C460000000A7DE800C07B35B3F0D6263AC81AE6E31CA8A493A12274568746645EF462AD47FD8892C9460826B6F5F558A0E75CC4E4AC5561556A9455D20A14B4EE450E669AB1E892532D8D21B364B2F844052BF0F8ECA46A54A000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C2200000E150000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000019000000410067006700720065006700610074006500460069006C0074006500720050006100720061006D006500740065007200000002000B00467B0000A8B2FFFFD6830000A8B2FFFF0000000002000000F0F0F00000000000000000000000000000000000010000007800000000000000F072000057B3FFFF3C19000058010000320000000100000200003C19000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612B0046004B005F00410067006700720065006700610074006500460069006C0074006500720050006100720061006D0065007400650072005F00410067006700720065006700610074006500460069006C007400650072002143341208000000822E0000641F000078563412070000001401000043006100740061006C006F006700750065004900740065006D004900730073007500650000002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D0062003700370061003500630035003600310039003300340065003000380039000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000822E0000641F0000000000002D010000090000000C000000070000001C0100006C0C0000DC05000094020000390300003A020000DE030000DD040000EE020000DD040000360600003804000000000000010000003E260000E717000000000000070000000700000002000000020000001C010000561300000000000001000000D91000006806000000000000010000000100000002000000020000001C010000260700000100000000000000D91000009E03000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001300000043006100740061006C006F006700750065004900740065006D0049007300730075006500000003000B0070620000E6FBFFFF7062000074F5FFFFF276000074F5FFFF0000000002000000F0F0F000000000000000000000000000000000000100000082000000000000008062000023F6FFFFA11500005801000032000000010000020000A115000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61230046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F0043006100740061006C006F006700750065004900740065006D0021433412080000003C2200009315000078563412070000001401000049007300730075006500530079007300740065006D005500730065007200000001000000C800000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C22000093150000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006800000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001000000049007300730075006500530079007300740065006D005500730065007200000003000B00E2B3000003E2FFFFE2B3000040EDFFFF74A5000040EDFFFF0000000002000000F0F0F00000000000000000000000000000000000010000008500000000000000F09700007CE3FFFF431B00005801000007000000010000020000431B000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612B0046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F004F0077006E00650072005F0049007300730075006500530079007300740065006D00550073006500720003000B00F4B0000042DCFFFFDC9B000042DCFFFFDC9B00000CE5FFFF0000000002000000F0F0F000000000000000000000000000000000000100000087000000000000004B9200003BDAFFFF801C00005801000007000000010000020000801C000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612E0046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F005200650070006F0072007400650072005F0049007300730075006500530079007300740065006D00550073006500720021433412080000003C220000BC12000078563412070000001401000041004E004F005400610062006C00650000006E0066006F00000000000200000001000000C800000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C220000BC120000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000005A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000900000041004E004F005400610062006C006500000002000B0002B7FFFFEC130000FCD6FFFFEC1300000000000002000000F0F0F00000000000000000000000000000000000010000008C00000000000000D8BFFFFF9B1400004E0E000058010000320000000100000200004E0E000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61160046004B005F0043006F006C0075006D006E0049006E0066006F005F0041004E004F005400610062006C00650021433412080000003C2200007B1A00007856341207000000140100005000720065004C006F006100640044006900730063006100720064006500640043006F006C0075006D006E0000000000040000000200000000001066000000010000200000005A66D11F3372CF63785FCA7F40C69EA7DCEDA7CC247BCFBB00C38E42D74AECAA000000000E800000000200002000000022DD4B17FD42971A525C6C9C486DCAF55C6C488516735862E36E352C2D42E2C460000000A7DE800C07B35B3F0D6263AC81AE6E31CA8A493A12274568746645EF462AD47FD8892C9460826B6F5F558A0E75CC4E4AC5561556A9455D20A14B4EE450E669AB1E892532D8D21B364B2F844052BF0F8ECA46A54A000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003C2200007B1A0000000000002D0100000D0000000C000000070000001C01000052080000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007600000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000170000005000720065004C006F006100640044006900730063006100720064006500640043006F006C0075006D006E00000002000B00F4CFFFFF26340000C2C9FFFF263400000000000002000000F0F0F00000000000000000000000000000000000010000008F0000000000000019C2FFFF1F3200008415000058010000320000000100000200008415000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61230046004B005F005000720065004C006F006100640044006900730063006100720064006500640043006F006C0075006D006E005F005400610062006C00650049006E0066006F0021433412080000009A290000A51B0000785634120700000014010000500072006F0063006500730073005400610073006B0041007200670075006D0065006E00740000002C002000560065007200730069006F006E003D0034002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00620037003700610035006300350036003100390033003400650030003800390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000009A290000A51B0000000000002D0100000D0000000C000000070000001C010000F70800005307000094020000390300003A020000DD040000DD040000EE020000DD04000036060000380400000000000001000000F21300000804000000000000000000000000000002000000020000001C010000F70800000000000001000000F21300000804000000000000000000000000000002000000020000001C010000F70800000100000000000000F21300000804000000000000000000000000000002000000020000001C010000F7080000000000000000000055320000DD23000000000000000000000D00000004000000040000001C010000F70800009B0A00008106000078563412040000007000000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000014000000500072006F0063006500730073005400610073006B0041007200670075006D0065006E007400000002000B009ED10000EC5E000036D80000EC5E00000000000002000000F0F0F0000000000000000000000000000000000001000000950000000000000044CA0000E55C00004B15000058010000320000000100000200004B15000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61220046004B005F00500072006F0063006500730073005400610073006B0041007200670075006D0065006E0074005F00500072006F0063006500730073005400610073006B00214334120800000002230000D1240000785634120700000014010000500072006F0063006500730073005400610073006B0000006700720061006D002000460069006C00650073002000280078003800360029002F004D006900630072006F0073006F00660074002000530051004C0020005300650072007600650072002F003100310030002F0054006F006F006C0073002F00420069006E006E002F004D0061006E006100670065006D0065006E007400530074007500640069006F002F004900440045002F00500072006900760061007400650041007300730065006D0062006C006900650073002F004F0062006A006500630074004500780070006C006F007200650072005200000000000000000000000000000005000000540000002C0000002C0000002C00000034000000000000000000000002230000D1240000000000002D0100000D0000000C000000070000001C010000450600002805000094020000390300003A02000066030000DD040000EE020000DD040000360600003804000000000000010000004C0F00000804000000000000000000000000000002000000020000001C0100004506000000000000010000004C0F00000804000000000000000000000000000002000000020000001C0100004506000001000000000000004C0F00000804000000000000000000000000000002000000020000001C010000450600000000000000000000CB2400007C24000000000000000000000D00000004000000040000001C01000045060000710700009204000078563412040000006000000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000C000000500072006F0063006500730073005400610073006B00000003000B00243900007A0D0000DE3F00007A0D0000DE3F000020CCFFFF0000000002000000F0F0F000000000000000000000000000000000000100000097000000000000008D4000008BF0FFFFAF1900005801000032000000010000020000AF19000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D612B0046004B005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0003000B0021720000E691000092B80000E691000092B80000A37F00000000000002000000F0F0F00000000000000000000000000000000000010000009B00000000000000E99E000095920000DF0E00005801000032000000010000020000DF0E000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61180046004B005F00500072006F0063006500730073005400610073006B005F0043006100740061006C006F0067007500650000020000F90C0000160900000200640000000500008000000000000000003A00010000009001C0D40100085365676F652055491E004E0065007600650072002000430041005300430041004400450020000D000A00440045004C0045005400450020000D000A0048006500720065002100214334120800000036220000472400007856341207000000140100004C006F00610064004D006F00640075006C00650041007300730065006D0062006C0079000000000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003622000047240000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000130000004C006F00610064004D006F00640075006C00650041007300730065006D0062006C007900000021433412080000009E390000252700007856341207000000140100004C006F00610064005300630068006500640075006C00650000005300650072007600650072002E004200610074006300680050006100720073006500720043006C00690065006E0074002C002000560065007200730069006F006E003D00310031002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00380039003800340035006400630064003800300038003000630063003900310000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000009E39000025270000000000002D0100000D0000000C000000070000001C010000C50D0000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000104F0000B1240000000000000B0000000B00000002000000020000001C0100007B2A00000000000001000000D9100000AF08000000000000020000000200000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006200000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000D0000004C006F00610064005300630068006500640075006C006500000021433412080000007829000010190000785634120700000014010000450078007400650072006E0061006C0044006100740061006200610073006500530065007200760065007200000000007501000000000000140000000000000000000000010000000400000075010000430000004700000004000000000000000600000004000000750100001400000047000000010000000300000005000000E4FFFFFF750100001400000047000000000000000300000005000000E8FFFFFF7501000014000000470000000200000003000000050000000800000075010000530000005C0100000400000000000000060000000800000075010000530000005C01000001000000030000000500000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000007829000010190000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007600000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F00000017000000450078007400650072006E0061006C0044006100740061006200610073006500530065007200760065007200000003000B0036F7FFFFFC6C0000B4E2FFFFFC6C0000B4E2FFFF495900000000000002000000F0F0F0000000000000000000000000000000000001000000A40000000000000044CDFFFFAB6D00002D15000058010000320000000100000200002D15000058010000020000000000050000800800008001000000150001000000900144420100065461686F6D61230046004B005F005400610062006C00650049006E0066006F005F00450078007400650072006E0061006C004400610074006100620061007300650053006500720076006500720003000B004C1D00001E8300004C1D0000089D0000A8480000089D00000000000002000000F0F0F0000000000000000000000000000000000001000000A700000000000000F50F0000B79D00008415000058010000320000000100000200008415000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61230046004B005F0043006100740061006C006F006700750065005F00450078007400650072006E0061006C004400610074006100620061007300650053006500720076006500720003000B00701700001E830000701700004EA20000A84800004EA200000000000002000000F0F0F0000000000000000000000000000000000001000000A900000000000000B4090000FDA200003116000058010000320000000100000200003116000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61240046004B005F0043006100740061006C006F006700750065005F00450078007400650072006E0061006C0044006100740061006200610073006500530065007200760065007200310003000B0036F7FFFF546F00002EA5FFFF546F00002EA5FFFF122600000000000002000000F0F0F0000000000000000000000000000000000001000000AB00000000000000DDA5FFFF926800006715000058010000380000000100000200006715000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61220046004B005F0041004E004F005400610062006C0065005F00450078007400650072006E0061006C00440061007400610062006100730065005300650072007600650072002143341208000000C61B0000E61700007856341207000000140100004C006F006100640050006500720069006F0064006900630061006C006C0079000000440026004400570044004F0052004A005800480003001000030026004400570044004F0052004A005800480042002700440057004400420027004C0044004A00550044005000000080400000004100001041000000410000C040000040400000C0400000E04000008040000040400000E040000080400000C0400000E0400000E04000008040000000410000C040000080400000C040000000410000C040000080400000C040000040400000E0400000E0400000E0400000C040000040400000A04000004040000000410000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000C61B0000E6170000000000002D0100000D0000000C000000070000001C010000890D0000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006A00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F000000110000004C006F006100640050006500720069006F0064006900630061006C006C007900000002000B00B42D0000E4C1FFFFF8230000E4C1FFFF0000000002000000F0F0F0000000000000000000000000000000000001000000B0000000000000005F1B0000DDBFFFFFED1A00005801000032000000010000020000ED1A000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D612C0046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E002143341208000000E71B0000DF3500007856341207000000140100004C006F00610064004D0065007400610064006100740061000000954000000000000010400100000000000000000000000E000000050000001801000000000000000000000000000000000000F800000000000000050000000000000000000000020000000000000000C0954000000000000000000000000000C095400000000000000040040000002000000030000000000000000000000000B8954000000000000010400000000000000040000000000000004000000000000000000100000000000000050000000000000040000000010000000000000000000040000000000000104004000000200000002000000000000000000000000100000005000000540000002C0000002C0000002C0000003400000000000000000000003622000047240000000000002D0100000D0000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000E71B0000DF35000000000000140000000C00000002000000020000001C0100007A0D00000000000001000000D91000006806000000000000010000000100000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000006200000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000000D0000004C006F00610064004D006500740061006400610074006100000002000B00AA820000F654000021720000F65400000000000002000000F0F0F0000000000000000000000000000000000001000000BF0000000000000066720000EF520000FF0F00005801000032000000010000020000FF0F000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61190046004B005F0043006100740061006C006F006700750065005F004C006F00610064004D00650074006100640061007400610004000B00919E000086880000919E000084940000CA9E000084940000CA9E0000F69F00000200000002000000F0F0F0000000000000000000000000000000000001000000C100000000000000D98A0000069500000913000058010000320000000100000200000913000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61200046004B005F004C006F006100640050006500720069006F0064006900630061006C006C0079005F004C006F00610064004D00650074006100640061007400610002000B00919E00003A6B00009CAE00003A6B00000000000002000000F0F0F0000000000000000000000000000000000001000000C300000000000000079E0000E96B00001F11000058010000320000000100000200001F11000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D611B0046004B005F00500072006F0063006500730073005400610073006B005F004C006F00610064004D00650074006100640061007400610004000B00919E0000E88000008EA90000E88000008EA90000D6830000D8BD0000D68300000000000002000000F0F0F0000000000000000000000000000000000001000000C50000000000000081AA0000CF810000E91100005801000032000000010000020000E911000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D611C0046004B005F004C006F00610064005300630068006500640075006C0065005F004C006F00610064004D0065007400610064006100740061002143341208000000362200003A1A000078563412070000001401000044004C004500570069006E0064006F0077007300530065007200760069006300650045007800630065007000740069006F006E000000720073006500720043006C00690065006E0074002C002000560065007200730069006F006E003D00310031002E0030002E0030002E0030002C002000430075006C0074007500720065003D006E00650075007400720061006C002C0020005000750062006C00690063004B006500790054006F006B0065006E003D00380039003800340035006400630064003800300038003000630063003900310000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000362200003A1A0000000000002D010000080000000C000000070000001C01000026070000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000621700007B1A000000000000060000000600000002000000020000001C010000E60A00000000000001000000D91000006806000000000000010000000100000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007E00000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001B00000044004C004500570069006E0064006F0077007300530065007200760069006300650045007800630065007000740069006F006E00000002000B00408300001389000040830000CA9E00000000000002000000F0F0F0000000000000000000000000000000000001000000C800000000000000FC67000042930000951A00005801000032000000010000020000951A000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D612A0046004B005F0044004C004500570069006E0064006F0077007300530065007200760069006300650045007800630065007000740069006F006E005F004C006F00610064004D00650074006100640061007400610005000B00849900001389000084990000849400004C990000849400004C9900008CA000009E9D00008CA000000000000002000000F0F0F0000000000000000000000000000000000001000000CA00000000000000E7840000C9950000B61300005801000033000000010000020000B613000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61210046004B005F004C006F006100640050006500720069006F0064006900630061006C006C0079005F004C006F00610064004D00650074006100640061007400610031002143341208000000112E00007116000078563412070000001401000041006700670072006500670061007400650043006F006E00740069006E0075006F0075007300440061007400650041007800690073000000010000002CF19F123CF19F1204000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A891B10B000400000000000074F19F120400000000000000000000000000000000000000000000000000000080457D121884AC0B00000000AA550000E0F09F1210000000604578120C0000000500000094DF7B007CDF7B00C4F19F1200000000D5FFAA55001000000C00000000000000A891B10B0000000000000000000000000000000005000000540000002C0000002C0000002C000000340000000000000000000000112E000071160000000000002D0100000D0000000C000000070000001C010000F7080000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000008000000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001C00000041006700670072006500670061007400650043006F006E00740069006E0075006F007500730044006100740065004100780069007300000002000B00F843000020CCFFFFF8430000F4CFFFFF0200000002000000F0F0F0000000000000000000000000000000000001000000CD00000000000000C22400005ECDFFFF871E00005801000032000000010000020000871E000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61310046004B005F0041006700670072006500670061007400650043006F006E00740069006E0075006F0075007300440061007400650041007800690073005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E0021433412080000003D2200006910000078563412070000001401000041006700670072006500670061007400650046006F0072006300650064004A006F0069006E00000000000000D800000003000000010000000001000000000000446174615F5053004D756C7469706C7952616469616C4772616469656E7443656E74657265645F5053315F436F6E7374616E745461626C6500666C48616C66546578656C53697A654E6F726D616C697A656400AB000003000100010001000000000000007D00000098000000050000000100010001000100A80000004C000000B0000000050000000100010001000100C00000004D756C7469706C7952616469616C4772616469656E7443656E74000000000000000000000000000005000000540000002C0000002C0000002C0000003400000000000000000000003D22000069100000000000002D0100000D0000000C000000070000001C01000015090000DC05000094020000390300003A020000DE030000DD040000EE020000DD04000036060000380400000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000000000001000000D91000000804000000000000000000000000000002000000020000001C010000260700000100000000000000D91000000804000000000000000000000000000002000000020000001C0100002607000000000000000000003D2900004724000000000000000000000D00000004000000040000001C010000260700007F0800003705000078563412040000007000000001000000010000000B000000000000000100000002000000030000000400000005000000060000000700000008000000090000000A00000004000000640062006F0000001400000041006700670072006500670061007400650046006F0072006300650064004A006F0069006E00000003000B0072060000CDCBFFFF720600005ECFFFFFB80B00005ECFFFFF0000000002000000F0F0F0000000000000000000000000000000000001000000D20000000000000064EAFFFFE9CFFFFF5F1B000058010000270000000100000200005F1B000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D612D0046004B005F0041006700670072006500670061007400650046006F0072006300650064004A006F0069006E005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E0004000B00AEF9FFFF263400008707000026340000870700009ADEFFFFB80B00009ADEFFFF0000000002000000F0F0F0000000000000000000000000000000000001000000D40000000000000036080000241600007C130000580100002B0000000100000200007C13000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61200046004B005F0041006700670072006500670061007400650046006F0072006300650064004A006F0069006E005F005400610062006C00650049006E0066006F0007000B00A8480000B42D0000F2430000B42D0000F243000020280000BC3C000020280000BC3C00005DCDFFFF282300005DCDFFFF28230000CDCBFFFF0000000002000000F0F0F0000000000000000000000000000000000001000000D6000000000000006B3D00003DECFFFF4B15000058010000380000000100000200004B15000058010000020000000000FFFFFF000800008001000000150001000000900144420100065461686F6D61230046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F0043006100740061006C006F006700750065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000FEFFFFFFFEFFFFFF0400000005000000060000000700000008000000090000000A0000000B0000000C0000000D0000000E0000000F000000100000001100000012000000130000001400000015000000160000001700000018000000190000001A0000001B0000001C0000001D0000001E0000001F00000020000000210000002200000023000000240000002500000026000000270000002800000029000000FEFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0100FEFF030A0000FFFFFFFF00000000000000000000000000000000170000004D6963726F736F66742044445320466F726D20322E300010000000456D626564646564204F626A6563740000000000F439B271000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010003000000000000000C0000000B0000004E61BC00000000000000000000000000000000000000000000000000000000000000000000000000000000000000DBE6B0E91C81D011AD5100A0C90F573900000200D062F43BF38BD0010202000010484500000000000000000000000000000000007A0100004400610074006100200053006F0075007200630065003D006A0061006E00750073003B0049006E0069007400690061006C00200043006100740061006C006F0067003D0053007000720069006E00740046006F0075007200440061007400610043006100740061006C006F006700750065003B0049006E00740065006700720061007400650064002000530065006300750072006900740079003D0054007200750065003B004D0075006C007400690070006C00650041006300740069007600650052006500730075006C00740053006500740073003D00460061006C00730065003B005000610063006B00650074002000530069007A0065003D0034003000390036003B0041000300440064007300530074007200650061006D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160002000300000006000000FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000005E0000007A6500000000000053006300680065006D00610020005500440056002000440065006600610075006C0074000000000000000000000000000000000000000000000000000000000026000200FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000020000001600000000000000440053005200450046002D0053004300480045004D0041002D0043004F004E00540045004E0054005300000000000000000000000000000000000000000000002C0002010500000007000000FFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000003000000A40900000000000053006300680065006D00610020005500440056002000440065006600610075006C007400200050006F007300740020005600360000000000000000000000000036000200FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000002A00000012000000000000008100000082000000830000008400000085000000860000008700000088000000890000008A0000008B0000008C0000008D0000008E0000008F00000090000000FEFFFFFF92000000930000009400000095000000FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C0000000CCFFFFF7289FFFF0100260000007300630068005F006C006100620065006C0073005F00760069007300690062006C0065000000010000000B0000001E000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000010000000100000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003200390035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003700390030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C0031003600360035000000020000000200000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0033003300370035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003700370035000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C0031003600360035000000030000000300000000000000540000000103737401000000640062006F00000046004B005F0043006100740061006C006F006700750065005F004900740065006D0073005F0044006100740061005F0043006100740061006C006F0067007500650000000000000000000000C40200000000040000000400000003000000080000000100650DC800650D0000000000000000AD070000000000050000000500000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003200390035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0033003500370030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C0031003600360035000000060000000600000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003800300035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003700390030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C00310036003600350000000700000007000000000000004600000001038A7601000000640062006F00000046004B005F005400610062006C0065005F004900740065006D0073005F0044006100740061005F005400610062006C006500730000000000000000000000C40200000000080000000800000007000000080000000100650D8800650D0000000000000000AD0700000000000D0000000D00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003200390035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C00310036003600350000001200000012000000000000005E00000001FF5F5E01000000640062006F00000046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F0043006F006C0075006D006E0049006E0066006F0000000000000000000000C40200000000130000001300000012000000080000000100650D4800650D0000000000000000AD0700000000001600000016000000000000006400000001016F0001000000640062006F00000046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F0043006100740061006C006F006700750065004900740065006D0000000000000000000000C40200000000170000001700000016000000080000000100650D0800650D0000000000000000AD070000000000180000001800000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000001900000019000000000000005000000001FF5F5E01000000640062006F00000046004B005F0053007500700070006F007200740069006E00670044006F00630075006D0065006E0074005F0043006100740061006C006F0067007500650000000000000000000000C402000000001A0000001A000000190000000800000001FF640DC8FF640D0000000000000000AD0700000000001B0000001B00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003400300030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000220000002200000000000000740000000102000001000000640062006F00000046004B005F0043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0000000000000000000000C402000000002300000023000000220000000800000001FF640D88FF640D0000000000000000AD070000000000240000002400000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003000370030002C0031002C0031003600390035002C0035002C0031003100320035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003000370030002C00310032002C0032003400340035002C00310031002C00310035003000300000002700000027000000000000003A0000000106000001000000640062006F00000046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F0000000000000000000000C402000000002800000028000000270000000800000001FF640D48FF640D0000000000000000AD0700000000002900000029000000000000003C0000000107000001000000640062006F00000046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F00310000000000000000000000C402000000002A0000002A000000290000000800000001FF640D08FF640D0000000000000000AD0700000000002B0000002B000000000000003C0000000105000001000000640062006F00000046004B005F004C006F006F006B00750070005F0043006F006C0075006D006E0049006E0066006F00320000000000000000000000C402000000002C0000002C0000002B0000000800000001FE640DC8FE640D0000000000000000AD0700000000002F0000002F00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003000370030002C0031002C0031003600320030002C0035002C0031003100320035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003000370030002C00310032002C0032003400340035002C00310031002C00310035003000300000003300000033000000000000005000000001FF5F5E01000000640062006F00000046004B005F004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F004A006F0069006E004B0065007900310000000000000000000000C402000000003400000034000000330000000800000001FE640D88FE640D0000000000000000AD0700000000003500000035000000000000005000000001FF5F5E01000000640062006F00000046004B005F004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F004A006F0069006E004B0065007900320000000000000000000000C402000000003600000036000000350000000800000001FE640D48FE640D0000000000000000AD070000000000380000003800000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003000350035002C0031002C0031003100370030002C0035002C0031003000360035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000003900000039000000000000006400000001006F0001000000640062006F00000046004B005F00450078007400720061006300740069006F006E00460069006C007400650072005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0000000000000000000000C402000000003A0000003A000000390000000800000001FE640D08FE640D0000000000000000AD0700000000003B0000003B00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0031003500340035002C0031002C0031003100370030002C0035002C0031003000360035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000003C0000003C000000000000006C000000011A5F5E01000000640062006F00000046004B005F00450078007400720061006300740069006F006E00460069006C0074006500720050006100720061006D0065007400650072005F00450078007400720061006300740069006F006E00460069006C0074006500720000000000000000000000C402000000003D0000003D0000003C0000000800000001FD640DC8FD640D0000000000000000AD070000000000400000004000000000000000560000000103737401000000640062006F00000046004B005F0043006100740061006C006F006700750065005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0000000000000000000000C402000000004100000041000000400000000800000001FD640D88FD640D0000000000000000AD0700000000004C0000004C00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0035003000370030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000540000005400000000000000540000000103737401000000640062006F00000046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F004C006F006F006B007500700000000000000000000000C402000000005500000055000000540000000800000001FD640D48FD640D0000000000000000AD0700000000005600000056000000000000005C00000001FF5F5E01000000640062006F00000046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F0000000000000000000000C402000000005700000057000000560000000800000001FD640D08FD640D0000000000000000AD0700000000005900000059000000000000006200000001006F0001000000640062006F00000046004B005F004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F005F0043006F006C0075006D006E0049006E0066006F005F0046004B0000000000000000000000C402000000005A0000005A000000590000000800000001FC640DC8FC640D0000000000000000AD0700000000005C0000005C00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000005D0000005D000000000000005000000001FF5F5E01000000640062006F00000046004B005F0053007500700070006F007200740069006E006700530051004C005400610062006C0065005F0043006100740061006C006F0067007500650000000000000000000000C402000000005E0000005E0000005D0000000800000001FC640D88FC640D0000000000000000AD0700000000005F0000005F00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000600000006000000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003600340030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000630000006300000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0033003100320030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000640000006400000000000000800000000106401001000000640062006F00000046004B005F00410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E00650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720000000000000000000000C402000000006500000065000000640000000800000001FC640D48FC640D0000000000000000AD0700000000006600000066000000000000008200000001FF690001000000640062006F00000046004B005F00410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E00650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E0065007200310000000000000000000000C402000000006700000067000000660000000800000001F57115C8F571150000000000000000AD0700000000006E0000006E00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0034003600350030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000006F0000006F000000000000006800000001006F0001000000640062006F00000046004B005F00410067006700720065006700610074006500460069006C007400650072005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720000000000000000000000C4020000000070000000700000006F0000000800000001F5711588F571150000000000000000AD070000000000710000007100000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003600350035002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000007200000072000000000000006A000000011A5F5E01000000640062006F00000046004B005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E0000000000000000000000C402000000007300000073000000720000000800000001F5711548F571150000000000000000AD070000000000740000007400000000000000760000000102000001000000640062006F00000046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F00410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E006500720000000000000000000000C402000000007500000075000000740000000800000001F5711508F571150000000000000000AD070000000000760000007600000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000007700000077000000000000006800000001016F0001000000640062006F00000046004B005F00410067006700720065006700610074006500460069006C0074006500720050006100720061006D0065007400650072005F00410067006700720065006700610074006500460069006C0074006500720000000000000000000000C402000000007800000078000000770000000800000001F47115C8F471150000000000000000AD0700000000007C0000007C00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0033003100380030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0034003900350030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000810000008100000000000000580000000103737401000000640062006F00000046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F0043006100740061006C006F006700750065004900740065006D0000000000000000000000C402000000008200000082000000810000000800000001F4711588F471150000000000000000AD070000000000830000008300000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000008400000084000000000000006800000001016F0001000000640062006F00000046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F004F0077006E00650072005F0049007300730075006500530079007300740065006D00550073006500720000000000000000000000C402000000008500000085000000840000000800000001F4711548F471150000000000000000AD0700000000008600000086000000000000006E000000011A5F5E01000000640062006F00000046004B005F0043006100740061006C006F006700750065004900740065006D00490073007300750065005F005200650070006F0072007400650072005F0049007300730075006500530079007300740065006D00550073006500720000000000000000000000C402000000008700000087000000860000000800000001F4711508F471150000000000000000AD070000000000880000008800000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000008B0000008B000000000000003E0000000105000001000000640062006F00000046004B005F0043006F006C0075006D006E0049006E0066006F005F0041004E004F005400610062006C00650000000000000000000000C402000000008C0000008C0000008B0000000800000001F37115C8F371150000000000000000AD0700000000008D0000008D00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003100330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000008E0000008E00000000000000580000000102737401000000640062006F00000046004B005F005000720065004C006F006100640044006900730063006100720064006500640043006F006C0075006D006E005F005400610062006C00650049006E0066006F0000000000000000000000C402000000008F0000008F0000008E0000000800000001F3711588F371150000000000000000AD070000000000900000009000000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003600300035002C0031002C0031003300320030002C0035002C003800370030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003600300035000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003600300035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003600300035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003600300035002C00310032002C0031003900300035002C00310031002C0031003100370030000000910000009100000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003A00000034002C0030002C003200380034002C0030002C0032003200390035002C0031002C0031003800370035002C0035002C0031003200340035000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0032003200390035000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0032003200390035002C00310032002C0032003700310035002C00310031002C0031003600360035000000940000009400000000000000560000000101737401000000640062006F00000046004B005F00500072006F0063006500730073005400610073006B0041007200670075006D0065006E0074005F00500072006F0063006500730073005400610073006B0000000000000000000000C402000000009500000095000000940000000800000001F3711548F371150000000000000000AD0700000000009600000096000000000000006800000001016F0001000000640062006F00000046004B005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E005F00450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E0000000000000000000000C402000000009700000097000000960000000800000001F3711508F371150000000000000000AD0700000000009A0000009A000000000000004200000001038A7601000000640062006F00000046004B005F00500072006F0063006500730073005400610073006B005F0043006100740061006C006F0067007500650000000000000000000000C402000000009B0000009B0000009A0000000800000001F27115C8F271150000000000000000AD0700000000009C0000009C000000000000000800000001F2711588F271150000000000000000E40700000000009D0000009D00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C00310033003300350000009E0000009E00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0033003500320035002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008002000000032002C0030002C003200380034002C0030002C00310030003800370035000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000A2000000A200000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000A3000000A300000000000000580000000103737401000000640062006F00000046004B005F005400610062006C00650049006E0066006F005F00450078007400650072006E0061006C004400610074006100620061007300650053006500720076006500720000000000000000000000C40200000000A4000000A4000000A30000000800000001F2711548F271150000000000000000AD070000000000A6000000A600000000000000580000000103737401000000640062006F00000046004B005F0043006100740061006C006F006700750065005F00450078007400650072006E0061006C004400610074006100620061007300650053006500720076006500720000000000000000000000C40200000000A7000000A7000000A60000000800000001F2711508F271150000000000000000AD070000000000A8000000A8000000000000005A00000001075F5E01000000640062006F00000046004B005F0043006100740061006C006F006700750065005F00450078007400650072006E0061006C0044006100740061006200610073006500530065007200760065007200310000000000000000000000C40200000000A9000000A9000000A80000000800000001F17115C8F171150000000000000000AD070000000000AA000000AA00000000000000560000000103737401000000640062006F00000046004B005F0041004E004F005400610062006C0065005F00450078007400650072006E0061006C004400610074006100620061007300650053006500720076006500720000000000000000000000C40200000000AB000000AB000000AA0000000800000001F1711588F171150000000000000000AD070000000000AC000000AC00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0033003400360035002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000AF000000AF000000000000006A000000011A5F5E01000000640062006F00000046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E0000000000000000000000C40200000000B0000000B0000000AF0000000800000001F1711548F171150000000000000000AD070000000000BD000000BD00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000031000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0033003400350030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000BE000000BE000000000000004400000001038A7601000000640062006F00000046004B005F0043006100740061006C006F006700750065005F004C006F00610064004D00650074006100640061007400610000000000000000000000C40200000000BF000000BF000000BE0000000800000001F1711508F171150000000000000000AD070000000000C0000000C000000000000000520000000103737401000000640062006F00000046004B005F004C006F006100640050006500720069006F0064006900630061006C006C0079005F004C006F00610064004D00650074006100640061007400610000000000000000000000C40200000000C1000000C1000000C00000000800000001F07115C8F071150000000000000000AD070000000000C2000000C2000000000000004800000001038A7601000000640062006F00000046004B005F00500072006F0063006500730073005400610073006B005F004C006F00610064004D00650074006100640061007400610000000000000000000000C40200000000C3000000C3000000C20000000800000001F0711588F071150000000000000000AD070000000000C4000000C4000000000000004A00000001FF5F5E01000000640062006F00000046004B005F004C006F00610064005300630068006500640075006C0065005F004C006F00610064004D00650074006100640061007400610000000000000000000000C40200000000C5000000C5000000C40000000800000001F0711548F071150000000000000000AD070000000000C6000000C600000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0031003800330030002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0032003700390030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000C7000000C7000000000000006600000001006F0001000000640062006F00000046004B005F0044004C004500570069006E0064006F0077007300530065007200760069006300650045007800630065007000740069006F006E005F004C006F00610064004D00650074006100640061007400610000000000000000000000C40200000000C8000000C8000000C70000000800000001F0711508F071150000000000000000AD070000000000C9000000C900000000000000540000000103737401000000640062006F00000046004B005F004C006F006100640050006500720069006F0064006900630061006C006C0079005F004C006F00610064004D006500740061006400610074006100310000000000000000000000C40200000000CA000000CA000000C90000000800000001EF7115C8EF71150000000000000000AD070000000000CB000000CB00000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003200390035002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000CC000000CC00000000000000740000000102000001000000640062006F00000046004B005F0041006700670072006500670061007400650043006F006E00740069006E0075006F0075007300440061007400650041007800690073005F00410067006700720065006700610074006500440069006D0065006E00730069006F006E0000000000000000000000C40200000000CD000000CD000000CC0000000800000001EF711588EF71150000000000000000AD070000000000D0000000D000000000000000000000000000000000000000D00200000600280000004100630074006900760065005400610062006C00650056006900650077004D006F006400650000000100000008000400000030000000200000005400610062006C00650056006900650077004D006F00640065003A00300000000100000008003800000034002C0030002C003200380034002C0030002C0032003300320035002C0031002C0031003500300030002C0035002C003900390030000000200000005400610062006C00650056006900650077004D006F00640065003A00310000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00320000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00330000000100000008001E00000032002C0030002C003200380034002C0030002C0031003800330030000000200000005400610062006C00650056006900650077004D006F00640065003A00340000000100000008003E00000034002C0030002C003200380034002C0030002C0031003800330030002C00310032002C0032003100370035002C00310031002C0031003300330035000000D1000000D1000000000000006C000000011A5F5E01000000640062006F00000046004B005F0041006700670072006500670061007400650046006F0072006300650064004A006F0069006E005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E0000000000000000000000C40200000000D2000000D2000000D10000000800000001EF711548EF71150000000000000000AD070000000000D3000000D300000000000000520000000100737401000000640062006F00000046004B005F0041006700670072006500670061007400650046006F0072006300650064004A006F0069006E005F005400610062006C00650049006E0066006F0000000000000000000000C40200000000D4000000D4000000D30000000800000001B5511558B551150000000000000000AD070000000000D5000000D500000000000000580000000103737401000000640062006F00000046004B005F0041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E005F0043006100740061006C006F0067007500650000000000000000000000C40200000000D6000000D6000000D50000000800000001337715E03377150000000000000000AD0F0000010000EB00000081000000010000007C00000056000000D200000016000000010000000D0000008C00000085000000D5000000020000005F0000008C000000710000005D000000020000005C00000097000000AA0000001900000002000000180000009F0000008000000003000000020000000100000000000000010000009A0000000200000090000000E30100002100000007000000050000000600000038000000210000008E000000050000008D0000008C00000093000000D300000005000000D00000008D000000A600000012000000060000000D0000008A000000C80000002700000006000000240000002A000000390000002900000006000000240000003C0000004B0000002B0000000600000024000000200000002F00000033000000060000002F000000A20000008D00000035000000060000002F000000B20000009D00000056000000060000004C000000140000009C00000059000000060000004C0000000600000090000000960000001B00000071000000930000003D000000220000001B0000000D0000004000000033000000390000001B00000038000000170000004E000000400000001B000000020000007F000000C001000054000000240000004C0000001C0000001B0000003C000000380000003B000000350000002C000000720000005F00000071000000A500000090000000D10000005F000000D00000000F0000007200000074000000600000005F00000080000000730000006F000000600000006E0000009F000000720000006600000060000000630000007300000088000000640000006000000063000000870000009C000000770000006E000000760000007900000072000000AF000000710000005F000000B6000000CB000000CC00000071000000CB0000004B0000000000000084000000830000007C00000009000000B700000086000000830000007C000000A60000007C0000008B000000880000000600000073000000E2000000940000009000000091000000830000008C000000AA000000A2000000880000009C00000037000000A8000000A2000000020000006D0000001A020000A6000000A2000000020000008100000008020000A3000000A200000005000000940000003F000000C9000000BD000000AC0000004D0000005C000000BE000000BD000000020000006000000013010000C0000000BD000000AC0000001101000002000000C2000000BD00000090000000AD000000AC000000C4000000BD0000009E000000F7000000C2000000C7000000BD000000C6000000010000002E0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000700070006C00690063006100740069006F006E0020004E0061006D0065003D0022004D006900630072006F0073006F00660074002000530051004C00200053006500720076006500720020004D0061006E006100670065006D0065006E0074002000530074007500640069006F0022000000008005002E00000043006100740061006C006F006700750065005F0044006100740061005F004400690061006700720061006D000000000226002800000041006700670072006500670061007400650046006F0072006300650064004A006F0069006E00000008000000640062006F000000000226003800000041006700670072006500670061007400650043006F006E00740069006E0075006F007500730044006100740065004100780069007300000008000000640062006F000000000226003600000044004C004500570069006E0064006F0077007300530065007200760069006300650045007800630065007000740069006F006E00000008000000640062006F000000000226001A0000004C006F00610064004D006500740061006400610074006100000008000000640062006F00000000022600220000004C006F006100640050006500720069006F0064006900630061006C006C007900000008000000640062006F000000000226002E000000450078007400650072006E0061006C0044006100740061006200610073006500530065007200760065007200000008000000640062006F000000000226001A0000004C006F00610064005300630068006500640075006C006500000008000000640062006F00000000022600260000004C006F00610064004D006F00640075006C00650041007300730065006D0062006C007900000008000000640062006F0000000002260028000000500072006F0063006500730073005400610073006B0041007200670075006D0065006E007400000008000000640062006F0000000002260018000000500072006F0063006500730073005400610073006B00000008000000640062006F000000000226002E0000005000720065004C006F006100640044006900730063006100720064006500640043006F006C0075006D006E00000008000000640062006F000000000226001200000041004E004F005400610062006C006500000008000000640062006F000000000226002000000049007300730075006500530079007300740065006D005500730065007200000008000000640062006F000000000226002600000043006100740061006C006F006700750065004900740065006D0049007300730075006500000008000000640062006F0000000002260032000000410067006700720065006700610074006500460069006C0074006500720050006100720061006D006500740065007200000008000000640062006F0000000002260026000000410067006700720065006700610074006500440069006D0065006E00730069006F006E00000008000000640062006F0000000002260020000000410067006700720065006700610074006500460069006C00740065007200000008000000640062006F0000000002260038000000410067006700720065006700610074006500460069006C0074006500720053007500620043006F006E007400610069006E0065007200000008000000640062006F0000000002260032000000410067006700720065006700610074006500460069006C0074006500720043006F006E007400610069006E0065007200000008000000640062006F000000000226002E00000041006700670072006500670061007400650043006F006E00660069006700750072006100740069006F006E00000008000000640062006F000000000226002600000053007500700070006F007200740069006E006700530051004C005400610062006C006500000008000000640062006F00000000022600300000004C006F006F006B007500700043006F006D0070006F0073006900740065004A006F0069006E0049006E0066006F00000008000000640062006F0000000002260034000000450078007400720061006300740069006F006E00460069006C0074006500720050006100720061006D006500740065007200000008000000640062006F0000000002260022000000450078007400720061006300740069006F006E00460069006C00740065007200000008000000640062006F00000000022600120000004A006F0069006E0049006E0066006F00000008000000640062006F000000000226000E0000004C006F006F006B0075007000000008000000640062006F000000000226002C000000450078007400720061006300740069006F006E0049006E0066006F0072006D006100740069006F006E00000008000000640062006F000000000226002600000053007500700070006F007200740069006E00670044006F00630075006D0065006E007400000008000000640062006F000000000226003200000043006F006C0075006D006E0049006E0066006F005F0043006100740061006C006F006700750065004900740065006D00000008000000640062006F000000000226001600000043006F006C0075006D006E0049006E0066006F00000008000000640062006F00000000022600140000005400610062006C00650049006E0066006F00000008000000640062006F000000000226001400000043006100740061006C006F00670075006500000008000000640062006F000000000224001C00000043006100740061006C006F006700750065004900740065006D00000008000000640062006F00000001000000D68509B3BB6BF2459AB8371664F0327008004E0000007B00310036003300340043004400440037002D0030003800380038002D0034003200450033002D0039004600410032002D004200360044003300320035003600330042003900310044007D00000000000000000000000000000000000000000000000000000000000000010003000000000000000C0000000B00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000062885214) diff --git a/Rdmp.Core/Databases/CatalogueDatabase/up/077_AddDataSetMapping.sql b/Rdmp.Core/Databases/CatalogueDatabase/up/077_AddDataSetMapping.sql new file mode 100644 index 0000000000..114460613d --- /dev/null +++ b/Rdmp.Core/Databases/CatalogueDatabase/up/077_AddDataSetMapping.sql @@ -0,0 +1,27 @@ +--Version:8.1.1 +--Description: Adds tables to model external datasets + GO +-- Create Dataset table +if not exists(select 1 from sys.columns where object_id = OBJECT_ID('Dataset')) +BEGIN +CREATE TABLE [dbo].Dataset( + [ID] [int] IDENTITY(1,1) NOT NULL, + [Name] [varchar](256) NOT NULL, + [Folder] [nvarchar](1000) NOT NULL, + [DigitalObjectIdentifier] [varchar](256) NULL, + [Source] [varchar](256) NULL, + CONSTRAINT [PK_Dataset] PRIMARY KEY CLUSTERED +( + [ID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] +END +GO + +IF NOT EXISTS(SELECT 1 FROM sys.columns + WHERE Name = N'Dataset_ID' + AND Object_ID = Object_ID('ColumnInfo')) +BEGIN +ALTER TABLE [dbo].[ColumnInfo] ADD Dataset_ID [int] NULL +ALTER TABLE [dbo].[ColumnInfo] ADD CONSTRAINT [FK_Column_Info_Dataset] FOREIGN KEY([Dataset_ID]) REFERENCES [dbo].[Dataset] ([ID]) ON DELETE CASCADE ON UPDATE CASCADE +END diff --git a/Rdmp.Core/Databases/LoggingDatabase/runAfterCreateDatabase/CreateLogging.sql b/Rdmp.Core/Databases/LoggingDatabase/runAfterCreateDatabase/CreateLogging.sql index ae6c828f99..3e5b9173dc 100644 --- a/Rdmp.Core/Databases/LoggingDatabase/runAfterCreateDatabase/CreateLogging.sql +++ b/Rdmp.Core/Databases/LoggingDatabase/runAfterCreateDatabase/CreateLogging.sql @@ -324,7 +324,7 @@ INSERT [dbo].[z_DataLoadTaskStatus] ([ID], [status], [description]) VALUES (1, N GO INSERT [dbo].[z_DataLoadTaskStatus] ([ID], [status], [description]) VALUES (2, N'Ready', NULL) GO -INSERT [dbo].[z_DataLoadTaskStatus] ([ID], [status], [description]) VALUES (3, N'Commited', NULL) +INSERT [dbo].[z_DataLoadTaskStatus] ([ID], [status], [description]) VALUES (3, N'Committed', NULL) GO SET IDENTITY_INSERT [dbo].[z_DataLoadTaskStatus] OFF GO diff --git a/Rdmp.Core/Dataset/DatasetConfigurationUICommon.cs b/Rdmp.Core/Dataset/DatasetConfigurationUICommon.cs new file mode 100644 index 0000000000..d51360e1a2 --- /dev/null +++ b/Rdmp.Core/Dataset/DatasetConfigurationUICommon.cs @@ -0,0 +1,31 @@ +// Copyright (c) The University of Dundee 2018-2019 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using Rdmp.Core.CommandExecution; + +namespace Rdmp.Core.Dataset; + +/// +/// Common methods used by Cohort Builder UI implementations. Eliminates +/// code duplication and makes it possible to add new UI formats later +/// e.g. web/console etc +/// +public class DatasetConfigurationUICommon +{ + /// + /// User interface layer for modal dialogs, showing Exceptions etc + /// + public IBasicActivateItems Activator; + + public Curation.Data.Dataset Dataset; + + + public DatasetConfigurationUICommon() + { + } + + +} \ No newline at end of file diff --git a/Rdmp.Core/Icons/AllExpiredPluginsNode.png b/Rdmp.Core/Icons/AllExpiredPluginsNode.png deleted file mode 100644 index bec6c0b594750a5eaa94fb408891f527edd8efc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 973 zcmV;;12X)HP)N2bZe?^J zG%hhNHvLWs=l}o%OG!jQR5(wKlt)YBQ541hA0o4y#e9cZ*g-@T3t|BSE(EuNf@Gx& z6$V{c7Gfg`20=tDpn?Ul#@>x>?6J3KCZ=cd&zXC#8Y04A;4G57`+Mh}ci&UqKhx9G z8WN_arZ6!v0i)4~xw*M7i)-Idib4?0`1m*s1_SEq>af4Rk3b;sWijv#r6^-#W160x z9;BtEAuB5jy}i9~yWOzc?YO_c$JNypE-x>Gy1l)H&1Qqo=lcwsoSf8*j*gq>Dk{*{)`s=R99Dn^JdsAwP>E5owYEG`+t0VM00bq!1ng`B%jvSR-~k) ze1frZa&j;-G6H3AaL`VH`Z>&Z*xlV7s;a7xmzRgGt}YA@52LuaSe%80g&{IBQuGc> zPEM9J?9B1>^yGhec?rVUNo8dvVq;^W)oLZPgoFe{M@J()JstV^`6wtTKz4Svw3(EY z^a|_i>$5#PJowp7D2z`lv=vrnW~Q{y>$bMG(An83EvBZXzQQPACl#yL*Vq4rMMXtH zr_%|<>-EC#_scpSlZ=dvAk24ja}ywUI6OR*k=WkehQ(r$B9F%dm&+9t&y>UAfU2t4 z*w}zxua_9)0J^)oeRO(cC?M0!VhD>1x&8C=bDW-@%4U4cctgrr2Ac<*^Oez{)AG`F z32-r===1ZlxMBzoZzyDEX9t^`n=+)_$>QRozk`(11)DSD~Q%P4g00000NkvXXu0mjf`bN&R diff --git a/Rdmp.Core/Icons/Dataset.png b/Rdmp.Core/Icons/Dataset.png new file mode 100644 index 0000000000000000000000000000000000000000..693709cbc1b156839a754e53cbaf409edec69567 GIT binary patch literal 726 zcmV;{0xA88P)T&uF!>{(iS?1OX-eX zKw9bunxR5FrF6QaYs~9>A4#zW^dwIvCpq(+cfR?U`T6-{9LHUqo16RKcDwUVr?cX4 zIN~hJDs48~aRAJ}U_2g=KAB9SP$;0;Y@*$6Ly{z<(`i^NmbL#1W@l#$wOS3;YPBOE zJ;7`?L*?Ga6XzC292wl75}>gDz`(>h?is$JPxm#0jGnotoK|nAVM5$DQ z!C*kO-aeF@+Ejy?nVHEp8V&F~k7BWicsx!aH9kHLRpcQ?L&JFBAB4i&kAaVUxVvzh z3a-EY0%m%8nhI7|SE(QpiBL#sG#VUMM9}*(0mg2(Q$Zq;z|PJNd_Euiem@;jtJN@i za|c2MmsL?PR;yKNwOUA}QuO=7;V@#c7!{~gs?J7hAlsE7U#g?$aRkhSTqLq6iuCu9 z10_j_=;?Dc?4cZ386qH0HkgHTDT|HmGR`W4V2noNQJqfLJEot)q{V_UtsW+m31cP~ zDwWEi3HYBSoF4M;T?VaIdqinn1HZ9}32qs-PdwPbCf+WI6n9jl0-8cjV3%1FB%B&r z+`mzSliyLSH0dxYE}rk&=!uCa*V>()2znj`_XYjtbt>@4FLHnJE|G`xv)Ba@oLBny z1%3K7c4fiB^4{k6E8Pif0kNy62}b@9+ RDMPConcept.Favourite, RDMPCollection.Cohort => RDMPConcept.CohortIdentificationConfiguration, RDMPCollection.DataLoad => RDMPConcept.LoadMetadata, + RDMPCollection.Datasets => RDMPConcept.Dataset, _ => throw new ArgumentOutOfRangeException(nameof(rdmpCollection)) }; } diff --git a/Rdmp.Core/Icons/IconProvision/CatalogueIcons.Designer.cs b/Rdmp.Core/Icons/IconProvision/CatalogueIcons.Designer.cs index 46ca977cb6..765963e39d 100644 --- a/Rdmp.Core/Icons/IconProvision/CatalogueIcons.Designer.cs +++ b/Rdmp.Core/Icons/IconProvision/CatalogueIcons.Designer.cs @@ -184,16 +184,6 @@ public static Byte[] AllDataAccessCredentialsNode { } } - /// - /// Looks up a localized resource of type Image. - /// - public static Byte[] AllExpiredPluginsNode { - get { - object obj = ResourceManager.GetObject("AllExpiredPluginsNode", resourceCulture); - return ((Byte[])(obj)); - } - } - /// /// Looks up a localized resource of type Image. /// @@ -1265,7 +1255,20 @@ public static Byte[] LoadBubble { return ((Byte[])(obj)); } } - + + + /// + /// Looks up a localized resource of type Image. + /// + public static Byte[] Dataset + { + get + { + object obj = ResourceManager.GetObject("Dataset", resourceCulture); + return ((Byte[])(obj)); + } + } + /// /// Looks up a localized resource of type Image. /// diff --git a/Rdmp.Core/Icons/IconProvision/CatalogueIcons.resx b/Rdmp.Core/Icons/IconProvision/CatalogueIcons.resx index 5a01456fdf..c8154eed89 100644 --- a/Rdmp.Core/Icons/IconProvision/CatalogueIcons.resx +++ b/Rdmp.Core/Icons/IconProvision/CatalogueIcons.resx @@ -667,9 +667,6 @@ ..\WhatIsACohort.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\AllExpiredPluginsNode.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - ..\AllPluginsNode.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -751,7 +748,10 @@ ..\Memento.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + ..\TableInfoDatabaseNode.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Dataset.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/Rdmp.Core/Icons/IconProvision/RDMPConcept.cs b/Rdmp.Core/Icons/IconProvision/RDMPConcept.cs index d2aa93bab7..5c3ee77f1d 100644 --- a/Rdmp.Core/Icons/IconProvision/RDMPConcept.cs +++ b/Rdmp.Core/Icons/IconProvision/RDMPConcept.cs @@ -179,7 +179,6 @@ public enum RDMPConcept CohortAggregateContainer, AllPluginsNode, - AllExpiredPluginsNode, ProcessTask, @@ -203,5 +202,6 @@ public enum RDMPConcept MutilateDataTables, Commit, Memento, - TableInfoDatabaseNode + TableInfoDatabaseNode, + Dataset } \ No newline at end of file diff --git a/Rdmp.Core/Icons/IconProvision/StateBasedIconProviders/ProcessTaskStateBasedIconProvider.cs b/Rdmp.Core/Icons/IconProvision/StateBasedIconProviders/ProcessTaskStateBasedIconProvider.cs index c866bb57cf..98b52aeb37 100644 --- a/Rdmp.Core/Icons/IconProvision/StateBasedIconProviders/ProcessTaskStateBasedIconProvider.cs +++ b/Rdmp.Core/Icons/IconProvision/StateBasedIconProviders/ProcessTaskStateBasedIconProvider.cs @@ -41,6 +41,7 @@ public Image GetImageIfSupportedObject(object o) { ProcessTaskType.Executable => _exe, ProcessTaskType.SQLFile => _sql, + ProcessTaskType.SQLBakFile => _sql, ProcessTaskType.Attacher => _attacher, ProcessTaskType.DataProvider => _dataProvider, ProcessTaskType.MutilateDataTable => _mutilateDataTables, diff --git a/Rdmp.Core/MapsDirectlyToDatabaseTable/MemoryRepository.cs b/Rdmp.Core/MapsDirectlyToDatabaseTable/MemoryRepository.cs index be2241cca2..567c3573f1 100644 --- a/Rdmp.Core/MapsDirectlyToDatabaseTable/MemoryRepository.cs +++ b/Rdmp.Core/MapsDirectlyToDatabaseTable/MemoryRepository.cs @@ -13,6 +13,7 @@ using System.Reflection; using Rdmp.Core.MapsDirectlyToDatabaseTable.Injection; using Rdmp.Core.MapsDirectlyToDatabaseTable.Revertable; +using Rdmp.Core.ReusableLibraryCode.Annotations; namespace Rdmp.Core.MapsDirectlyToDatabaseTable; @@ -225,20 +226,18 @@ protected virtual void CascadeDeletes(IMapsDirectlyToDatabaseTable oTableWrapper { } - public void RevertToDatabaseState(IMapsDirectlyToDatabaseTable mapsDirectlyToDatabaseTable) + public void RevertToDatabaseState([NotNull] IMapsDirectlyToDatabaseTable mapsDirectlyToDatabaseTable) { //Mark any cached data as out of date if (mapsDirectlyToDatabaseTable is IInjectKnown inject) inject.ClearAllInjections(); - if (!_propertyChanges.ContainsKey(mapsDirectlyToDatabaseTable)) + if (!_propertyChanges.TryGetValue(mapsDirectlyToDatabaseTable, out var changedExtendedEventArgsSet)) return; var type = mapsDirectlyToDatabaseTable.GetType(); - foreach (var e in - _propertyChanges[mapsDirectlyToDatabaseTable] - .ToArray()) //call ToArray to avoid cyclical events on SetValue + foreach (var e in changedExtendedEventArgsSet.ToArray()) //call ToArray to avoid cyclical events on SetValue { var prop = type.GetProperty(e.PropertyName); prop.SetValue(mapsDirectlyToDatabaseTable, e.OldValue); //reset the old values @@ -248,6 +247,7 @@ public void RevertToDatabaseState(IMapsDirectlyToDatabaseTable mapsDirectlyToDat _propertyChanges.TryRemove(mapsDirectlyToDatabaseTable, out _); } + [NotNull] public RevertableObjectReport HasLocalChanges(IMapsDirectlyToDatabaseTable mapsDirectlyToDatabaseTable) { //if we don't know about it then it was deleted @@ -255,12 +255,12 @@ public RevertableObjectReport HasLocalChanges(IMapsDirectlyToDatabaseTable mapsD return new RevertableObjectReport { Evaluation = ChangeDescription.DatabaseCopyWasDeleted }; //if it has no changes (since a save) - if (!_propertyChanges.ContainsKey(mapsDirectlyToDatabaseTable)) + if (!_propertyChanges.TryGetValue(mapsDirectlyToDatabaseTable, out var changedExtendedEventArgsSet)) return new RevertableObjectReport { Evaluation = ChangeDescription.NoChanges }; //we have local 'unsaved' changes var type = mapsDirectlyToDatabaseTable.GetType(); - var differences = _propertyChanges[mapsDirectlyToDatabaseTable].Select( + var differences = changedExtendedEventArgsSet.Select( d => new RevertablePropertyDifference(type.GetProperty(d.PropertyName), d.NewValue, d.OldValue)) .ToList(); diff --git a/Rdmp.Core/Providers/CatalogueChildProvider.cs b/Rdmp.Core/Providers/CatalogueChildProvider.cs index 96b6c4a6cb..74eb02f694 100644 --- a/Rdmp.Core/Providers/CatalogueChildProvider.cs +++ b/Rdmp.Core/Providers/CatalogueChildProvider.cs @@ -63,6 +63,7 @@ public class CatalogueChildProvider : ICoreChildProvider //Catalogue side of things public Catalogue[] AllCatalogues { get; set; } + public Curation.Data.Dataset[] AllDatasets { get; set; } public Dictionary AllCataloguesDictionary { get; private set; } public SupportingDocument[] AllSupportingDocuments { get; set; } @@ -138,6 +139,8 @@ public class CatalogueChildProvider : ICoreChildProvider public AllPermissionWindowsNode AllPermissionWindowsNode { get; set; } public FolderNode LoadMetadataRootFolder { get; set; } + + public FolderNode DatasetRootFolder { get; set; } public FolderNode CohortIdentificationConfigurationRootFolder { get; set; } public AllConnectionStringKeywordsNode AllConnectionStringKeywordsNode { get; set; } @@ -187,9 +190,6 @@ public class CatalogueChildProvider : ICoreChildProvider public JoinableCohortAggregateConfigurationUse[] AllJoinableCohortAggregateConfigurationUse { get; private set; } public AllPluginsNode AllPluginsNode { get; private set; } - public Plugin[] AllPlugins { get; private set; } - public Plugin[] AllCompatiblePlugins { get; private set; } - public HashSet PipelineUseCases { get; set; } = new(); /// @@ -244,6 +244,8 @@ public CatalogueChildProvider(ICatalogueRepository repository, IChildProvider[] AllCatalogues = GetAllObjects(repository); AllCataloguesDictionary = AllCatalogues.ToDictionaryEx(i => i.ID, o => o); + AllDatasets = GetAllObjects(repository); + AllLoadMetadatas = GetAllObjects(repository); AllProcessTasks = GetAllObjects(repository); AllProcessTasksArguments = GetAllObjects(repository); @@ -379,6 +381,10 @@ public CatalogueChildProvider(ICatalogueRepository repository, IChildProvider[] CatalogueRootFolder = FolderHelper.BuildFolderTree(AllCatalogues); AddChildren(CatalogueRootFolder, new DescendancyList(CatalogueRootFolder)); + + DatasetRootFolder = FolderHelper.BuildFolderTree(AllDatasets); + AddChildren(DatasetRootFolder, new DescendancyList(DatasetRootFolder)); + ReportProgress("Build Catalogue Folder Root"); LoadMetadataRootFolder = FolderHelper.BuildFolderTree(AllLoadMetadatas); @@ -432,9 +438,6 @@ public CatalogueChildProvider(ICatalogueRepository repository, IChildProvider[] ReportProgress("After Governance"); AllPluginsNode = new AllPluginsNode(); - AllPlugins = GetAllObjects(repository); - AllCompatiblePlugins = _catalogueRepository.PluginManager.GetCompatiblePlugins(); - AddChildren(AllPluginsNode); ReportProgress("After Plugins"); @@ -579,26 +582,8 @@ protected void ReportProgress(string desc) private void AddChildren(AllPluginsNode allPluginsNode) { - var children = new HashSet(); + var children = new HashSet(LoadModuleAssembly.Assemblies); var descendancy = new DescendancyList(allPluginsNode); - - foreach (var p in AllCompatiblePlugins) - children.Add(p); - - var expiredPluginsNode = new AllExpiredPluginsNode(); - children.Add(expiredPluginsNode); - AddChildren(expiredPluginsNode, descendancy.Add(expiredPluginsNode)); - - AddToDictionaries(children, descendancy); - } - - private void AddChildren(AllExpiredPluginsNode expiredPluginsNode, DescendancyList descendancy) - { - var children = new HashSet(); - - foreach (var p in AllPlugins.Except(AllCompatiblePlugins)) - children.Add(p); - AddToDictionaries(children, descendancy); } @@ -626,7 +611,6 @@ private void AddChildren(GovernancePeriod governancePeriod, DescendancyList desc AddToDictionaries(children, descendancy); } - private void AddChildren(AllPermissionWindowsNode allPermissionWindowsNode) { var descendancy = new DescendancyList(allPermissionWindowsNode); @@ -848,6 +832,22 @@ private void AddChildren(FolderNode folder, DescendancyList descen ); } + private void AddChildren(FolderNode folder, DescendancyList descendancy) + { + foreach (var child in folder.ChildFolders) + //add subfolder children + AddChildren(child, descendancy.Add(child)); + + //add loads in folder + foreach (var ds in folder.ChildObjects) AddChildren(ds, descendancy.Add(ds)); + + // Children are the folders + objects + AddToDictionaries(new HashSet( + folder.ChildFolders.Cast() + .Union(folder.ChildObjects)), descendancy + ); + } + private void AddChildren(FolderNode folder, DescendancyList descendancy) { foreach (var child in folder.ChildFolders) @@ -864,6 +864,13 @@ private void AddChildren(FolderNode folder, D ); } + private void AddChildren(Curation.Data.Dataset lmd, DescendancyList descendancy) + { + var childObjects = new List(); + AddToDictionaries(new HashSet(childObjects), descendancy); + } + + #region Load Metadata private void AddChildren(LoadMetadata lmd, DescendancyList descendancy) @@ -1511,19 +1518,18 @@ public virtual object[] GetChildren(object model) { lock (WriteLock) { - //if we don't have a record of any children in the child dictionary for the parent model object - if (!_childDictionary.ContainsKey(model)) + //if we have a record of any children in the child dictionary for the parent model object + if (_childDictionary.TryGetValue(model,out var cached)) + return cached.OrderBy(static o => o.ToString()).ToArray(); + + return model switch { //if they want the children of a Pipeline (which we don't track) just serve the components - if (model is Pipeline p) return p.PipelineComponents.ToArray(); + Pipeline p => p.PipelineComponents.ToArray(), //if they want the children of a PipelineComponent (which we don't track) just serve the arguments - if (model is PipelineComponent pc) return pc.PipelineComponentArguments.ToArray(); - - return Array.Empty(); //return none - } - - - return _childDictionary[model].OrderBy(o => o.ToString()).ToArray(); + PipelineComponent pc => pc.PipelineComponentArguments.ToArray(), + _ => Array.Empty() + }; } } @@ -1781,8 +1787,6 @@ public virtual void UpdateTo(ICoreChildProvider other) GovernanceCoverage = otherCat.GovernanceCoverage; AllJoinableCohortAggregateConfigurationUse = otherCat.AllJoinableCohortAggregateConfigurationUse; AllPluginsNode = otherCat.AllPluginsNode; - AllPlugins = otherCat.AllPlugins; - AllCompatiblePlugins = otherCat.AllCompatiblePlugins; PipelineUseCases = otherCat.PipelineUseCases; OrphanAggregateConfigurationsNode = otherCat.OrphanAggregateConfigurationsNode; TemplateAggregateConfigurationsNode = otherCat.TemplateAggregateConfigurationsNode; diff --git a/Rdmp.Core/Providers/DataExportChildProvider.cs b/Rdmp.Core/Providers/DataExportChildProvider.cs index 2014248761..2d36cec369 100644 --- a/Rdmp.Core/Providers/DataExportChildProvider.cs +++ b/Rdmp.Core/Providers/DataExportChildProvider.cs @@ -621,13 +621,14 @@ private void ForbidList(ExternalCohortTable source, Exception ex) public List GetAllCohortProjectUsageNodesFor(Project project) { //if the current project does not have a number or there are no cohorts associated with it - if (project.ProjectNumber == null || !ProjectNumberToCohortsDictionary.ContainsKey(project.ProjectNumber.Value)) + if (project.ProjectNumber == null || + !ProjectNumberToCohortsDictionary.TryGetValue(project.ProjectNumber.Value, out var cohorts)) return new List(); var toReturn = new List(); - foreach (var cohort in ProjectNumberToCohortsDictionary[project.ProjectNumber.Value]) + foreach (var cohort in cohorts) { //get the source of the cohort var source = CohortSources.Single(s => s.ID == cohort.ExternalCohortTable_ID); @@ -798,6 +799,7 @@ public override void UpdateTo(ICoreChildProvider other) _extractionInformationsByCatalogueItem = dxOther._extractionInformationsByCatalogueItem; _extractionProgressesBySelectedDataSetID = dxOther._extractionProgressesBySelectedDataSetID; ProjectRootFolder = dxOther.ProjectRootFolder; + DatasetRootFolder = dxOther.DatasetRootFolder; } } diff --git a/Rdmp.Core/Providers/DatasetChildProvider.cs b/Rdmp.Core/Providers/DatasetChildProvider.cs new file mode 100644 index 0000000000..897ceff035 --- /dev/null +++ b/Rdmp.Core/Providers/DatasetChildProvider.cs @@ -0,0 +1,18 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see .using Rdmp.Core.Repositories; +using Rdmp.Core.Repositories; +using Rdmp.Core.ReusableLibraryCode.Checks; + +namespace Rdmp.Core.Providers; + +/// +public class DatasetChildProvider : CatalogueChildProvider +{ + public DatasetChildProvider(ICatalogueRepository repository, IChildProvider[] pluginChildProviders, ICheckNotifier errorsCheckNotifier, CatalogueChildProvider previousStateIfKnown) : base(repository, pluginChildProviders, errorsCheckNotifier, previousStateIfKnown) + { + } +} + diff --git a/Rdmp.Core/Providers/DescendancyList.cs b/Rdmp.Core/Providers/DescendancyList.cs index 102ef3c2f6..d1347b308c 100644 --- a/Rdmp.Core/Providers/DescendancyList.cs +++ b/Rdmp.Core/Providers/DescendancyList.cs @@ -83,7 +83,7 @@ public DescendancyList(params object[] parents) public DescendancyList Add(object anotherKnownParent) { if (Parents.Contains(anotherKnownParent)) - throw new ArgumentException($"DecendancyList already contains '{anotherKnownParent}'"); + throw new ArgumentException($"DescendancyList already contains '{anotherKnownParent}'"); var list = new List(Parents) { anotherKnownParent }; var toReturn = new DescendancyList(list.ToArray()) diff --git a/Rdmp.Core/Providers/ICoreChildProvider.cs b/Rdmp.Core/Providers/ICoreChildProvider.cs index c3879cf5da..a578400621 100644 --- a/Rdmp.Core/Providers/ICoreChildProvider.cs +++ b/Rdmp.Core/Providers/ICoreChildProvider.cs @@ -44,10 +44,12 @@ public interface ICoreChildProvider : IChildProvider JoinableCohortAggregateConfigurationUse[] AllJoinUses { get; set; } FolderNode CatalogueRootFolder { get; } + FolderNode DatasetRootFolder { get; } FolderNode LoadMetadataRootFolder { get; } FolderNode CohortIdentificationConfigurationRootFolder { get; } Catalogue[] AllCatalogues { get; } + Curation.Data.Dataset[] AllDatasets { get; } Dictionary AllCataloguesDictionary { get; } ExternalDatabaseServer[] AllExternalServers { get; } diff --git a/Rdmp.Core/Providers/Nodes/SingletonNode.cs b/Rdmp.Core/Providers/Nodes/SingletonNode.cs index f0be05289b..22ddbaeda0 100644 --- a/Rdmp.Core/Providers/Nodes/SingletonNode.cs +++ b/Rdmp.Core/Providers/Nodes/SingletonNode.cs @@ -12,22 +12,19 @@ namespace Rdmp.Core.Providers.Nodes; /// public abstract class SingletonNode : Node { - protected readonly string Caption; + private readonly string _caption; protected SingletonNode(string caption) { - Caption = caption; + _caption = caption; } - public override string ToString() => Caption; + public override string ToString() => _caption; - protected bool Equals(SingletonNode other) => string.Equals(Caption, other.Caption); + public bool Equals(SingletonNode other) => string.Equals(_caption, other._caption); - public override bool Equals(object obj) - { - if (obj is null) return false; - return ReferenceEquals(this, obj) || obj is SingletonNode other && Equals(other); - } + public override bool Equals(object obj) => obj is SingletonNode sn && + Equals(sn); - public override int GetHashCode() => Caption.GetHashCode(); + public override int GetHashCode() => _caption.GetHashCode(); } \ No newline at end of file diff --git a/Rdmp.Core/QueryBuilding/ExtractionQueryBuilder.cs b/Rdmp.Core/QueryBuilding/ExtractionQueryBuilder.cs index 23910c4da0..ca684923e6 100644 --- a/Rdmp.Core/QueryBuilding/ExtractionQueryBuilder.cs +++ b/Rdmp.Core/QueryBuilding/ExtractionQueryBuilder.cs @@ -50,7 +50,7 @@ public QueryBuilder GetSQLCommandForFullExtractionSet(ExtractDatasetCommand requ if (request.ExtractableCohort == null) throw new NullReferenceException("No Cohort selected"); - + var databaseType = request.Catalogue.GetDistinctLiveDatabaseServerType() ?? throw new NotSupportedException( $"Catalogue {request.Catalogue} did not know what DatabaseType it hosted, how can we extract from it! does it have no TableInfos?"); var syntaxHelper = new QuerySyntaxHelperFactory().Create(databaseType); diff --git a/Rdmp.Core/QueryBuilding/Options/AggregateBuilderCohortOptions.cs b/Rdmp.Core/QueryBuilding/Options/AggregateBuilderCohortOptions.cs index c041e4abcb..95ea58cdb1 100644 --- a/Rdmp.Core/QueryBuilding/Options/AggregateBuilderCohortOptions.cs +++ b/Rdmp.Core/QueryBuilding/Options/AggregateBuilderCohortOptions.cs @@ -83,7 +83,7 @@ public bool ShouldBeEnabled(AggregateEditorSection section, AggregateConfigurati return section switch { AggregateEditorSection.Extractable => false, - AggregateEditorSection.TOPX => false, + AggregateEditorSection.TOPX => true, AggregateEditorSection.PIVOT => false, AggregateEditorSection.AXIS => false, _ => throw new ArgumentOutOfRangeException(nameof(section)) diff --git a/Rdmp.Core/QueryBuilding/QueryTimeColumn.cs b/Rdmp.Core/QueryBuilding/QueryTimeColumn.cs index 4e56c56a26..42bc7fd907 100644 --- a/Rdmp.Core/QueryBuilding/QueryTimeColumn.cs +++ b/Rdmp.Core/QueryBuilding/QueryTimeColumn.cs @@ -112,7 +112,7 @@ public static void SetLookupStatus(QueryTimeColumn[] ColumnsInOrder, List(); - + for (var i = 0; i < ColumnsInOrder.Length; i++) { //it is a custom column @@ -146,7 +146,7 @@ public static void SetLookupStatus(QueryTimeColumn[] ColumnsInOrder, List - - + + @@ -57,14 +55,11 @@ - + - + - + @@ -79,17 +74,14 @@ - + - + - + @@ -97,15 +89,13 @@ - + - + @@ -128,27 +118,24 @@ - - - + + + + - + - + - + @@ -183,114 +170,79 @@ - + Never - - + + - - - - + + + + - - - - + + + + - - - + + + - + - + - - - - + + + + - - - - - + + + + + - - - + + + - - - + + + - - + + - + - - + + - - + + + @@ -299,37 +251,25 @@ - - - - + + + + - - - + + + - - + + - + - - + + @@ -339,21 +279,17 @@ - + - - + + - + @@ -361,49 +297,37 @@ + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - - - - - - - + + + + + - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - + + + - + - - PreserveNewest - + + Never + + diff --git a/Rdmp.Core/Reports/DocXHelper.cs b/Rdmp.Core/Reports/DocXHelper.cs index b098b60612..c48ec02e97 100644 --- a/Rdmp.Core/Reports/DocXHelper.cs +++ b/Rdmp.Core/Reports/DocXHelper.cs @@ -59,17 +59,15 @@ protected static void InsertHeader(XWPFDocument document, string htext, int head r0.SetText(htext ?? ""); } - private static int GetSize(int headSize) - { - return headSize switch + private static int GetSize(int headSize) => + headSize switch { 1 => H1Size, 2 => H2Size, 3 => H3Size, 4 => H4Size, - _ => throw new ArgumentOutOfRangeException() + _ => throw new ArgumentOutOfRangeException(nameof(headSize)) }; - } protected static void SetTableCell(XWPFTable table, int row, int col, string value, int fontSize = -1) { diff --git a/Rdmp.Core/Reports/DublinCore/DublinCoreDefinition.cs b/Rdmp.Core/Reports/DublinCore/DublinCoreDefinition.cs index 1be3fe6333..e36004b1cc 100644 --- a/Rdmp.Core/Reports/DublinCore/DublinCoreDefinition.cs +++ b/Rdmp.Core/Reports/DublinCore/DublinCoreDefinition.cs @@ -7,7 +7,7 @@ using System; using System.IO; using System.Linq; -using System.Security; +using System.Xml; using System.Xml.Linq; namespace Rdmp.Core.Reports.DublinCore; @@ -105,7 +105,7 @@ public void WriteXml(Stream to) public void LoadFrom(XElement element) { if (element.Name != "metadata") - throw new XmlSyntaxException($"Expected metadata element but got {element}"); + throw new XmlException($"Expected metadata element but got {element}"); var descendants = element.Descendants().ToArray(); Title = GetElement(descendants, "title", true); @@ -137,7 +137,7 @@ private static string GetElement(XElement[] descendants, string tagLocalName, bo e.Name.LocalName.Equals(tagLocalName, StringComparison.CurrentCultureIgnoreCase)); if (match == null) - return mandatory ? throw new XmlSyntaxException($"Failed to find mandatory tag {tagLocalName}") : null; + return mandatory ? throw new XmlException($"Failed to find mandatory tag {tagLocalName}") : null; return match.Value.Trim(); } diff --git a/Rdmp.Core/Reports/ExtractionTime/WordDataReleaseFileGenerator.cs b/Rdmp.Core/Reports/ExtractionTime/WordDataReleaseFileGenerator.cs index ae1910d6d6..0ccb871060 100644 --- a/Rdmp.Core/Reports/ExtractionTime/WordDataReleaseFileGenerator.cs +++ b/Rdmp.Core/Reports/ExtractionTime/WordDataReleaseFileGenerator.cs @@ -12,6 +12,7 @@ using Rdmp.Core.DataExport.Data; using Rdmp.Core.Repositories; using Rdmp.Core.Repositories.Managers; +using Rdmp.Core.ReusableLibraryCode.Annotations; namespace Rdmp.Core.Reports.ExtractionTime; @@ -160,9 +161,15 @@ private void CreateCohortDetailsTable(XWPFDocument document) Cohort.GetCountDistinctFromDatabase(CohortCountTimeoutInSeconds).ToString("N0")); } + [NotNull] + private string getDOI([NotNull] Curation.Data.Dataset ds) + { + return !string.IsNullOrWhiteSpace(ds.DigitalObjectIdentifier) ? $" (DOI: {ds.DigitalObjectIdentifier})" : ""; + } + private void CreateFileSummary(XWPFDocument document) { - var table = InsertTable(document, ExtractionResults.Length + 1, 5); + var table = InsertTable(document, ExtractionResults.Length + 1, 6); var tableLine = 0; @@ -171,18 +178,23 @@ private void CreateFileSummary(XWPFDocument document) SetTableCell(table, tableLine, 2, "Filename"); SetTableCell(table, tableLine, 3, "Records"); SetTableCell(table, tableLine, 4, "Unique Individuals"); + SetTableCell(table, tableLine, 5, "Datasets"); tableLine++; foreach (var result in ExtractionResults) { var filename = GetFileName(result); - + var extractableDataset = _repository.GetObjectByID(result.ExtractableDataSet_ID); SetTableCell(table, tableLine, 0, - _repository.GetObjectByID(result.ExtractableDataSet_ID).ToString()); + extractableDataset.ToString()); + var linkedDatasets = extractableDataset.Catalogue.CatalogueItems.Select(static c => c.ColumnInfo).Where(ci => ci.Dataset_ID != null).Distinct().Select(ci => ci.Dataset_ID); + var datasets = _repository.CatalogueRepository.GetAllObjects().Where(d => linkedDatasets.Contains(d.ID)).ToList(); + var datasetString = string.Join("",datasets.Select(ds=> $"{ds.Name} {getDOI(ds)}, {Environment.NewLine}")); SetTableCell(table, tableLine, 1, result.FiltersUsed); SetTableCell(table, tableLine, 2, filename); SetTableCell(table, tableLine, 3, result.RecordsExtracted.ToString("N0")); SetTableCell(table, tableLine, 4, result.DistinctReleaseIdentifiersEncountered.ToString("N0")); + SetTableCell(table, tableLine, 5, datasetString); tableLine++; } } diff --git a/Rdmp.Core/Reports/ExtractionTime/WordDataWriter.cs b/Rdmp.Core/Reports/ExtractionTime/WordDataWriter.cs index 801da15e83..45806e2f09 100644 --- a/Rdmp.Core/Reports/ExtractionTime/WordDataWriter.cs +++ b/Rdmp.Core/Reports/ExtractionTime/WordDataWriter.cs @@ -17,6 +17,7 @@ using Rdmp.Core.DataExport.DataExtraction.Pipeline; using Rdmp.Core.DataExport.DataExtraction.Pipeline.Destinations; using Rdmp.Core.ReusableLibraryCode; +using Rdmp.Core.ReusableLibraryCode.Annotations; using Rdmp.Core.Validation.Constraints; using IFilter = Rdmp.Core.Curation.Data.IFilter; @@ -53,8 +54,16 @@ public WordDataWriter(ExtractionPipelineUseCase executer) private static readonly object OLockOnWordUsage = new(); private readonly IExecuteDatasetExtractionDestination _destination; + + + [NotNull] + private static string GetDoi([NotNull] Curation.Data.Dataset ds) + { + return !string.IsNullOrWhiteSpace(ds.DigitalObjectIdentifier) ? $" (DOI: {ds.DigitalObjectIdentifier})" : ""; + } + /// - /// Generates a new meta data word file in the extraction directory and populates it with information about the extraction. + /// Generates a new metadata word file in the extraction directory and populates it with information about the extraction. /// It returns the open document as an object so that you can supplement it e.g. with catalogue information /// /// @@ -72,6 +81,14 @@ public void GenerateWordFile() var rowCount = _destination.GeneratesFiles ? 10 : 5; + var foundDatasets = Executer.Source.Request.ColumnsToExtract.Select(static col => col.ColumnInfo) + .Where(static ci => ci.Dataset_ID > 0).Select(static ci => ci.Dataset_ID.Value).Distinct().ToList(); + if (foundDatasets.Count > 0) + { + rowCount++; + } + + var t = InsertTable(document, rowCount, 2); var rownum = 0; @@ -144,6 +161,21 @@ public void GenerateWordFile() CreateValidationResultsTable(document); } + if (foundDatasets.Count > 0) + { + var datasets = Executer.Source.Request.Catalogue.Repository.GetAllObjects().ToList(); + + var datasetString = string.Join(", ", + foundDatasets + .Select(ds => datasets.FirstOrDefault(d => d.ID == ds)) + .Where(static d => d != null) + .Select(static fullDataset => $"{fullDataset.Name}{GetDoi(fullDataset)}")); + + SetTableCell(t, rownum, 0, "Datasets Used"); + SetTableCell(t, rownum, 1, datasetString); + rownum++; + } + //if a count of date times seen exists for this extraction create a graph of the counts seen if (Executer.Source.ExtractionTimeTimeCoverageAggregator != null && Executer.Source.ExtractionTimeTimeCoverageAggregator.Buckets.Any()) diff --git a/Rdmp.Core/Repositories/CatalogueRepository.cs b/Rdmp.Core/Repositories/CatalogueRepository.cs index ea7e3eb40d..87941840e9 100644 --- a/Rdmp.Core/Repositories/CatalogueRepository.cs +++ b/Rdmp.Core/Repositories/CatalogueRepository.cs @@ -55,8 +55,6 @@ public class CatalogueRepository : TableRepository, ICatalogueRepository public IEncryptionManager EncryptionManager { get; private set; } - public IPluginManager PluginManager { get; private set; } - /// /// Flag used by Startup processes to determine whether the should be loaded with documentation from the xmldoc files. /// @@ -79,7 +77,6 @@ public CatalogueRepository(DbConnectionStringBuilder catalogueConnectionString) CohortContainerManager = new CohortContainerManager(this); FilterManager = new AggregateFilterManager(this); EncryptionManager = new PasswordEncryptionKeyLocation(this); - PluginManager = new PluginManager(this); CommentStore = new CommentStoreWithKeywords(); @@ -96,7 +93,6 @@ public CatalogueRepository(DbConnectionStringBuilder catalogueConnectionString) Constructors.Add(typeof(StandardRegex), (rep, r) => new StandardRegex((ICatalogueRepository)rep, r)); Constructors.Add(typeof(AnyTableSqlParameter), (rep, r) => new AnyTableSqlParameter((ICatalogueRepository)rep, r)); - Constructors.Add(typeof(Plugin), (rep, r) => new Plugin((ICatalogueRepository)rep, r)); Constructors.Add(typeof(ANOTable), (rep, r) => new ANOTable((ICatalogueRepository)rep, r)); Constructors.Add(typeof(AggregateConfiguration), (rep, r) => new AggregateConfiguration((ICatalogueRepository)rep, r)); @@ -126,7 +122,6 @@ public CatalogueRepository(DbConnectionStringBuilder catalogueConnectionString) Constructors.Add(typeof(LoadMetadata), (rep, r) => new LoadMetadata((ICatalogueRepository)rep, r)); Constructors.Add(typeof(ExtractionFilterParameterSetValue), (rep, r) => new ExtractionFilterParameterSetValue((ICatalogueRepository)rep, r)); - Constructors.Add(typeof(LoadModuleAssembly), (rep, r) => new LoadModuleAssembly((ICatalogueRepository)rep, r)); Constructors.Add(typeof(LoadProgress), (rep, r) => new LoadProgress((ICatalogueRepository)rep, r)); Constructors.Add(typeof(Favourite), (rep, r) => new Favourite((ICatalogueRepository)rep, r)); Constructors.Add(typeof(Pipeline), (rep, r) => new Pipeline((ICatalogueRepository)rep, r)); diff --git a/Rdmp.Core/Repositories/ICatalogueRepository.cs b/Rdmp.Core/Repositories/ICatalogueRepository.cs index 6f32f7182a..c27008e537 100644 --- a/Rdmp.Core/Repositories/ICatalogueRepository.cs +++ b/Rdmp.Core/Repositories/ICatalogueRepository.cs @@ -76,11 +76,6 @@ public interface ICatalogueRepository : IRepository, IServerDefaults /// IFilterManager FilterManager { get; } - /// - /// Manager for identifying current active s - /// - IPluginManager PluginManager { get; } - /// /// Returns a new that audits in the default logging server specified by /// diff --git a/Rdmp.Core/Repositories/MEF.cs b/Rdmp.Core/Repositories/MEF.cs index 00c692bbf6..e174c26e8d 100644 --- a/Rdmp.Core/Repositories/MEF.cs +++ b/Rdmp.Core/Repositories/MEF.cs @@ -10,7 +10,6 @@ using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; -using System.Reflection; using System.Threading; using Rdmp.Core.Curation.Data; using Rdmp.Core.Repositories.Construction; diff --git a/Rdmp.Core/Repositories/Managers/CommentStoreWithKeywords.cs b/Rdmp.Core/Repositories/Managers/CommentStoreWithKeywords.cs index 186235f7cf..fa358f6041 100644 --- a/Rdmp.Core/Repositories/Managers/CommentStoreWithKeywords.cs +++ b/Rdmp.Core/Repositories/Managers/CommentStoreWithKeywords.cs @@ -13,16 +13,16 @@ namespace Rdmp.Core.Repositories.Managers; /// /// Subclass of which also loads KeywordHelp.txt /// -public class CommentStoreWithKeywords : CommentStore +public sealed class CommentStoreWithKeywords : CommentStore { public override void ReadComments(params string[] directoriesToLookInForComments) { base.ReadComments(directoriesToLookInForComments); - var keywords = new FileInfo("./Curation/KeywordHelp.txt"); - - if (keywords.Exists) - AddToHelp(File.ReadAllText(keywords.FullName)); + var assembly=typeof(CommentStoreWithKeywords).Assembly; + using var stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.Curation.KeywordHelp.txt"); + using var reader = new StreamReader(stream ?? throw new ApplicationException("Unable to read KeywordHelp.txt resource")); + AddToHelp(reader.ReadToEnd()); } private void AddToHelp(string keywordHelpFileContents) diff --git a/Rdmp.Core/Repositories/Managers/HighPerformance/FilterManagerFromChildProvider.cs b/Rdmp.Core/Repositories/Managers/HighPerformance/FilterManagerFromChildProvider.cs index 377369a26c..d445e9b1c9 100644 --- a/Rdmp.Core/Repositories/Managers/HighPerformance/FilterManagerFromChildProvider.cs +++ b/Rdmp.Core/Repositories/Managers/HighPerformance/FilterManagerFromChildProvider.cs @@ -53,7 +53,7 @@ public FilterManagerFromChildProvider(CatalogueRepository repository, ICoreChild } r.Close(); } - + public override IContainer[] GetSubContainers(IContainer container) { return _subcontainers.TryGetValue(container.ID, out var result) ? result.ToArray() : diff --git a/Rdmp.Core/Repositories/Managers/PluginManager.cs b/Rdmp.Core/Repositories/Managers/PluginManager.cs deleted file mode 100644 index 34ba692f44..0000000000 --- a/Rdmp.Core/Repositories/Managers/PluginManager.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) The University of Dundee 2018-2019 -// This file is part of the Research Data Management Platform (RDMP). -// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -// RDMP 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 General Public License for more details. -// You should have received a copy of the GNU General Public License along with RDMP. If not, see . - -using System.Linq; -using Rdmp.Core.ReusableLibraryCode.Extensions; - -namespace Rdmp.Core.Repositories.Managers; - -/// -public class PluginManager : IPluginManager -{ - private readonly ICatalogueRepository _repository; - - - public PluginManager(ICatalogueRepository repository) - { - _repository = repository; - } - - /// - /// Returns the latest version of each plugin which is compatible with the running RDMP software version (as determined - /// by the listed ) - /// - /// - public Curation.Data.Plugin[] GetCompatiblePlugins() - { - var runningSoftwareVersion = typeof(PluginManager).Assembly.GetName().Version; - - //nupkg that are compatible with the running software - var plugins = _repository.GetAllObjects() - .Where(a => a.RdmpVersion.IsCompatibleWith(runningSoftwareVersion, 2)); - - //latest versions - var latestVersionsOfPlugins = plugins.GroupBy(static p => p.GetShortName()) - .Select(static grp => grp.MaxBy(static p => p.PluginVersion)); - - return latestVersionsOfPlugins.ToArray(); - } -} \ No newline at end of file diff --git a/Rdmp.Core/Repositories/MemoryCatalogueRepository.cs b/Rdmp.Core/Repositories/MemoryCatalogueRepository.cs index 27adc2ed9a..7330ab171b 100644 --- a/Rdmp.Core/Repositories/MemoryCatalogueRepository.cs +++ b/Rdmp.Core/Repositories/MemoryCatalogueRepository.cs @@ -19,6 +19,7 @@ using Rdmp.Core.MapsDirectlyToDatabaseTable.Versioning; using Rdmp.Core.Providers.Nodes; using Rdmp.Core.Repositories.Managers; +using Rdmp.Core.ReusableLibraryCode.Annotations; using Rdmp.Core.ReusableLibraryCode.Comments; using Rdmp.Core.ReusableLibraryCode.DataAccess; using Rdmp.Core.ReusableLibraryCode.Settings; @@ -42,7 +43,6 @@ public class MemoryCatalogueRepository : MemoryRepository, ICatalogueRepository, public IEncryptionManager EncryptionManager { get; private set; } public IFilterManager FilterManager => this; - public IPluginManager PluginManager { get; private set; } public IJoinManager JoinManager { get; private set; } @@ -73,7 +73,6 @@ public IObscureDependencyFinder ObscureDependencyFinder public MemoryCatalogueRepository(IServerDefaults currentDefaults = null) { JoinManager = new JoinManager(this); - PluginManager = new PluginManager(this); CommentStore = new CommentStoreWithKeywords(); EncryptionManager = new PasswordEncryptionKeyLocation(this); @@ -213,24 +212,24 @@ public virtual void CreateLinkBetween(DataAccessCredentials credentials, ITableI public virtual void BreakLinkBetween(DataAccessCredentials credentials, ITableInfo tableInfo, DataAccessContext context) { - if (!CredentialsDictionary.ContainsKey(tableInfo)) + if (!CredentialsDictionary.TryGetValue(tableInfo, out var credentialsMap)) return; - CredentialsDictionary[tableInfo].Remove(context); + credentialsMap.Remove(context); tableInfo.ClearAllInjections(); } public virtual void BreakAllLinksBetween(DataAccessCredentials credentials, ITableInfo tableInfo) { - if (!CredentialsDictionary.ContainsKey(tableInfo)) + if (!CredentialsDictionary.TryGetValue(tableInfo, out var credentialsMap)) return; - var toRemove = CredentialsDictionary[tableInfo].Where(v => Equals(v.Value, credentials)).Select(k => k.Key) + var toRemove = credentialsMap.Where(v => Equals(v.Value, credentials)).Select(k => k.Key) .ToArray(); foreach (var context in toRemove) - CredentialsDictionary[tableInfo].Remove(context); + credentialsMap.Remove(context); } public DataAccessCredentials GetCredentialsIfExistsFor(ITableInfo tableInfo, DataAccessContext context) @@ -289,31 +288,27 @@ public DataAccessCredentials GetCredentialByUsernameAndPasswordIfExists(string u public ITableInfo[] GetAllForcedJoinsFor(AggregateConfiguration configuration) { - var everyone = Enumerable.Empty(); - - // join with everyone? .... what do you mean everyone? EVERYONE!!!! - if (UserSettings.AlwaysJoinEverything) - everyone = configuration.Catalogue.GetTableInfosIdeallyJustFromMainTables(); + var everyone = + // join with everyone? .... what do you mean everyone? EVERYONE!!!! + UserSettings.AlwaysJoinEverything + ? configuration.Catalogue.GetTableInfosIdeallyJustFromMainTables() + : Enumerable.Empty(); - return !ForcedJoins.ContainsKey(configuration) - ? everyone.ToArray() - : ForcedJoins[configuration].Union(everyone).ToArray(); + return !ForcedJoins.TryGetValue(configuration, out var forced) ? everyone.ToArray() + : forced.Union(everyone).ToArray(); } - public virtual void BreakLinkBetween(AggregateConfiguration configuration, ITableInfo tableInfo) + public virtual void BreakLinkBetween([NotNull] AggregateConfiguration configuration, ITableInfo tableInfo) { - if (!ForcedJoins.ContainsKey(configuration)) - return; - - ForcedJoins[configuration].Remove(tableInfo); + if (ForcedJoins.TryGetValue(configuration, out var value)) value.Remove(tableInfo); } - public virtual void CreateLinkBetween(AggregateConfiguration configuration, ITableInfo tableInfo) + public virtual void CreateLinkBetween([NotNull] AggregateConfiguration configuration, ITableInfo tableInfo) { - if (!ForcedJoins.ContainsKey(configuration)) - ForcedJoins.Add(configuration, new HashSet()); + if (!ForcedJoins.TryGetValue(configuration,out var forced)) + ForcedJoins.Add(configuration, forced=new HashSet()); - ForcedJoins[configuration].Add(tableInfo); + forced.Add(tableInfo); } #endregion @@ -369,15 +364,15 @@ public CohortContainerContent(IOrderable orderable, int order) public IOrderable[] GetChildren(CohortAggregateContainer parent) { - return !CohortContainerContents.ContainsKey(parent) - ? Array.Empty() - : CohortContainerContents[parent].OrderBy(o => o.Order).Select(o => o.Orderable).ToArray(); + return !CohortContainerContents.TryGetValue(parent, out var cohortContainerContents) ? + Array.Empty() + : cohortContainerContents.OrderBy(static o => o.Order).Select(static o => o.Orderable).ToArray(); } public CohortAggregateContainer GetParent(CohortAggregateContainer child) { var match = CohortContainerContents.Where(k => k.Value.Any(hs => Equals(hs.Orderable, child))) - .Select(kvp => kvp.Key).ToArray(); + .Select(static kvp => kvp.Key).ToArray(); return match.Length > 0 ? match.Single() : null; } @@ -413,21 +408,22 @@ public virtual void Add(CohortAggregateContainer parent, CohortAggregateContaine protected Dictionary> WhereSubContainers { get; set; } = new(); - public IContainer[] GetSubContainers(IContainer container) => !WhereSubContainers.ContainsKey(container) - ? Array.Empty() - : WhereSubContainers[container].ToArray(); + [NotNull] + public IContainer[] GetSubContainers(IContainer container) => + !WhereSubContainers.TryGetValue(container, out var containers) + ? Array.Empty() + : containers.ToArray(); public virtual void MakeIntoAnOrphan(IContainer container) { foreach (var contents in WhereSubContainers) - if (contents.Value.Contains(container)) - contents.Value.Remove(container); + contents.Value.Remove(container); } + [CanBeNull] public IContainer GetParentContainerIfAny(IContainer container) { - var match = WhereSubContainers.Where(k => k.Value.Contains(container)).ToArray(); - return match.Length != 0 ? match[0].Key : null; + return WhereSubContainers.FirstOrDefault(k => k.Value.Contains(container)).Key; } public IFilter[] GetFilters(IContainer container) @@ -474,13 +470,13 @@ public virtual void Link(GovernancePeriod governancePeriod, ICatalogue catalogue public Dictionary> GetAllGovernedCataloguesForAllGovernancePeriods() { - return GovernanceCoverage.ToDictionary(k => k.Key.ID, v => new HashSet(v.Value.Select(c => c.ID))); + return GovernanceCoverage.ToDictionary(static k => k.Key.ID, + static v => new HashSet(v.Value.Select(static c => c.ID))); } public IEnumerable GetAllGovernedCatalogues(GovernancePeriod governancePeriod) => - !GovernanceCoverage.ContainsKey(governancePeriod) - ? Enumerable.Empty() - : GovernanceCoverage[governancePeriod]; + !GovernanceCoverage.TryGetValue(governancePeriod, out var governedCatalogues) ? Enumerable.Empty() + : governedCatalogues; #endregion diff --git a/Rdmp.Core/Repositories/YamlRepository.cs b/Rdmp.Core/Repositories/YamlRepository.cs index 00f2d29a79..faab988a06 100644 --- a/Rdmp.Core/Repositories/YamlRepository.cs +++ b/Rdmp.Core/Repositories/YamlRepository.cs @@ -167,15 +167,6 @@ protected virtual void SetRepositoryOnObject(IMapsDirectlyToDatabaseTable obj) case ConcreteContainer container: container.SetManager(this); break; - case LoadModuleAssembly lma: - lock (lockFs) - { - var file = GetNupkgPath(lma); - - if (File.Exists(file)) - lma.Bin = File.ReadAllBytes(file); - break; - } } } @@ -190,24 +181,12 @@ public override void InsertAndHydrate(T toCreate, Dictionary } } - private string GetNupkgPath(LoadModuleAssembly lma) - { - //somedir/LoadModuleAssembly/ - var path = Path.GetDirectoryName(GetPath(lma)); - - //somedir/LoadModuleAssembly/MyPlugin1.0.0.nupkg - return Path.Combine(path, GetObjectByID(lma.Plugin_ID).Name); - } - public override void DeleteFromDatabase(IMapsDirectlyToDatabaseTable oTableWrapperObject) { lock (lockFs) { base.DeleteFromDatabase(oTableWrapperObject); File.Delete(GetPath(oTableWrapperObject)); - - // if deleting a LoadModuleAssembly also delete its binary content file (the plugin dlls in nupkg) - if (oTableWrapperObject is LoadModuleAssembly lma) File.Delete(GetNupkgPath(lma)); } } @@ -222,12 +201,6 @@ public override void SaveToDatabase(IMapsDirectlyToDatabaseTable o) lock (lockFs) { File.WriteAllText(GetPath(o), yaml); - - // Do not write plugin binary content into yaml that results in - // a massive blob of binary yaml (not useful and slow to load) - if (o is LoadModuleAssembly lma) - // write the nupkg as a binary file instead to the same folder - File.WriteAllBytes(GetNupkgPath(lma), lma.Bin); } } diff --git a/Rdmp.Core/ReusableLibraryCode/Checks/CheckEventArgs.cs b/Rdmp.Core/ReusableLibraryCode/Checks/CheckEventArgs.cs index 11755f169f..d5f942988e 100644 --- a/Rdmp.Core/ReusableLibraryCode/Checks/CheckEventArgs.cs +++ b/Rdmp.Core/ReusableLibraryCode/Checks/CheckEventArgs.cs @@ -12,17 +12,17 @@ namespace Rdmp.Core.ReusableLibraryCode.Checks; /// /// Created when an ICheckable performs a check to indicate whether the check passed or not and whether there is an Exception or ProposedFix. ProposedFix -/// is a string that suggests how a problem can be resolved but where the resolution might be undesireable under certain circumstances (hence the choice). +/// is a string that suggests how a problem can be resolved but where the resolution might be undesirable under certain circumstances (hence the choice). /// /// The workflow is: /// 1. ICheckable has its Check method called with an ICheckNotifier /// 2. Check logic performed /// 3. CheckEventArgs created and ICheckNotifier.OnCheckPerformed called /// 4. ICheckNotifier decides how to respond to the message (which can include throwing an Exception - which you should not catch/suppress). -/// 5. If OnCheckPerformed compeltes without Exception evaluate the bool return if there was a ProposedFix and apply the fix if it is true +/// 5. If OnCheckPerformed completes without Exception evaluate the bool return if there was a ProposedFix and apply the fix if it is true /// /// -public partial class CheckEventArgs : IHasSummary +public sealed class CheckEventArgs : IHasSummary { public string Message { get; set; } public CheckResult Result { get; set; } diff --git a/Rdmp.Core/ReusableLibraryCode/Serialization/IgnorableSerializerContractResolver.cs b/Rdmp.Core/ReusableLibraryCode/Serialization/IgnorableSerializerContractResolver.cs index 2d845014f0..c9bbb06396 100644 --- a/Rdmp.Core/ReusableLibraryCode/Serialization/IgnorableSerializerContractResolver.cs +++ b/Rdmp.Core/ReusableLibraryCode/Serialization/IgnorableSerializerContractResolver.cs @@ -43,12 +43,11 @@ public void Ignore(Type type, params string[] propertyName) /// /// /// - public bool IsIgnored(Type type, string propertyName) + private bool IsIgnored(Type type, string propertyName) { - if (!Ignores.ContainsKey(type)) return false; - - // if no properties provided, ignore the type entirely - return Ignores[type].Count == 0 || Ignores[type].Contains(propertyName); + return Ignores.TryGetValue(type, out var ignore) && ( + // if no properties provided, ignore the type entirely + ignore.Count == 0 || ignore.Contains(propertyName)); } /// diff --git a/Rdmp.Core/Sharing/Dependency/Gathering/Gatherer.cs b/Rdmp.Core/Sharing/Dependency/Gathering/Gatherer.cs index c9c545aec3..def4de25cd 100644 --- a/Rdmp.Core/Sharing/Dependency/Gathering/Gatherer.cs +++ b/Rdmp.Core/Sharing/Dependency/Gathering/Gatherer.cs @@ -33,7 +33,6 @@ public Gatherer(IRDMPPlatformRepositoryServiceLocator repositoryLocator) _functions.Add(typeof(Catalogue), o => GatherDependencies((Catalogue)o)); _functions.Add(typeof(ColumnInfo), o => GatherDependencies((ColumnInfo)o)); _functions.Add(typeof(ANOTable), o => GatherDependencies((ANOTable)o)); - _functions.Add(typeof(Plugin), o => GatherDependencies((Plugin)o)); _functions.Add(typeof(LoadMetadata), o => GatherDependencies((LoadMetadata)o)); @@ -68,16 +67,6 @@ public static GatheredObject GatherDependencies(ANOTable anoTable) return root; } - public static GatheredObject GatherDependencies(Plugin plugin) - { - var root = new GatheredObject(plugin); - - foreach (var lma in plugin.LoadModuleAssemblies) - root.Children.Add(new GatheredObject(lma)); - - return root; - } - public GatheredObject GatherDependencies(LoadMetadata loadMetadata) { //Share the LoadMetadata diff --git a/Rdmp.Core/Startup/Startup.cs b/Rdmp.Core/Startup/Startup.cs index 75668fb1d4..8f51ab4cb7 100644 --- a/Rdmp.Core/Startup/Startup.cs +++ b/Rdmp.Core/Startup/Startup.cs @@ -194,7 +194,7 @@ private bool Find(IRepository repository, IPatcher patcher, ICheckNotifier notif ? RDMPPlatformDatabaseStatus.Healthy : RDMPPlatformDatabaseStatus.RequiresPatching, Patch.PatchingState.SoftwareBehindDatabase => RDMPPlatformDatabaseStatus.SoftwareOutOfDate, - _ => throw new ArgumentOutOfRangeException(nameof(patchingRequired)) + _ => throw new InvalidOperationException(nameof(patchingRequired)) })); } catch (Exception e) @@ -241,11 +241,7 @@ private void FindWithPatcher(IPatcher patcher, ICheckNotifier notifier) /// private static void LoadMEF(ICatalogueRepository catalogueRepository, ICheckNotifier notifier) { - /*foreach (var (name, body) in catalogueRepository.PluginManager.GetCompatiblePlugins() - .SelectMany(static p => p.LoadModuleAssemblies).SelectMany(static a => a.GetContents()))*/ - // Ignore tiny nupkg files from old 'unit test' foreach (var (name, body) in Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory, "*.nupkg") - .Where(path => new FileInfo(path).Length > 100).Select(File.OpenRead) .SelectMany(LoadModuleAssembly.GetContents)) try { diff --git a/Rdmp.UI.Tests/AggregateEditorUITests.cs b/Rdmp.UI.Tests/AggregateEditorUITests.cs index e3f8898bf1..489a511c96 100644 --- a/Rdmp.UI.Tests/AggregateEditorUITests.cs +++ b/Rdmp.UI.Tests/AggregateEditorUITests.cs @@ -27,17 +27,19 @@ public void Test_AggregateEditorUI_NormalState() //should show two available columns var available = colsUi.AvailableColumns; - Assert.AreEqual(2, available.Count); + Assert.That(available, Has.Count.EqualTo(2)); //the count(*) column var included = colsUi.IncludedColumns; - Assert.AreEqual(1, included.Count); + Assert.That(included, Has.Count.EqualTo(1)); //before we have added any columns it should not be possible to launch the graph var cmdExecuteGraph = new ExecuteCommandExecuteAggregateGraph(ItemActivator, config); - Assert.IsTrue(cmdExecuteGraph.IsImpossible); - StringAssert.Contains("No tables could be identified for the query. Try adding a column or a force join", - cmdExecuteGraph.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmdExecuteGraph.IsImpossible); + Assert.That(cmdExecuteGraph.ReasonCommandImpossible, Does.Contain("No tables could be identified for the query. Try adding a column or a force join")); + }); var ei = config.Catalogue.CatalogueItems[0].ExtractionInformation; @@ -49,15 +51,15 @@ public void Test_AggregateEditorUI_NormalState() //should show one available columns available = colsUi.AvailableColumns; - Assert.AreEqual(1, available.Count); + Assert.That(available, Has.Count.EqualTo(1)); //the count(*) column and the added dimension included = colsUi.IncludedColumns; - Assert.AreEqual(2, included.Count); + Assert.That(included, Has.Count.EqualTo(2)); //should now be possible to launch the graph cmdExecuteGraph = new ExecuteCommandExecuteAggregateGraph(ItemActivator, config); - Assert.IsFalse(cmdExecuteGraph.IsImpossible); + Assert.That(cmdExecuteGraph.IsImpossible, Is.False); AssertNoErrors(ExpectedErrorType.Any); } @@ -75,12 +77,15 @@ public void Test_AggregateEditorUI_AxisOnlyShowsDateDimensions() var ui = AndLaunch(config); //only date should be an option for axis dimension - Assert.AreEqual(1, ui.ddAxisDimension.Items.Count); - Assert.AreEqual(dimDate, ui.ddAxisDimension.Items[0]); + Assert.That(ui.ddAxisDimension.Items, Has.Count.EqualTo(1)); + Assert.Multiple(() => + { + Assert.That(ui.ddAxisDimension.Items[0], Is.EqualTo(dimDate)); - //dates are not valid for pivots - Assert.AreEqual(1, ui.ddPivotDimension.Items.Count); - Assert.AreEqual(dimOther, ui.ddPivotDimension.Items[0]); + //dates are not valid for pivots + Assert.That(ui.ddPivotDimension.Items, Has.Count.EqualTo(1)); + }); + Assert.That(ui.ddPivotDimension.Items[0], Is.EqualTo(dimOther)); //it wants us to pick either a pivot or an axis AssertErrorWasShown(ExpectedErrorType.FailedCheck, @@ -103,16 +108,22 @@ public void Test_AggregateEditorUI_NoExtractableColumns() //these commands should be impossible var cmd = new ExecuteCommandAddNewAggregateGraph(ItemActivator, cata); - Assert.IsTrue(cmd.IsImpossible); - StringAssert.Contains("no extractable columns", cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Does.Contain("no extractable columns")); + }); //and if the broken config is activated var ui = AndLaunch(config); //it should not launch and instead show the following message var killed = ItemActivator.Results.KilledForms.Single(); - Assert.AreEqual(ui.ParentForm, killed.Key); - StringAssert.Contains("no extractable columns", killed.Value.Message); + Assert.Multiple(() => + { + Assert.That(killed.Key, Is.EqualTo(ui.ParentForm)); + Assert.That(killed.Value.Message, Does.Contain("no extractable columns")); + }); } diff --git a/Rdmp.UI.Tests/ArbitraryFolderNodeTests.cs b/Rdmp.UI.Tests/ArbitraryFolderNodeTests.cs index aa4fed8f99..703f166c11 100644 --- a/Rdmp.UI.Tests/ArbitraryFolderNodeTests.cs +++ b/Rdmp.UI.Tests/ArbitraryFolderNodeTests.cs @@ -28,10 +28,10 @@ public void Test_ArbitraryFolderNode_CommandGetter_Throwing() var node = new ArbitraryFolderNode("my node", 0); var menu1 = common.GetMenuIfExists(node); - Assert.IsNotNull(menu1); + Assert.That(menu1, Is.Not.Null); var count1 = menu1.Items.Count; //some you get for free e.g. Expand/Collapse - Assert.GreaterOrEqual(count1, 2); + Assert.That(count1, Is.GreaterThanOrEqualTo(2)); //set the menu to have one command in it node.CommandGetter = () => new IAtomicCommand[] { new ImpossibleCommand("Do Nothing") }; @@ -42,7 +42,7 @@ public void Test_ArbitraryFolderNode_CommandGetter_Throwing() // expect 2 new entries in the context menu. The "Do Nothing" command added above // and a tool strip seperator to divide the menu commands from the common commands - Assert.AreEqual(count1 + 2, count2); + Assert.That(count2, Is.EqualTo(count1 + 2)); //what happens if the delegate crashes? node.CommandGetter = () => throw new NotSupportedException("It went wrong!"); diff --git a/Rdmp.UI.Tests/CatalogueIconProviderTests.cs b/Rdmp.UI.Tests/CatalogueIconProviderTests.cs index c07f8415ec..d6c99055e1 100644 --- a/Rdmp.UI.Tests/CatalogueIconProviderTests.cs +++ b/Rdmp.UI.Tests/CatalogueIconProviderTests.cs @@ -26,7 +26,7 @@ public void CatalogueIconProvider_HasImage_NoImage() var img = provider.GetImage(new object(), OverlayKind.None); - Assert.IsFalse(provider.HasIcon(new object())); + Assert.That(provider.HasIcon(new object()), Is.False); } [Test] @@ -43,15 +43,15 @@ public void CatalogueIconProvider_HasImage_AllObjectsHave() { d.IsDisabled = true; - Assert.IsTrue(IsBlackAndWhite(provider.GetImage(obj, OverlayKind.Add)), + Assert.That(IsBlackAndWhite(provider.GetImage(obj, OverlayKind.Add)), $"Grayscaling failed for Object of Type '{obj.GetType().Name}' did not have an image"); d.IsDisabled = false; - Assert.IsFalse(IsBlackAndWhite(provider.GetImage(obj, OverlayKind.Add)), + Assert.That(IsBlackAndWhite(provider.GetImage(obj, OverlayKind.Add)), Is.False, $"Enabled Object of Type '{obj.GetType().Name}' was unexpectedly Grayscale"); } - Assert.IsTrue(provider.HasIcon(obj), $"Object of Type '{obj.GetType().Name}' did not have an image"); + Assert.That(provider.HasIcon(obj), $"Object of Type '{obj.GetType().Name}' did not have an image"); objectCount++; } @@ -66,10 +66,10 @@ public void TestGrayscale() var ac = WhenIHaveA(); - Assert.IsFalse(IsBlackAndWhite(provider.GetImage(ac)), "Image was unexpectedly Grayscale"); + Assert.That(IsBlackAndWhite(provider.GetImage(ac)), Is.False, "Image was unexpectedly Grayscale"); ac.IsDisabled = true; - Assert.IsTrue(IsBlackAndWhite(provider.GetImage(ac)), "Image was expected to be Grayscale but wasn't'"); + Assert.That(IsBlackAndWhite(provider.GetImage(ac)), "Image was expected to be Grayscale but wasn't'"); } @@ -84,7 +84,7 @@ public void Test_ObjectMasqueradingAsSelf() var provider = new CatalogueIconProvider(RepositoryLocator, null); provider.GetImage(me, OverlayKind.Add); - Assert.IsFalse(provider.HasIcon(me)); + Assert.That(provider.HasIcon(me), Is.False); } private class IAmMe : IMasqueradeAs diff --git a/Rdmp.UI.Tests/CatalogueItemUITests.cs b/Rdmp.UI.Tests/CatalogueItemUITests.cs index 6ef98d63b6..b84c0cf658 100644 --- a/Rdmp.UI.Tests/CatalogueItemUITests.cs +++ b/Rdmp.UI.Tests/CatalogueItemUITests.cs @@ -35,13 +35,15 @@ public void Test_CatalogueItemUI_NormalState() var saver = ui.GetObjectSaverButton(); saver.Save(); - //the new description shuold be set in my class - Assert.AreEqual("what is in the column", catalogueItem.Description); + Assert.Multiple(() => + { + //the new description shuold be set in my class + Assert.That(catalogueItem.Description, Is.EqualTo("what is in the column")); - //and the UI should have shown the Propagate changes dialog - Assert.AreEqual(1, ItemActivator.Results.WindowsShown.Count); - Assert.IsInstanceOf(typeof(PropagateCatalogueItemChangesToSimilarNamedUI), - ItemActivator.Results.WindowsShown.Single()); + //and the UI should have shown the Propagate changes dialog + Assert.That(ItemActivator.Results.WindowsShown, Has.Count.EqualTo(1)); + }); + Assert.That(ItemActivator.Results.WindowsShown.Single(), Is.InstanceOf(typeof(PropagateCatalogueItemChangesToSimilarNamedUI))); AssertNoErrors(ExpectedErrorType.Any); } @@ -57,7 +59,7 @@ public void Test_CatalogueItemUI_GetTabName() var ci = WhenIHaveA(); var ui = AndLaunch(ci); - Assert.AreEqual("MyCataItem (Mycata)", ui.GetTabName()); + Assert.That(ui.GetTabName(), Is.EqualTo("MyCataItem (Mycata)")); //introduce database change but don't save ci.Name = "Fish"; @@ -76,7 +78,7 @@ public void Test_CatalogueItemUI_GetTabName() //and finish launching it, this should trigger the 'FreshCopyDelegate' which will exercise GetTabName. ui.SetDatabaseObject(ItemActivator, ci); - Assert.AreEqual("MyCataItem (Mycata)", ui.GetTabName()); + Assert.That(ui.GetTabName(), Is.EqualTo("MyCataItem (Mycata)")); //clear the delgate for the next user ItemActivator.ShouldReloadFreshCopyDelegate = null; diff --git a/Rdmp.UI.Tests/CatalogueUITests.cs b/Rdmp.UI.Tests/CatalogueUITests.cs index 73bf572892..aba095465a 100644 --- a/Rdmp.UI.Tests/CatalogueUITests.cs +++ b/Rdmp.UI.Tests/CatalogueUITests.cs @@ -23,44 +23,62 @@ public void Test_CatalogueUI_NormalState() var ui = AndLaunch(cata); //there no unsaved changes - Assert.AreEqual(ChangeDescription.NoChanges, cata.HasLocalChanges().Evaluation); + Assert.That(cata.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.NoChanges)); //but when I type text ui._scintillaDescription.Text = "amagad zombies"; - //my class should get the typed text but it shouldn't be saved into the database yet - Assert.AreEqual("amagad zombies", cata.Description); - Assert.AreEqual(ChangeDescription.DatabaseCopyDifferent, cata.HasLocalChanges().Evaluation); + Assert.Multiple(() => + { + //my class should get the typed text but it shouldn't be saved into the database yet + Assert.That(cata.Description, Is.EqualTo("amagad zombies")); + Assert.That(cata.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.DatabaseCopyDifferent)); + }); //when I press undo var saver = ui.GetObjectSaverButton(); saver.Undo(); - //it should set the text editor back to blank - Assert.AreEqual("", ui._scintillaDescription.Text); - //and clear my class property - Assert.AreEqual(null, cata.Description); + Assert.Multiple(() => + { + //it should set the text editor back to blank + Assert.That(ui._scintillaDescription.Text, Is.EqualTo("")); + //and clear my class property + Assert.That(cata.Description, Is.EqualTo(null)); + }); //redo should update both the local class and text box saver.Redo(); - Assert.AreEqual("amagad zombies", ui._scintillaDescription.Text); - Assert.AreEqual("amagad zombies", cata.Description); + Assert.Multiple(() => + { + Assert.That(ui._scintillaDescription.Text, Is.EqualTo("amagad zombies")); + Assert.That(cata.Description, Is.EqualTo("amagad zombies")); + }); //undo a redo should still be valid saver.Undo(); - Assert.AreEqual("", ui._scintillaDescription.Text); - Assert.AreEqual(null, cata.Description); + Assert.Multiple(() => + { + Assert.That(ui._scintillaDescription.Text, Is.EqualTo("")); + Assert.That(cata.Description, Is.EqualTo(null)); + }); saver.Redo(); - Assert.AreEqual("amagad zombies", ui._scintillaDescription.Text); - Assert.AreEqual("amagad zombies", cata.Description); + Assert.Multiple(() => + { + Assert.That(ui._scintillaDescription.Text, Is.EqualTo("amagad zombies")); + Assert.That(cata.Description, Is.EqualTo("amagad zombies")); + }); //when I save saver.Save(); - //my class should have no changes (vs the database) and should have the proper description - Assert.AreEqual(ChangeDescription.NoChanges, cata.HasLocalChanges().Evaluation); - Assert.AreEqual("amagad zombies", cata.Description); + Assert.Multiple(() => + { + //my class should have no changes (vs the database) and should have the proper description + Assert.That(cata.HasLocalChanges().Evaluation, Is.EqualTo(ChangeDescription.NoChanges)); + Assert.That(cata.Description, Is.EqualTo("amagad zombies")); + }); AssertNoErrors(ExpectedErrorType.Any); diff --git a/Rdmp.UI.Tests/ChildProviderTests.cs b/Rdmp.UI.Tests/ChildProviderTests.cs index d99a3e6925..e35e533058 100644 --- a/Rdmp.UI.Tests/ChildProviderTests.cs +++ b/Rdmp.UI.Tests/ChildProviderTests.cs @@ -29,11 +29,11 @@ public void ChildProviderGiven_TableInfoWith_NullServer() var provider = new CatalogueChildProvider(Repository.CatalogueRepository, null, ThrowImmediatelyCheckNotifier.Quiet, null); var desc = provider.GetDescendancyListIfAnyFor(ti); - Assert.IsNotNull(desc); + Assert.That(desc, Is.Not.Null); //instead we should get a parent node with the name "Null Server" var parent = (TableInfoServerNode)desc.Parents[^2]; - Assert.AreEqual(TableInfoServerNode.NullServerNode, parent.ServerName); + Assert.That(parent.ServerName, Is.EqualTo(TableInfoServerNode.NullServerNode)); } [Test] @@ -47,11 +47,11 @@ public void ChildProviderGiven_TableInfoWith_NullDatabase() var provider = new CatalogueChildProvider(Repository.CatalogueRepository, null, ThrowImmediatelyCheckNotifier.Quiet, null); var desc = provider.GetDescendancyListIfAnyFor(ti); - Assert.IsNotNull(desc); + Assert.That(desc, Is.Not.Null); //instead we should get a parent node with the name "Null Server" var parent = (TableInfoDatabaseNode)desc.Parents[^1]; - Assert.AreEqual(TableInfoDatabaseNode.NullDatabaseNode, parent.DatabaseName); + Assert.That(parent.DatabaseName, Is.EqualTo(TableInfoDatabaseNode.NullDatabaseNode)); } [Test] @@ -79,7 +79,7 @@ public void TestUpTo() if (val1 is Array a1 && val2 is Array a2 && a1.Length == 0 && a2.Length == 0) continue; - Assert.AreNotSame(val1, val2, $"Prop {prop} was unexpectedly the same between child providers"); + Assert.That(val2, Is.Not.SameAs(val1), $"Prop {prop} was unexpectedly the same between child providers"); } @@ -92,7 +92,7 @@ public void TestUpTo() if (val1 is Array a1 && val2 is Array a2 && a1.Length == 0 && a2.Length == 0) continue; - Assert.AreNotSame(val1, val2, $"Field {field} was unexpectedly the same between child providers"); + Assert.That(val2, Is.Not.SameAs(val1), $"Field {field} was unexpectedly the same between child providers"); } @@ -104,7 +104,7 @@ public void TestUpTo() foreach (var prop in typeof(DataExportChildProvider).GetProperties().Where(p => !skip.Contains(p.Name))) try { - Assert.AreSame(prop.GetValue(cp1), prop.GetValue(cp2), + Assert.That(prop.GetValue(cp2), Is.SameAs(prop.GetValue(cp1)), $"Prop {prop} was not the same between child providers - after UpdateTo"); } catch (Exception) @@ -112,14 +112,14 @@ public void TestUpTo() badProps.Add(prop.Name); } - Assert.IsEmpty(badProps); + Assert.That(badProps, Is.Empty); var badFields = new List(); foreach (var field in typeof(DataExportChildProvider).GetFields(bindFlags).Where(p => !skip.Contains(p.Name))) try { - Assert.AreSame(field.GetValue(cp1), field.GetValue(cp2), + Assert.That(field.GetValue(cp2), Is.SameAs(field.GetValue(cp1)), $"Field {field} was not the same between child providers - after UpdateTo"); } catch (Exception) @@ -127,7 +127,7 @@ public void TestUpTo() badFields.Add(field.Name); } - Assert.IsEmpty(badFields); + Assert.That(badFields, Is.Empty); } [Test] @@ -145,7 +145,7 @@ public void TestDuplicateTableInfos_Identical() var p2 = cp.GetDescendancyListIfAnyFor(t2).Parents; // both objects should have identical path - Assert.IsTrue(p1.SequenceEqual(p2)); + Assert.That(p2, Is.EqualTo(p1)); } [Test] @@ -165,23 +165,29 @@ public void TestDuplicateTableInfos_DifferentServers() var p1 = cp.GetDescendancyListIfAnyFor(t1).Parents; var p2 = cp.GetDescendancyListIfAnyFor(t2).Parents; - // both objects should have identical path - Assert.IsFalse(p1.SequenceEqual(p2)); + Assert.Multiple(() => + { + // both objects should have identical path + Assert.That(p1.SequenceEqual(p2), Is.False); - Assert.AreEqual(p1[0], p2[0]); // Data Repository Servers + Assert.That(p2[0], Is.EqualTo(p1[0])); // Data Repository Servers - Assert.IsInstanceOf(p1[1]); - Assert.IsInstanceOf(p2[1]); - Assert.AreNotEqual(p1[1], p2[1]); // Server (e.g. localhost/127.0.0.1) + Assert.That(p1[1], Is.InstanceOf()); + Assert.That(p2[1], Is.InstanceOf()); + }); + Assert.Multiple(() => + { + Assert.That(p2[1], Is.Not.EqualTo(p1[1])); // Server (e.g. localhost/127.0.0.1) - Assert.IsInstanceOf(p1[2]); - Assert.IsInstanceOf(p2[2]); - Assert.AreNotEqual(p1[2], p2[2]); // Database (must not be equal because the server is different!) + Assert.That(p1[2], Is.InstanceOf()); + Assert.That(p2[2], Is.InstanceOf()); + }); + Assert.That(p2[2], Is.Not.EqualTo(p1[2])); // Database (must not be equal because the server is different!) } /// - /// If two TableInfo differ by DatabaseType then they should have seperate hierarchies. + /// If two TableInfo differ by DatabaseType then they should have separate hierarchies. /// [Test] public void TestDuplicateTableInfos_DifferentServers_DatabaseTypeOnly() @@ -200,19 +206,25 @@ public void TestDuplicateTableInfos_DifferentServers_DatabaseTypeOnly() var p1 = cp.GetDescendancyListIfAnyFor(t1).Parents; var p2 = cp.GetDescendancyListIfAnyFor(t2).Parents; - // both objects should have identical path - Assert.IsFalse(p1.SequenceEqual(p2)); + Assert.Multiple(() => + { + // both objects should have identical path + Assert.That(p1.SequenceEqual(p2), Is.False); - Assert.AreEqual(p1[0], p2[0]); // Data Repository Servers + Assert.That(p2[0], Is.EqualTo(p1[0])); // Data Repository Servers - Assert.IsInstanceOf(p1[1]); - Assert.IsInstanceOf(p2[1]); - Assert.AreNotEqual(p1[1], p2[1]); // Server (must not be equal because DatabaseType differs) + Assert.That(p1[1], Is.InstanceOf()); + Assert.That(p2[1], Is.InstanceOf()); + }); + Assert.Multiple(() => + { + Assert.That(p2[1], Is.Not.EqualTo(p1[1])); // Server (must not be equal because DatabaseType differs) - Assert.IsInstanceOf(p1[2]); - Assert.IsInstanceOf(p2[2]); - Assert.AreNotEqual(p1[2], p2[2]); // Database (must not be equal because the server is different!) + Assert.That(p1[2], Is.InstanceOf()); + Assert.That(p2[2], Is.InstanceOf()); + }); + Assert.That(p2[2], Is.Not.EqualTo(p1[2])); // Database (must not be equal because the server is different!) } [Test] @@ -232,19 +244,25 @@ public void TestDuplicateTableInfos_DifferentDatabases() var p1 = cp.GetDescendancyListIfAnyFor(t1).Parents; var p2 = cp.GetDescendancyListIfAnyFor(t2).Parents; - // both objects should have identical path - Assert.IsFalse(p1.SequenceEqual(p2)); + Assert.Multiple(() => + { + // both objects should have identical path + Assert.That(p1.SequenceEqual(p2), Is.False); - Assert.AreEqual(p1[0], p2[0]); // Data Repository Servers + Assert.That(p2[0], Is.EqualTo(p1[0])); // Data Repository Servers - Assert.IsInstanceOf(p1[1]); - Assert.IsInstanceOf(p2[1]); - Assert.AreEqual(p1[1], p2[1]); // Server + Assert.That(p1[1], Is.InstanceOf()); + Assert.That(p2[1], Is.InstanceOf()); + }); + Assert.Multiple(() => + { + Assert.That(p2[1], Is.EqualTo(p1[1])); // Server - Assert.IsInstanceOf(p1[2]); - Assert.IsInstanceOf(p2[2]); - Assert.AreNotEqual(p1[2], p2[2]); // Database (i.e. Frank/Biff) + Assert.That(p1[2], Is.InstanceOf()); + Assert.That(p2[2], Is.InstanceOf()); + }); + Assert.That(p2[2], Is.Not.EqualTo(p1[2])); // Database (i.e. Frank/Biff) } /// @@ -270,7 +288,7 @@ public void TestDuplicateTableInfos_DifferentServers_CapsOnly() var p2 = cp.GetDescendancyListIfAnyFor(t2).Parents; // both objects should have identical path - Assert.IsTrue(p1.SequenceEqual(p2)); + Assert.That(p2, Is.EqualTo(p1)); } /// @@ -296,6 +314,6 @@ public void TestDuplicateTableInfos_DifferentDatabases_CapsOnly() var p2 = cp.GetDescendancyListIfAnyFor(t2).Parents; // both objects should have identical path - Assert.IsTrue(p1.SequenceEqual(p2)); + Assert.That(p2, Is.EqualTo(p1)); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/CohortBuilding/CohortIdentificationConfigurationUnitTests.cs b/Rdmp.UI.Tests/CohortBuilding/CohortIdentificationConfigurationUnitTests.cs index 9c07505f60..832882300f 100644 --- a/Rdmp.UI.Tests/CohortBuilding/CohortIdentificationConfigurationUnitTests.cs +++ b/Rdmp.UI.Tests/CohortBuilding/CohortIdentificationConfigurationUnitTests.cs @@ -51,7 +51,7 @@ public void Test_AggregateConfigurationOrder_TwoAggregates() cmd.Execute(); var ac1 = (AggregateConfiguration)cic.RootCohortAggregateContainer.GetOrderedContents().First(); - Assert.AreEqual(0, ac1.Order); + Assert.That(ac1.Order, Is.EqualTo(0)); //add another one var cmd2 = new ExecuteCommandAddCatalogueToCohortIdentificationSetContainer(ItemActivator, @@ -64,11 +64,14 @@ public void Test_AggregateConfigurationOrder_TwoAggregates() ac1 = (AggregateConfiguration)all[0]; var ac2 = (AggregateConfiguration)all[1]; - Assert.AreEqual(0, ac1.Order); - Assert.AreEqual(1, ac2.Order); + Assert.Multiple(() => + { + Assert.That(ac1.Order, Is.EqualTo(0)); + Assert.That(ac2.Order, Is.EqualTo(1)); - Assert.AreEqual(2, Repository.GetAllObjects().Length, - "Expected you to create 2 AggregateConfiguration only"); + Assert.That(Repository.GetAllObjects(), Has.Length.EqualTo(2), + "Expected you to create 2 AggregateConfiguration only"); + }); } @@ -106,9 +109,12 @@ public void Test_AggregateConfigurationOrder_MovingAggregatesBetweenContainers() var ac2 = (AggregateConfiguration)subcontainer.GetOrderedContents().Single(); var intersect = (CohortAggregateContainer)all[0]; - Assert.AreEqual(0, intersect.Order); - Assert.AreEqual(1, ac1.Order); - Assert.AreEqual(0, ac2.Order); + Assert.Multiple(() => + { + Assert.That(intersect.Order, Is.EqualTo(0)); + Assert.That(ac1.Order, Is.EqualTo(1)); + Assert.That(ac2.Order, Is.EqualTo(0)); + }); //now move the Ac2 to Root (problematic since both Ac 2 and the INTERSECT have Order 0 - in their own separate containers) var cmd3 = new ExecuteCommandMoveAggregateIntoContainer(ItemActivator, @@ -127,9 +133,12 @@ public void Test_AggregateConfigurationOrder_MovingAggregatesBetweenContainers() intersect = (CohortAggregateContainer)all[1]; ac1 = (AggregateConfiguration)all[2]; - Assert.AreEqual(0, ac2.Order); - Assert.AreEqual(1, intersect.Order); - Assert.AreEqual(2, ac1.Order); + Assert.Multiple(() => + { + Assert.That(ac2.Order, Is.EqualTo(0)); + Assert.That(intersect.Order, Is.EqualTo(1)); + Assert.That(ac1.Order, Is.EqualTo(2)); + }); } private void DeleteOldAggregates() @@ -138,7 +147,7 @@ private void DeleteOldAggregates() foreach (var ac in Repository.GetAllObjects()) ac.DeleteInDatabase(); - Assert.AreEqual(0, Repository.GetAllObjects().Length, + Assert.That(Repository.GetAllObjects(), Is.Empty, "We just deleted the AggregateConfigurations why were there suddenly some in the db!?"); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/CohortUI/CohortSourceManagement/ExternalCohortTableUITests.cs b/Rdmp.UI.Tests/CohortUI/CohortSourceManagement/ExternalCohortTableUITests.cs index 84373e7fc4..cbcea73e5a 100644 --- a/Rdmp.UI.Tests/CohortUI/CohortSourceManagement/ExternalCohortTableUITests.cs +++ b/Rdmp.UI.Tests/CohortUI/CohortSourceManagement/ExternalCohortTableUITests.cs @@ -18,7 +18,7 @@ public void Test_ExternalCohortTableUI_Constructor() { var o = WhenIHaveA(); var ui = AndLaunch(o); - Assert.IsNotNull(ui); + Assert.That(ui, Is.Not.Null); //because cohort table doesnt actually go to a legit database the source should have been forbidlisted during the child provider stage (not really related to our UI). AssertErrorWasShown(ExpectedErrorType.GlobalErrorCheckNotifier, diff --git a/Rdmp.UI.Tests/CommandExecution/Alter/ExecuteCommandAlterColumnTypeTests.cs b/Rdmp.UI.Tests/CommandExecution/Alter/ExecuteCommandAlterColumnTypeTests.cs index 4723f21d83..7535625337 100644 --- a/Rdmp.UI.Tests/CommandExecution/Alter/ExecuteCommandAlterColumnTypeTests.cs +++ b/Rdmp.UI.Tests/CommandExecution/Alter/ExecuteCommandAlterColumnTypeTests.cs @@ -33,7 +33,7 @@ public void AlterColumnType_NoArchive(DatabaseType dbType) var myCol = tbl.DiscoverColumn("myCol"); //should have started out as 10 - Assert.AreEqual(10, myCol.DataType.GetLengthIfString()); + Assert.That(myCol.DataType.GetLengthIfString(), Is.EqualTo(10)); //we want the new type to be 50 long var newType = myCol.DataType.SQLType.Replace("10", "50"); @@ -45,8 +45,11 @@ public void AlterColumnType_NoArchive(DatabaseType dbType) //rediscover the col to get the expected new datatype myCol = tbl.DiscoverColumn("myCol"); - Assert.AreEqual(newType, myCol.DataType.SQLType); - Assert.AreEqual(newType, ti.ColumnInfos[0].Data_type); + Assert.Multiple(() => + { + Assert.That(myCol.DataType.SQLType, Is.EqualTo(newType)); + Assert.That(ti.ColumnInfos[0].Data_type, Is.EqualTo(newType)); + }); tbl.Drop(); } @@ -72,7 +75,7 @@ public void AlterColumnType_WithArchive(DatabaseType dbType) var myCol = tbl.DiscoverColumn("myCol"); //should have started out as 10 - Assert.AreEqual(10, myCol.DataType.GetLengthIfString()); + Assert.That(myCol.DataType.GetLengthIfString(), Is.EqualTo(10)); var oldType = myCol.DataType.SQLType; //we want the new type to be 50 long @@ -86,11 +89,14 @@ public void AlterColumnType_WithArchive(DatabaseType dbType) myCol = tbl.DiscoverColumn("myCol"); var myColArchive = tblArchive.DiscoverColumn("myCol"); - Assert.AreEqual(newType, myCol.DataType.SQLType); - Assert.AreEqual(newType, ti.ColumnInfos[0].Data_type); + Assert.Multiple(() => + { + Assert.That(myCol.DataType.SQLType, Is.EqualTo(newType)); + Assert.That(ti.ColumnInfos[0].Data_type, Is.EqualTo(newType)); - //if they changed the archive then the archive column should also match on Type otherwise it should have stayed the old Type - Assert.AreEqual(newType, myColArchive.DataType.SQLType); + //if they changed the archive then the archive column should also match on Type otherwise it should have stayed the old Type + Assert.That(myColArchive.DataType.SQLType, Is.EqualTo(newType)); + }); tbl.Drop(); tblArchive.Drop(); diff --git a/Rdmp.UI.Tests/CommandExecution/ExecuteCommandClearFavouritesTests.cs b/Rdmp.UI.Tests/CommandExecution/ExecuteCommandClearFavouritesTests.cs index 5836ca1a1f..93a27c0230 100644 --- a/Rdmp.UI.Tests/CommandExecution/ExecuteCommandClearFavouritesTests.cs +++ b/Rdmp.UI.Tests/CommandExecution/ExecuteCommandClearFavouritesTests.cs @@ -19,15 +19,18 @@ public void Test_NoFavourites() { var cmd = new ExecuteCommandClearFavourites(ItemActivator); - Assert.IsTrue(cmd.IsImpossible); - StringAssert.AreEqualIgnoringCase("You do not have any Favourites", cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Is.EqualTo("You do not have any Favourites").IgnoreCase); + }); var myFavCatalogue = WhenIHaveA(); ItemActivator.FavouritesProvider.AddFavourite(this, myFavCatalogue); cmd = new ExecuteCommandClearFavourites(ItemActivator); - Assert.IsFalse(cmd.IsImpossible); + Assert.That(cmd.IsImpossible, Is.False); } @@ -41,7 +44,7 @@ public void Test_ClearFavourites() ItemActivator.FavouritesProvider.AddFavourite(this, myFavCatalogue); ItemActivator.FavouritesProvider.AddFavourite(this, mProject); - Assert.AreEqual(2, ItemActivator.FavouritesProvider.CurrentFavourites.Count); + Assert.That(ItemActivator.FavouritesProvider.CurrentFavourites, Has.Count.EqualTo(2)); //when we say no to deleting them ItemActivator.YesNoResponse = false; @@ -50,13 +53,13 @@ public void Test_ClearFavourites() cmd.Execute(); //they should not be deleted! - Assert.AreEqual(2, ItemActivator.FavouritesProvider.CurrentFavourites.Count); + Assert.That(ItemActivator.FavouritesProvider.CurrentFavourites, Has.Count.EqualTo(2)); //when we say yes to deleting them ItemActivator.YesNoResponse = true; cmd.Execute(); //they should not be deleted - Assert.IsEmpty(ItemActivator.FavouritesProvider.CurrentFavourites); + Assert.That(ItemActivator.FavouritesProvider.CurrentFavourites, Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/CommandExecution/ExecuteCommandDeleteTests.cs b/Rdmp.UI.Tests/CommandExecution/ExecuteCommandDeleteTests.cs index 76a4a179e5..baf683cb17 100644 --- a/Rdmp.UI.Tests/CommandExecution/ExecuteCommandDeleteTests.cs +++ b/Rdmp.UI.Tests/CommandExecution/ExecuteCommandDeleteTests.cs @@ -19,7 +19,7 @@ internal class ExecuteCommandDeleteTests : UITests public void Delete_IsSupportedCommand() { var invoker = new CommandInvoker(ItemActivator); - Assert.IsNull(invoker.WhyCommandNotSupported(typeof(ExecuteCommandDelete))); + Assert.That(invoker.WhyCommandNotSupported(typeof(ExecuteCommandDelete)), Is.Null); } /// @@ -35,8 +35,11 @@ public void TestDeleteMultiple_OneObjectInheritsAnother() ItemActivator.YesNoResponse = true; - Assert.IsTrue(ci.Exists()); - Assert.IsTrue(ei.Exists()); + Assert.Multiple(() => + { + Assert.That(ci.Exists()); + Assert.That(ei.Exists()); + }); //now because we don't actually have a CASCADE in memory we will have to fake it ei.DeleteInDatabase(); @@ -44,8 +47,11 @@ public void TestDeleteMultiple_OneObjectInheritsAnother() var cmd = new ExecuteCommandDelete(ItemActivator, new IDeleteable[] { ci, ei }); cmd.Execute(); - Assert.IsFalse(ci.Exists()); - Assert.IsFalse(ei.Exists()); + Assert.Multiple(() => + { + Assert.That(ci.Exists(), Is.False); + Assert.That(ei.Exists(), Is.False); + }); } [Test] @@ -53,13 +59,16 @@ public void TestDeleteMultiple_OneObjectInheritsAnother() public void Test_DeleteRootContainer_IsImpossible() { var container = WhenIHaveA(); - Assert.IsNotNull(container); - Assert.IsTrue(container.IsRootContainer(), "expected it to be a root container"); + Assert.That(container, Is.Not.Null); + Assert.That(container.IsRootContainer(), "expected it to be a root container"); var cmd = new ExecuteCommandDelete(ItemActivator, container); - Assert.IsTrue(cmd.IsImpossible, "expected command to be impossible"); - StringAssert.Contains("root container", cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible, "expected command to be impossible"); + Assert.That(cmd.ReasonCommandImpossible, Does.Contain("root container")); + }); } @@ -73,8 +82,11 @@ public void Test_Delete2RootContainers_IsImpossible() var cmd = new ExecuteCommandDelete(ItemActivator, new IDeleteable[] { container1, container2 }); - Assert.IsTrue(cmd.IsImpossible, "expected command to be impossible"); - StringAssert.Contains("root container", cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible, "expected command to be impossible"); + Assert.That(cmd.ReasonCommandImpossible, Does.Contain("root container")); + }); } @@ -90,9 +102,9 @@ public void Test_DeleteNonRootContainer_Possible() cic.SaveToDatabase(); container.AddChild(subcontainer); - Assert.IsFalse(subcontainer.IsRootContainer(), "expected it not to be a root container"); + Assert.That(subcontainer.IsRootContainer(), Is.False, "expected it not to be a root container"); var cmd = new ExecuteCommandDelete(ItemActivator, subcontainer); - Assert.IsFalse(cmd.IsImpossible, "expected command to be possible"); + Assert.That(cmd.IsImpossible, Is.False, "expected command to be possible"); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/Curation/Integration/ExtractionFilterUITests.cs b/Rdmp.UI.Tests/Curation/Integration/ExtractionFilterUITests.cs index 6fa2330a89..521e2565c3 100644 --- a/Rdmp.UI.Tests/Curation/Integration/ExtractionFilterUITests.cs +++ b/Rdmp.UI.Tests/Curation/Integration/ExtractionFilterUITests.cs @@ -19,8 +19,11 @@ public void TestExtractionFilterDeleting_WhenItHas_ExtractionFilterParameterSet_ var set = new ExtractionFilterParameterSet(Repository, filter, "fff"); - Assert.IsTrue(filter.Exists()); - Assert.IsTrue(set.Exists()); + Assert.Multiple(() => + { + Assert.That(filter.Exists()); + Assert.That(set.Exists()); + }); var activator = new TestActivateItems(this, Repository) { @@ -31,7 +34,10 @@ public void TestExtractionFilterDeleting_WhenItHas_ExtractionFilterParameterSet_ var del = new ExecuteCommandDelete(activator, filter); del.Execute(); - Assert.IsFalse(filter.Exists()); - Assert.IsFalse(set.Exists()); + Assert.Multiple(() => + { + Assert.That(filter.Exists(), Is.False); + Assert.That(set.Exists(), Is.False); + }); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/DataLoadUIs/ANOUIs/ANOTableManagement/ColumnInfoToANOTableConverterUITests.cs b/Rdmp.UI.Tests/DataLoadUIs/ANOUIs/ANOTableManagement/ColumnInfoToANOTableConverterUITests.cs index 3401803107..becb5ebb26 100644 --- a/Rdmp.UI.Tests/DataLoadUIs/ANOUIs/ANOTableManagement/ColumnInfoToANOTableConverterUITests.cs +++ b/Rdmp.UI.Tests/DataLoadUIs/ANOUIs/ANOTableManagement/ColumnInfoToANOTableConverterUITests.cs @@ -18,7 +18,7 @@ public void Test_ColumnInfoToANOTableConverterUI_Constructor() { var o = WhenIHaveA(); var ui = AndLaunch(o); - Assert.IsNotNull(ui); + Assert.That(ui, Is.Not.Null); AssertErrorWasShown(ExpectedErrorType.KilledForm, "Could not get connection string because Server was null on dataAccessPoint 'My_Table'"); //AssertNoErrors(ExpectedErrorType.Fatal); diff --git a/Rdmp.UI.Tests/DataRelease/DataReleaseUITests.cs b/Rdmp.UI.Tests/DataRelease/DataReleaseUITests.cs index 5878d1ce28..693bf584b0 100644 --- a/Rdmp.UI.Tests/DataRelease/DataReleaseUITests.cs +++ b/Rdmp.UI.Tests/DataRelease/DataReleaseUITests.cs @@ -18,7 +18,7 @@ public void Test_DataReleaseUI_Constructor() { var o = WhenIHaveA(); var ui = AndLaunch(o); - Assert.IsNotNull(ui); + Assert.That(ui, Is.Not.Null); AssertNoErrors(ExpectedErrorType.Any); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/DesignPatternTests/AllObjectsHaveImages.cs b/Rdmp.UI.Tests/DesignPatternTests/AllObjectsHaveImages.cs index c4e2dbfe03..d0b202b68e 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/AllObjectsHaveImages.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/AllObjectsHaveImages.cs @@ -45,6 +45,6 @@ public void AllIHasDependenciesHaveIcons() Console.WriteLine( $"The following Database Object Types are missing concepts (and therefore images) in CatalogueManager.exe{Environment.NewLine}{string.Join($",{Environment.NewLine}", missingConcepts)}"); - Assert.AreEqual(0, missingConcepts.Count); + Assert.That(missingConcepts, Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/DesignPatternTests/AllUIsDocumentedTest.cs b/Rdmp.UI.Tests/DesignPatternTests/AllUIsDocumentedTest.cs index eb3fc631e8..9601cc4499 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/AllUIsDocumentedTest.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/AllUIsDocumentedTest.cs @@ -53,7 +53,7 @@ public void EveryClassInAppropriateNamespace() foreach (var error in Errors) Console.WriteLine($"FATAL NAMESPACE ERROR FAILURE:{error}"); - Assert.AreEqual(Errors.Count, 0); + Assert.That(Errors, Is.Empty); } private string[] _exemptNamespaces = diff --git a/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/AllImportantClassesDocumented.cs b/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/AllImportantClassesDocumented.cs index d754e2c63c..7dea59e9c2 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/AllImportantClassesDocumented.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/AllImportantClassesDocumented.cs @@ -141,7 +141,7 @@ public void FindProblems(List csFilesList) Console.WriteLine($"Total Documented Classes:{commentedCount}"); Console.WriteLine($"Total Lines of Classes Documentation:{commentLineCount}"); - Assert.AreEqual(0, problems.Count); + Assert.That(problems, Is.Empty); } [GeneratedRegex("namespace (.*)")] diff --git a/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/DocumentationCrossExaminationTest.cs b/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/DocumentationCrossExaminationTest.cs index 45f605f542..67805eb1c9 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/DocumentationCrossExaminationTest.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/DocumentationCrossExaminationTest.cs @@ -376,7 +376,7 @@ public void FindProblems(List csFilesFound) Console.WriteLine(problem); } - Assert.AreEqual(0, problems.Count, + Assert.That(problems, Is.Empty, "Expected there to be nothing talked about in comments that doesn't appear in the codebase somewhere"); } @@ -437,7 +437,7 @@ private static void EnsureCodeBlocksCompile(string mdFile, List problems var code = Regex.Replace(m.Groups[1].Value, "\\s+", " "); var docs = Regex.Replace(kvp.Value, "\\s+", " "); - Assert.AreEqual(code.Trim(), docs.Trim(), + Assert.That(docs.Trim(), Is.EqualTo(code.Trim()), $"Code in the documentation markdown (actual) did not match the corresponding compiled code (expected) for code guid {kvp.Key} markdown file was {mdFile} and code file was {codeBlocks}"); } } diff --git a/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/ExplicitDatabaseNameChecker.cs b/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/ExplicitDatabaseNameChecker.cs index 9be14362a9..075dd54c1d 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/ExplicitDatabaseNameChecker.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/ExplicitDatabaseNameChecker.cs @@ -66,6 +66,6 @@ public static void FindProblems(List csFilesFound) Console.WriteLine( $"FAIL: File '{kvp.Key}' contains a reference to an explicitly prohibited database name string ('{kvp.Value}')"); - Assert.AreEqual(0, problemFiles.Count); + Assert.That(problemFiles, Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/SuspiciousEmptyChecksMethodsOrNotICheckablePlugins.cs b/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/SuspiciousEmptyChecksMethodsOrNotICheckablePlugins.cs index 9327d6f99f..133da3cb2b 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/SuspiciousEmptyChecksMethodsOrNotICheckablePlugins.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/SuspiciousEmptyChecksMethodsOrNotICheckablePlugins.cs @@ -75,7 +75,7 @@ public void FindProblems(List csFilesFound) foreach (var fail in _fails) Console.WriteLine(fail); - Assert.AreEqual(0, _fails.Count); + Assert.That(_fails, Is.Empty); } [GeneratedRegex("(\\b|[a-z])Test(\\b|[A-Z])")] diff --git a/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/SuspiciousRelationshipPropertyUse.cs b/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/SuspiciousRelationshipPropertyUse.cs index 6440938084..48f936f092 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/SuspiciousRelationshipPropertyUse.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/ClassFileEvaluation/SuspiciousRelationshipPropertyUse.cs @@ -198,68 +198,7 @@ public void FindPropertyMisuse(List csFilesFound) foreach (var fail in _fails) Console.WriteLine(fail); - Assert.AreEqual(0, _fails.Count); - } - - private static void AnalyseRelationshipPropertyUsages() - { - foreach (var t in MEF.GetAllTypes()) - { - if (!t.IsClass) - continue; - - //don't worry about the ToString method on classes that are IInjectKnown - var toStringMethod = t.GetMethod("ToString", Type.EmptyTypes); - - //it doesn't have any ToString methods! - if (toStringMethod == null) - continue; - - if (toStringMethod.DeclaringType == typeof(object)) - continue; - - if (toStringMethod.DeclaringType == typeof(MarshalByRefObject)) - continue; - /* - IList instructions = null; - try - { - instructions = toStringMethod.GetInstructions(); - } - catch (Exception e) - { - Console.WriteLine(e); - } - - if (instructions != null) - foreach (Instruction instruction in instructions) - { - MethodInfo methodInfo = instruction.Operand as MethodInfo; - - if (methodInfo != null) - { - //is it a call to property - PropertyInfo prop; - - if (RelationshipPropertyInfos.TryGetBySecond(methodInfo, out prop)) - { - - //It doesn't look injected but it is - if(t == typeof(JoinInfo)) - continue; - - //if we are injectable for it - if( t.GetInterfaces().Any(x => - x.IsGenericType && - x.GetGenericTypeDefinition() == typeof(IInjectKnown<>) && - x.GetGenericArguments()[0] == prop.PropertyType)) - continue; - - _fails.Add("FAIL: ToString method in Type " + t.FullName + " uses Relationship PropertyInfo " + prop.Name); - } - } - }*/ - } + Assert.That(_fails, Is.Empty); } diff --git a/Rdmp.UI.Tests/DesignPatternTests/DependenciesEvaluation.cs b/Rdmp.UI.Tests/DesignPatternTests/DependenciesEvaluation.cs deleted file mode 100644 index 873391405c..0000000000 --- a/Rdmp.UI.Tests/DesignPatternTests/DependenciesEvaluation.cs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) The University of Dundee 2018-2019 -// This file is part of the Research Data Management Platform (RDMP). -// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -// RDMP 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 General Public License for more details. -// You should have received a copy of the GNU General Public License along with RDMP. If not, see . - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using System.Xml; -using NUnit.Framework; -using Rdmp.Core.ReusableLibraryCode.VisualStudioSolutionFileProcessing; - -namespace Rdmp.UI.Tests.DesignPatternTests; - -public class DependenciesEvaluation -{ - private string[] _nuspecFiles = - { - "Plugin/Plugin.Test/Plugin.Test.nuspec", - "Plugin/Plugin/Plugin.nuspec", - "Plugin/Plugin.UI/Plugin.UI.nuspec" - }; - - private Dictionary Dependencies = new(); - - public void FindProblems(VisualStudioSolutionFile sln) - { - var problems = new List(); - - foreach (var nuspecFile in _nuspecFiles) - { - var filePath = Path.Combine(sln.SolutionDirectory.FullName, nuspecFile); - var text = File.ReadAllText(filePath); - - - // - - var dc = new XmlDocument(); - dc.Load(fappPackages.FullName); - - foreach (XmlElement dependency in dc.GetElementsByTagName("package")) - { - var assembly = $"\"{dependency.Attributes["id"].Value}\""; - var version = $"\"{dependency.Attributes["version"].Value}\""; - - if (Dependencies.ContainsKey(assembly)) - { - if (!Equals(Dependencies[assembly], version)) - problems.Add( - $"In package {fappPackages.FullName} you reference {assembly} with version {version} but your nuspec has version {Dependencies[assembly]}"); - } - else - { - problems.Add( - $"In package {fappPackages.FullName} you reference {assembly} (version {version}) but no corresponding dependency listed in any of your nuspec files."); - } - } - } - - var csprojFileContents = File.ReadAllText(csproj.FullName); - - //look for dodgy reference includes - foreach (var (key, versionInNuspec) in Dependencies) - { - //Reference Include="MySql.Data, Version=8.0.12.0 - var r = new Regex($@"{key.Trim('"')}, Version=([0-9.""]*)"); - - foreach (Match match in r.Matches(csprojFileContents)) - { - var versionInCsproj = match.Groups[1].Value; - - if (!AreProbablyCompatibleVersions(versionInNuspec, versionInCsproj)) - problems.Add( - $"csproj file {project.Name} lists dependency of {key} with version {versionInCsproj} while in the nuspec it is {versionInNuspec}"); - } - } - } - - foreach (var problem in problems) - Console.WriteLine(problem); - - Assert.AreEqual(0, problems.Count); - } - - private void ProcessAppConfig(FileInfo fappConfig, List problems) - { - //look for dodgy binding redirects - - /* - * - */ - var dc = new XmlDocument(); - dc.Load(fappConfig.FullName); - - foreach (XmlElement dependency in dc.GetElementsByTagName("dependentAssembly")) - { - var assemblyIdentity = - dependency.GetElementsByTagName("assemblyIdentity").OfType().SingleOrDefault(); - var bindingRedirect = - dependency.GetElementsByTagName("bindingRedirect").OfType().SingleOrDefault(); - - if (assemblyIdentity != null && bindingRedirect != null) - { - var version = $"\"{bindingRedirect.Attributes["newVersion"].Value}\""; - var assembly = $"\"{assemblyIdentity.Attributes["name"].Value}\""; - - if (Dependencies.ContainsKey(assembly)) - { - if (!AreProbablyCompatibleVersions(Dependencies[assembly], version)) - problems.Add( - $"You have a binding redirect in {fappConfig.FullName} for assembly {assembly} to version {version} but your nuspec has version {Dependencies[assembly]}"); - } - else - { - problems.Add( - $"You have a binding redirect in {fappConfig.FullName} for assembly {assembly} but no corresponding dependency listed in any of your nuspec files. Why do you have binding redirects for assemblies that are not redistributed with RDMP?"); - } - } - } - } - - /// - /// Returns true if the assemblies are likely to be compatible - /// - /// The version available - /// The version required, can include 0 elements for wildcards e.g. 11.0.0.0 would be compatible with 11.2.0.0 - /// - private static bool AreProbablyCompatibleVersions(string availableVersion, string requiredVersion) - { - var v1 = new Version(availableVersion.Trim('"')); - var v2 = new Version(requiredVersion.Trim('"')); - - //must be equal on first 3 numbers (Revision is allowed to differ) - return - v1.Major == v2.Major && - (v1.Minor == v2.Minor || v2.Minor == 0 || v2.Minor == -1) && - (v1.Build == v2.Build || v2.Build == 0 || v2.Build == -1) && - (v1.Revision == v2.Revision || v2.Revision == 0 || v2.Revision == -1); - } -} \ No newline at end of file diff --git a/Rdmp.UI.Tests/DesignPatternTests/EvaluateNamespacesAndSolutionFoldersTests.cs b/Rdmp.UI.Tests/DesignPatternTests/EvaluateNamespacesAndSolutionFoldersTests.cs index 8fad7f558b..69bb58594f 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/EvaluateNamespacesAndSolutionFoldersTests.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/EvaluateNamespacesAndSolutionFoldersTests.cs @@ -42,7 +42,7 @@ public void EvaluateNamespacesAndSolutionFolders() { var solutionDir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory); while (solutionDir?.GetFiles("*.sln").Any() != true) solutionDir = solutionDir?.Parent; - Assert.IsNotNull(solutionDir, "Failed to find {0} in any parent directories", SolutionName); + Assert.That(solutionDir, Is.Not.Null, $"Failed to find {SolutionName} in any parent directories"); var sln = new VisualStudioSolutionFile(solutionDir, solutionDir.GetFiles(SolutionName).Single()); @@ -68,7 +68,7 @@ public void EvaluateNamespacesAndSolutionFolders() break; } - Assert.AreEqual(0, _errors.Count); + Assert.That(_errors, Is.Empty); // DependenciesEvaluation dependencies = new DependenciesEvaluation(); // dependencies.FindProblems(sln); @@ -240,9 +240,7 @@ public static void FindProblems(List csFilesFound) suggestedNewFileContents.Add(file, sbSuggestedText.ToString()); } - Assert.AreEqual(0, suggestedNewFileContents.Count, "The following files did not contain copyright:{0}{1}", - Environment.NewLine, - string.Join(Environment.NewLine, suggestedNewFileContents.Keys.Select(Path.GetFileName))); + Assert.That(suggestedNewFileContents, Is.Empty, $"The following files did not contain copyright:{Environment.NewLine}{string.Join(Environment.NewLine, suggestedNewFileContents.Keys.Select(Path.GetFileName))}"); //drag your debugger stack pointer to here to mess up all your files to match the suggestedNewFileContents :) foreach (var suggestedNewFileContent in suggestedNewFileContents) @@ -289,8 +287,11 @@ public static void FindProblems(List csFilesFound) var whitespace = m.Groups[1].Value; var member = m.Groups[3].Value; - Assert.IsTrue(string.IsNullOrWhiteSpace(whitespace)); - Assert.IsNotNull(t); + Assert.Multiple(() => + { + Assert.That(string.IsNullOrWhiteSpace(whitespace)); + Assert.That(t, Is.Not.Null); + }); if (t.GetProperty($"{member}_ID") != null) { @@ -370,7 +371,7 @@ public static void FindProblems(List csFilesFound) foreach (var suggestedNewFileContent in suggestedNewFileContents) File.WriteAllText(suggestedNewFileContent.Key, suggestedNewFileContent.Value); - Assert.IsEmpty(suggestedNewFileContents); + Assert.That(suggestedNewFileContents, Is.Empty); } private static string GetUniqueTypeName(string typename) diff --git a/Rdmp.UI.Tests/DesignPatternTests/InterfaceDeclarationsCorrect.cs b/Rdmp.UI.Tests/DesignPatternTests/InterfaceDeclarationsCorrect.cs index b8b5fb0021..d1d0616a1b 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/InterfaceDeclarationsCorrect.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/InterfaceDeclarationsCorrect.cs @@ -36,6 +36,6 @@ public static void FindProblems() .Select(static matchingInterface => $"FAIL: Interface '{matchingInterface.Name}' does not inherit IMapsDirectlyToDatabaseTable") .ToList(); - Assert.IsEmpty(problems); + Assert.That(problems, Is.Empty); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/DesignPatternTests/RunUITests.cs b/Rdmp.UI.Tests/DesignPatternTests/RunUITests.cs index 7f28d28a28..182055a69e 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/RunUITests.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/RunUITests.cs @@ -73,7 +73,8 @@ private List allowedToBeIncompatible typeof(ExecuteCommandCreateLookup), typeof(ExecuteCommandImportFilterDescriptionsFromShare), typeof(ExecuteCommandSetArgument), - typeof(ExecuteCommandAddToSession) + typeof(ExecuteCommandAddToSession), + typeof(ExecuteCommandDeletePlugin) }); [Test] @@ -86,7 +87,7 @@ public void AllCommandsCompatible() var commandCaller = new CommandInvoker(activator); - Assert.IsTrue(commandCaller.WhyCommandNotSupported(typeof(ExecuteCommandDelete)) is null); + Assert.That(commandCaller.WhyCommandNotSupported(typeof(ExecuteCommandDelete)) is null); var notSupported = MEF.GetAllTypes() .Where(t => typeof(IAtomicCommand).IsAssignableFrom(t) && !t.IsAbstract && @@ -95,7 +96,7 @@ public void AllCommandsCompatible() .Where(t => commandCaller.WhyCommandNotSupported(t) is not null) //but for some reason isn't .ToArray(); - Assert.AreEqual(0, notSupported.Length, + Assert.That(notSupported, Is.Empty, "The following commands were not compatible with RunUI:" + Environment.NewLine + string.Join(Environment.NewLine, notSupported.Select(t => t.Name))); } @@ -114,7 +115,7 @@ public void Test_IsSupported_BasicActivator() }) { var isSupported = commandCaller.WhyCommandNotSupported(t); - Assert.IsTrue(isSupported is null, $"Unsupported type {t} due to {isSupported}"); + Assert.That(isSupported is null, $"Unsupported type {t} due to {isSupported}"); } } diff --git a/Rdmp.UI.Tests/DesignPatternTests/UserInterfaceStandardisationChecker.cs b/Rdmp.UI.Tests/DesignPatternTests/UserInterfaceStandardisationChecker.cs index 750477fe75..4d74a84ce2 100644 --- a/Rdmp.UI.Tests/DesignPatternTests/UserInterfaceStandardisationChecker.cs +++ b/Rdmp.UI.Tests/DesignPatternTests/UserInterfaceStandardisationChecker.cs @@ -194,7 +194,7 @@ public void FindProblems(List csFilesList) foreach (var problem in problems) Console.WriteLine($"FATAL ERROR PROBLEM:{problem}"); - Assert.AreEqual(problems.Count, 0); + Assert.That(problems, Is.Empty); } private string GetExpectedClassOrInterface(string expectedClassName) diff --git a/Rdmp.UI.Tests/ExternalDatabaseServerUITests.cs b/Rdmp.UI.Tests/ExternalDatabaseServerUITests.cs index 5e03ac0a30..5878307105 100644 --- a/Rdmp.UI.Tests/ExternalDatabaseServerUITests.cs +++ b/Rdmp.UI.Tests/ExternalDatabaseServerUITests.cs @@ -22,13 +22,13 @@ public void Test_ExternalDatabaseServerUITests_NormalState() AssertNoErrors(ExpectedErrorType.Any); ui.tbUsername.Text = "fish"; - Assert.AreEqual("fish", server.Username); + Assert.That(server.Username, Is.EqualTo("fish")); ui.GetObjectSaverButton().Save(); - Assert.AreEqual("fish", server.Username); + Assert.That(server.Username, Is.EqualTo("fish")); ui.tbUsername.Text = ""; ui.GetObjectSaverButton().Save(); - Assert.AreEqual("", server.Username); + Assert.That(server.Username, Is.EqualTo("")); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/ExtractionUIs/ConfigureDatasetUITests.cs b/Rdmp.UI.Tests/ExtractionUIs/ConfigureDatasetUITests.cs index c2f5ad3c46..b1692cd1ca 100644 --- a/Rdmp.UI.Tests/ExtractionUIs/ConfigureDatasetUITests.cs +++ b/Rdmp.UI.Tests/ExtractionUIs/ConfigureDatasetUITests.cs @@ -25,36 +25,35 @@ public void Test_RemoveAllColumns_Only1Publish() //should be at least 2 in the config for this test to be sensible var cols = sds.ExtractionConfiguration.GetAllExtractableColumnsFor(sds.ExtractableDataSet); - Assert.GreaterOrEqual(cols.Length, 2); + Assert.That(cols, Has.Length.GreaterThanOrEqualTo(2)); ItemActivator.RefreshBus.BeforePublish += (s, e) => publishCount++; - Assert.AreEqual(0, publishCount); + Assert.That(publishCount, Is.EqualTo(0)); ui.ExcludeAll(); - Assert.AreEqual(1, publishCount); + Assert.That(publishCount, Is.EqualTo(1)); AssertNoErrors(); //should now be no columns in the extraction configuration - Assert.IsEmpty(sds.ExtractionConfiguration.GetAllExtractableColumnsFor(sds.ExtractableDataSet)); + Assert.That(sds.ExtractionConfiguration.GetAllExtractableColumnsFor(sds.ExtractableDataSet), Is.Empty); ui.IncludeAll(); //should now be another publish event - Assert.AreEqual(2, publishCount); + Assert.That(publishCount, Is.EqualTo(2)); //and the columns should be back in the configuration cols = sds.ExtractionConfiguration.GetAllExtractableColumnsFor(sds.ExtractableDataSet); - Assert.GreaterOrEqual(cols.Length, 2); + Assert.That(cols, Has.Length.GreaterThanOrEqualTo(2)); //multiple includes shouldnt change the number of columns ui.IncludeAll(); ui.IncludeAll(); ui.IncludeAll(); - Assert.AreEqual(cols.Length, - sds.ExtractionConfiguration.GetAllExtractableColumnsFor(sds.ExtractableDataSet).Length); + Assert.That(sds.ExtractionConfiguration.GetAllExtractableColumnsFor(sds.ExtractableDataSet), Has.Length.EqualTo(cols.Length)); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/ExtractionUIs/JoinsAndLookups/LookupBrowserUITests.cs b/Rdmp.UI.Tests/ExtractionUIs/JoinsAndLookups/LookupBrowserUITests.cs index 0514cea790..55adf02bc8 100644 --- a/Rdmp.UI.Tests/ExtractionUIs/JoinsAndLookups/LookupBrowserUITests.cs +++ b/Rdmp.UI.Tests/ExtractionUIs/JoinsAndLookups/LookupBrowserUITests.cs @@ -18,7 +18,7 @@ public void Test_LookupBrowserUI_Constructor() { var o = WhenIHaveA(); var ui = AndLaunch(o); - Assert.IsNotNull(ui); + Assert.That(ui, Is.Not.Null); //AssertNoErrors(ExpectedErrorType.Fatal); //AssertNoErrors(ExpectedErrorType.KilledForm); } diff --git a/Rdmp.UI.Tests/ForEachUITests.cs b/Rdmp.UI.Tests/ForEachUITests.cs index 4337be0b63..e8c77b9a66 100644 --- a/Rdmp.UI.Tests/ForEachUITests.cs +++ b/Rdmp.UI.Tests/ForEachUITests.cs @@ -22,8 +22,11 @@ public void ForEachUI_Test_GetTabName() { ForEachUI(ui => { - Assert.NotNull(ui); - Assert.IsFalse(string.IsNullOrWhiteSpace(ui.GetTabName())); + Assert.Multiple(() => + { + Assert.That(ui, Is.Not.Null); + Assert.That(string.IsNullOrWhiteSpace(ui.GetTabName()), Is.False); + }); }); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/HelpIconTests.cs b/Rdmp.UI.Tests/HelpIconTests.cs index 9aeab892c9..6cd655fe04 100644 --- a/Rdmp.UI.Tests/HelpIconTests.cs +++ b/Rdmp.UI.Tests/HelpIconTests.cs @@ -17,7 +17,7 @@ public void TestNullInputs_HelpIcon() var hi = new HelpIcon(); hi.SetHelpText(null, null); hi.SetHelpText("", ""); - Assert.IsNull(hi.HoverText); + Assert.That(hi.HoverText, Is.Null); } [Test] @@ -29,6 +29,6 @@ public void TestLongInputs_HelpIcon() const string testLongString = "kdsfldsfjsdafdfjsdafldsafadsfksdafjdfjdsfasdjfdsjfsdfldsjfkdsfkdsfksdafjdfsdaf;sdafsdafadsflsdafksdfjadslfjdsflsdjfldsfksadkfadkfasdfadsjfasdsdfladsfjsdjfkdflsdfksdfkadsfladsfj"; hi.SetHelpText(null, testLongString); - Assert.AreEqual(HelpIcon.MaxHoverTextLength, hi.HoverText.Length); + Assert.That(hi.HoverText, Has.Length.EqualTo(HelpIcon.MaxHoverTextLength)); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/HistoryProviderTests.cs b/Rdmp.UI.Tests/HistoryProviderTests.cs index 4fbf477222..9c0b62bdae 100644 --- a/Rdmp.UI.Tests/HistoryProviderTests.cs +++ b/Rdmp.UI.Tests/HistoryProviderTests.cs @@ -24,25 +24,25 @@ public void TestHistoryProvider_DuplicateAdding() var provider = new HistoryProvider(RepositoryLocator); provider.Clear(); - Assert.IsEmpty(provider.History); + Assert.That(provider.History, Is.Empty); provider.Add(c); - Assert.AreEqual(1, provider.History.Count); + Assert.That(provider.History, Has.Count.EqualTo(1)); provider.Add(c); - Assert.AreEqual(1, provider.History.Count); + Assert.That(provider.History, Has.Count.EqualTo(1)); provider.Add(c); - Assert.AreEqual(1, provider.History.Count); + Assert.That(provider.History, Has.Count.EqualTo(1)); var p = WhenIHaveA(); provider.Add(p); - Assert.AreEqual(2, provider.History.Count); + Assert.That(provider.History, Has.Count.EqualTo(2)); } [Test] @@ -55,7 +55,7 @@ public void TestHistoryProvider_Persist() var provider = new HistoryProvider(RepositoryLocator); provider.Clear(); - Assert.IsEmpty(provider.History); + Assert.That(provider.History, Is.Empty); provider.History.Add(new HistoryEntry(c1, new DateTime(2001, 01, 01))); provider.History.Add(new HistoryEntry(c2, new DateTime(2002, 02, 01))); @@ -63,20 +63,26 @@ public void TestHistoryProvider_Persist() provider.History.Add(new HistoryEntry(c4, new DateTime(2004, 01, 04))); provider.Save(2); - Assert.AreEqual(2, provider.History.Count); + Assert.That(provider.History, Has.Count.EqualTo(2)); - Assert.AreEqual(c4, provider.History[0].Object); - Assert.AreEqual(c3, provider.History[1].Object); - Assert.AreEqual(new DateTime(2004, 01, 04), provider.History[0].Date); - Assert.AreEqual(new DateTime(2003, 03, 01), provider.History[1].Date); + Assert.Multiple(() => + { + Assert.That(provider.History[0].Object, Is.EqualTo(c4)); + Assert.That(provider.History[1].Object, Is.EqualTo(c3)); + Assert.That(provider.History[0].Date, Is.EqualTo(new DateTime(2004, 01, 04))); + Assert.That(provider.History[1].Date, Is.EqualTo(new DateTime(2003, 03, 01))); + }); var provider2 = new HistoryProvider(RepositoryLocator); - Assert.AreEqual(c4, provider2.History[0].Object); - Assert.AreEqual(c3, provider2.History[1].Object); - Assert.AreEqual(new DateTime(2004, 01, 04), provider2.History[0].Date); - Assert.AreEqual(new DateTime(2003, 03, 01), provider2.History[1].Date); + Assert.Multiple(() => + { + Assert.That(provider2.History[0].Object, Is.EqualTo(c4)); + Assert.That(provider2.History[1].Object, Is.EqualTo(c3)); + Assert.That(provider2.History[0].Date, Is.EqualTo(new DateTime(2004, 01, 04))); + Assert.That(provider2.History[1].Date, Is.EqualTo(new DateTime(2003, 03, 01))); + }); } [Test] @@ -89,7 +95,7 @@ public void TestHistoryProvider_PersistByType() var provider = new HistoryProvider(RepositoryLocator); provider.Clear(); - Assert.IsEmpty(provider.History); + Assert.That(provider.History, Is.Empty); //these were viewed recently provider.History.Add(new HistoryEntry(c1, new DateTime(2001, 01, 01))); @@ -101,14 +107,20 @@ public void TestHistoryProvider_PersistByType() //persist only 1 entry (by Type) provider.Save(1); - Assert.AreEqual(2, provider.History.Count); + Assert.That(provider.History, Has.Count.EqualTo(2)); - Assert.AreEqual(c2, provider.History[0].Object); - Assert.AreEqual(lmd2, provider.History[1].Object); + Assert.Multiple(() => + { + Assert.That(provider.History[0].Object, Is.EqualTo(c2)); + Assert.That(provider.History[1].Object, Is.EqualTo(lmd2)); + }); var provider2 = new HistoryProvider(RepositoryLocator); - Assert.AreEqual(c2, provider2.History[0].Object); - Assert.AreEqual(lmd2, provider2.History[1].Object); + Assert.Multiple(() => + { + Assert.That(provider2.History[0].Object, Is.EqualTo(c2)); + Assert.That(provider2.History[1].Object, Is.EqualTo(lmd2)); + }); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/LogViewer/LoggingTabUITests.cs b/Rdmp.UI.Tests/LogViewer/LoggingTabUITests.cs index 585be692a1..a7bccacdb3 100644 --- a/Rdmp.UI.Tests/LogViewer/LoggingTabUITests.cs +++ b/Rdmp.UI.Tests/LogViewer/LoggingTabUITests.cs @@ -18,7 +18,7 @@ public void Test_LoggingTabUI_Constructor() { var o = WhenIHaveA(); var ui = AndLaunch(o); - Assert.IsNotNull(ui); + Assert.That(ui, Is.Not.Null); AssertErrorWasShown(ExpectedErrorType.KilledForm, "Database My Server did not exist"); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/Rdmp.UI.Tests.csproj b/Rdmp.UI.Tests/Rdmp.UI.Tests.csproj index 71361f2b4b..b0dd70cb99 100644 --- a/Rdmp.UI.Tests/Rdmp.UI.Tests.csproj +++ b/Rdmp.UI.Tests/Rdmp.UI.Tests.csproj @@ -16,9 +16,13 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -26,8 +30,7 @@ - + diff --git a/Rdmp.UI.Tests/TypeTextOrCancelDialogTests.cs b/Rdmp.UI.Tests/TypeTextOrCancelDialogTests.cs index f152cb6fcb..8c2ca01f64 100644 --- a/Rdmp.UI.Tests/TypeTextOrCancelDialogTests.cs +++ b/Rdmp.UI.Tests/TypeTextOrCancelDialogTests.cs @@ -21,13 +21,16 @@ public void Test_TypeTextOrCancelDialog_TinyStrings() //pretend like we launched it LastUserInterfaceLaunched = dlg; - //the title and body should be a reasonable length - Assert.AreEqual(1, dlg.Text.Length); - Assert.AreEqual(1, GetControl()[1].Text.Length); - - //dialog shouldn't go thinner than 540 or wider than 840 pixels - Assert.GreaterOrEqual(dlg.Width, 540); - Assert.LessOrEqual(dlg.Width, 840); + Assert.Multiple(() => + { + //the title and body should be a reasonable length + Assert.That(dlg.Text, Has.Length.EqualTo(1)); + Assert.That(GetControl()[1].Text, Has.Length.EqualTo(1)); + + //dialog shouldn't go thinner than 540 or wider than 840 pixels + Assert.That(dlg.Width, Is.GreaterThanOrEqualTo(540)); + }); + Assert.That(dlg.Width, Is.LessThanOrEqualTo(840)); } [Test] @@ -46,12 +49,15 @@ public void Test_TypeTextOrCancelDialog_LargeStrings() //pretend like we launched it LastUserInterfaceLaunched = dlg; - //the title and body should be a reasonable length - Assert.AreEqual(WideMessageBox.MAX_LENGTH_TITLE, dlg.Text.Length); - Assert.AreEqual(WideMessageBox.MAX_LENGTH_BODY, GetControl()[1].Text.Length); + Assert.Multiple(() => + { + //the title and body should be a reasonable length + Assert.That(dlg.Text, Has.Length.EqualTo(WideMessageBox.MAX_LENGTH_TITLE)); + Assert.That(GetControl()[1].Text, Has.Length.EqualTo(WideMessageBox.MAX_LENGTH_BODY)); - //dialog shouldn't go thinner than 540 or wider than 840 pixels - Assert.GreaterOrEqual(dlg.Width, 540); - Assert.LessOrEqual(dlg.Width, 840); + //dialog shouldn't go thinner than 540 or wider than 840 pixels + Assert.That(dlg.Width, Is.GreaterThanOrEqualTo(540)); + }); + Assert.That(dlg.Width, Is.LessThanOrEqualTo(840)); } } \ No newline at end of file diff --git a/Rdmp.UI.Tests/UITests.cs b/Rdmp.UI.Tests/UITests.cs index 5d697d8a8c..9e53bbc488 100644 --- a/Rdmp.UI.Tests/UITests.cs +++ b/Rdmp.UI.Tests/UITests.cs @@ -12,13 +12,11 @@ using System.Reflection; using System.Text; using System.Windows.Forms; -using MongoDB.Driver; using NUnit.Framework; using Rdmp.Core.CommandExecution.AtomicCommands; using Rdmp.Core.Curation.Data; using Rdmp.Core.Curation.Data.Spontaneous; using Rdmp.Core.ReusableLibraryCode.Checks; -using Rdmp.UI.Collections; using Rdmp.UI.CommandExecution; using Rdmp.UI.MainFormUITabs; using Rdmp.UI.Refreshing; @@ -51,7 +49,7 @@ private TestActivateItems InitializeItemActivator() /// 'Launches' a new instance of the UI defined by Type T which must be compatible with the provided . The UI will not /// visibly appear but will be mounted on a Form and generally should behave like live ones. /// - /// Method only tracks one set of results at once, so if you call this method more than once then expect old Errors to disapear. + /// Method only tracks one set of results at once, so if you call this method more than once then expect old Errors to disappear. /// /// /// @@ -59,7 +57,7 @@ private TestActivateItems InitializeItemActivator() /// will have to call it yourself /// /// Thrown when calling this method multiple times within a single test - public T AndLaunch(DatabaseEntity o, bool setDatabaseObject = true) + internal T AndLaunch(DatabaseEntity o, bool setDatabaseObject = true) where T : Control, IRDMPSingleDatabaseObjectControl, new() { var ui = new T(); @@ -70,15 +68,7 @@ public T AndLaunch(DatabaseEntity o, bool setDatabaseObject = true) } - public T AndLaunch() where T : RDMPCollectionUI, new() - { - var ui = new T(); - AndLaunch(ui); - ui.SetItemActivator(ItemActivator); - return ui; - } - - public void AndLaunch(Control ui) + internal void AndLaunch(Control ui) { //clear the old results ClearResults(); @@ -118,8 +108,11 @@ protected void ClearResults() /// The reason it should be impossible - uses StringAssert.Contains protected static void AssertCommandIsImpossible(IAtomicCommand cmd, string expectedReason) { - Assert.IsTrue(cmd.IsImpossible); - StringAssert.Contains(expectedReason, cmd.ReasonCommandImpossible); + Assert.Multiple(() => + { + Assert.That(cmd.IsImpossible); + Assert.That(cmd.ReasonCommandImpossible, Does.Contain(expectedReason)); + }); } /// @@ -172,24 +165,24 @@ protected void AssertNoErrors(ExpectedErrorType expectedErrorLevel = ExpectedErr switch (expectedErrorLevel) { case ExpectedErrorType.KilledForm: - Assert.IsEmpty(ItemActivator.Results.KilledForms); + Assert.That(ItemActivator.Results.KilledForms, Is.Empty); break; case ExpectedErrorType.Fatal: - Assert.IsEmpty(ItemActivator.Results.FatalCalls); + Assert.That(ItemActivator.Results.FatalCalls, Is.Empty); break; case ExpectedErrorType.FailedCheck: //there must have been something checked that failed with the provided message if (_checkResults != null) - Assert.IsEmpty(_checkResults.Messages.Where(m => m.Result == CheckResult.Fail)); + Assert.That(_checkResults.Messages.Where(static m => m.Result == CheckResult.Fail), Is.Empty); break; case ExpectedErrorType.ErrorProvider: - Assert.IsEmpty(GetAllErrorProviderErrorsShown()); + Assert.That(GetAllErrorProviderErrorsShown(), Is.Empty); break; case ExpectedErrorType.GlobalErrorCheckNotifier: - Assert.IsEmpty(((ToMemoryCheckNotifier)_itemActivator.GlobalErrorCheckNotifier).Messages); + Assert.That(((ToMemoryCheckNotifier)_itemActivator.GlobalErrorCheckNotifier).Messages, Is.Empty); break; @@ -217,13 +210,13 @@ protected void AssertErrorWasShown(ExpectedErrorType expectedErrorLevel, string switch (expectedErrorLevel) { case ExpectedErrorType.KilledForm: - Assert.IsTrue( + Assert.That( ItemActivator.Results.KilledForms.Values.Any(v => v.Message.Contains(expectedContainsText)), "Failed to find expected Exception, Exceptions were:\r\n" + string.Join(Environment.NewLine, ItemActivator.Results.KilledForms.Values.Select(v => v.ToString()))); break; case ExpectedErrorType.Fatal: - Assert.IsTrue(ItemActivator.Results.FatalCalls.Any(c => c.Message.Contains(expectedContainsText))); + Assert.That(ItemActivator.Results.FatalCalls.Any(c => c.Message.Contains(expectedContainsText))); break; case ExpectedErrorType.FailedCheck: @@ -240,7 +233,7 @@ protected void AssertErrorWasShown(ExpectedErrorType expectedErrorLevel, string break; case ExpectedErrorType.ErrorProvider: - Assert.IsTrue(GetAllErrorProviderErrorsShown().Any(m => m.Contains(expectedContainsText))); + Assert.That(GetAllErrorProviderErrorsShown().Any(m => m.Contains(expectedContainsText))); break; default: @@ -251,7 +244,7 @@ protected void AssertErrorWasShown(ExpectedErrorType expectedErrorLevel, string private static void AssertFailedCheck(ToMemoryCheckNotifier checkResults, string expectedContainsText) { //there must have been something checked that failed with the provided message - Assert.IsTrue(checkResults.Messages.Any(m => + Assert.That(checkResults.Messages.Any(m => m.Message.Contains(expectedContainsText) || (m.Ex != null && m.Ex.Message.Contains(expectedContainsText) && m.Result == CheckResult.Fail))); diff --git a/Rdmp.UI.Tests/UITimeoutAttribute.cs b/Rdmp.UI.Tests/UITimeoutAttribute.cs index ee9529212e..c5cbc7169f 100644 --- a/Rdmp.UI.Tests/UITimeoutAttribute.cs +++ b/Rdmp.UI.Tests/UITimeoutAttribute.cs @@ -9,7 +9,6 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; -using System.Threading.Tasks; using NUnit.Framework; using NUnit.Framework.Interfaces; using NUnit.Framework.Internal; diff --git a/Rdmp.UI.Tests/WideMessageBoxTests.cs b/Rdmp.UI.Tests/WideMessageBoxTests.cs index 80c3a5abab..8cab5d2a29 100644 --- a/Rdmp.UI.Tests/WideMessageBoxTests.cs +++ b/Rdmp.UI.Tests/WideMessageBoxTests.cs @@ -22,9 +22,12 @@ public void Test_WideMessageBox_TinyStrings() { var args = new WideMessageBoxArgs("1", "2", "3", "4", WideMessageBoxTheme.Help); - //it is important that the args retain the original length e.g. so user can copy to clipboard the text - Assert.AreEqual(1, args.Title.Length); - Assert.AreEqual(1, args.Message.Length); + Assert.Multiple(() => + { + //it is important that the args retain the original length e.g. so user can copy to clipboard the text + Assert.That(args.Title, Has.Length.EqualTo(1)); + Assert.That(args.Message, Has.Length.EqualTo(1)); + }); var wmb = new WideMessageBox(args); @@ -35,12 +38,15 @@ public void Test_WideMessageBox_TinyStrings() //pretend like we launched it LastUserInterfaceLaunched = wmb; - //the title and body should be a reasonable length - Assert.AreEqual(1, GetControl -public partial class RDMPCollectionCommonFunctionality : IRefreshBusSubscriber +public sealed class RDMPCollectionCommonFunctionality : IRefreshBusSubscriber { /// /// The collection if any that this represents in the UI @@ -153,7 +153,7 @@ public static void SetupColumnSortTracking(ObjectListView tree, Guid collectionG } //and track changes to the sort order - tree.AfterSorting += (s, e) => TreeOnAfterSorting(s, e, collectionGuid); + tree.AfterSorting += (_, e) => TreeOnAfterSorting(e, collectionGuid); } /// @@ -348,18 +348,16 @@ public static bool GetToolTip(IActivateItems activator, object model, out string private static string GetToolTipTitle(object model) => model is IMapsDirectlyToDatabaseTable d ? $"{model} (ID: {d.ID})" : model?.ToString(); - private static DateTime lastInvalidatedCache = DateTime.Now; - private static Dictionary cache = new(); + private static DateTime nextInvalidateCache = DateTime.Now.AddSeconds(10); + private static readonly Dictionary cache = new(); private static string GetToolTipBody(IActivateItems activator, ICanBeSummarised sum) { - if (DateTime.Now.Subtract(lastInvalidatedCache).TotalSeconds > 10) + if (DateTime.Now.CompareTo(nextInvalidateCache)>0) { cache.Clear(); - lastInvalidatedCache = DateTime.Now; - } - - if (cache.TryGetValue(sum, out var body)) + nextInvalidateCache = DateTime.Now.AddSeconds(10); + } else if (cache.TryGetValue(sum, out var body)) return body; var sb = new StringBuilder(); @@ -369,23 +367,26 @@ private static string GetToolTipBody(IActivateItems activator, ICanBeSummarised try { var associatedObjects = gotoF.GetCommands(sum).OfType() - .ToDictionary(cmd => cmd.GetCommandName(), cmd => cmd.GetObjects().Where(o => o != null)); + .ToDictionary(static cmd => cmd.GetCommandName(), static cmd => cmd.GetObjects().Where(static o => o != null)); - foreach (var kvp in associatedObjects) + foreach (var (key, value) in associatedObjects) { - if (!kvp.Value.Any()) - continue; - - var val = string.Join(", ", kvp.Value.Select(o => o.ToString()).ToArray()); - - if (val.Length > 100) val = $"{val[..100]}..."; + var val = string.Join(", ", value.Select(static o => o.ToString())); + switch (val.Length) + { + case 0: + continue; + case > 100: + val = $"{val[..100]}..."; + break; + } - sb.AppendLine($"{kvp.Key}: {val}"); + sb.AppendLine($"{key}: {val}"); } } catch (Exception) { - // couldn't get all the things you can go to, nevermind + // couldn't get all the things you can go to, never mind return sb.ToString(); } finally @@ -403,14 +404,14 @@ private void Tree_KeyDown(object sender, KeyEventArgs e) e.SuppressKeyPress = true; } - private void Tree_KeyPress(object sender, KeyPressEventArgs e) + private static void Tree_KeyPress(object sender, KeyPressEventArgs e) { //Prevents keyboard 'bong' sound occuring when using Enter to activate an object if (e.KeyChar == (char)Keys.Enter) e.Handled = true; } - private static void TreeOnAfterSorting(object sender, AfterSortingEventArgs e, Guid collectionGuid) + private static void TreeOnAfterSorting(AfterSortingEventArgs e, Guid collectionGuid) { UserSettings.SetLastColumnSortForCollection(collectionGuid, e.ColumnToSort?.Text, e.SortOrder == SortOrder.Ascending); @@ -443,7 +444,7 @@ private void Tree_FormatRow(object sender, FormatRowEventArgs e) { var hasProblems = _activator.HasProblem(e.Model); - if (e.Model is IDisableable { IsDisabled: true } disableable) + if (e.Model is IDisableable { IsDisabled: true }) { e.Item.ForeColor = Color.FromArgb(152, 152, 152); diff --git a/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandCreateNewDatasetUI.cs b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandCreateNewDatasetUI.cs new file mode 100644 index 0000000000..79db5b123d --- /dev/null +++ b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandCreateNewDatasetUI.cs @@ -0,0 +1,28 @@ +// Copyright (c) The University of Dundee 2018-2019 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using Rdmp.Core.CommandExecution.AtomicCommands; +using Rdmp.UI.ItemActivation; +using Rdmp.UI.SimpleDialogs.Datasets; + +namespace Rdmp.UI.CommandExecution.AtomicCommands; + +public class ExecuteCommandCreateNewDatasetUI : ExecuteCommandCreateDataset +{ + private readonly IActivateItems _activator; + + public ExecuteCommandCreateNewDatasetUI(IActivateItems activator) : base( + activator,"") + { + _activator = activator; + } + + public override void Execute() + { + var ui = new CreateNewDatasetUI(_activator, this); + ui.ShowDialog(); + } +} \ No newline at end of file diff --git a/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandDeleteDatasetUI.cs b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandDeleteDatasetUI.cs new file mode 100644 index 0000000000..90803cb3a3 --- /dev/null +++ b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandDeleteDatasetUI.cs @@ -0,0 +1,38 @@ +using Rdmp.Core.Curation.Data; +using Rdmp.Core.Icons.IconProvision; +using Rdmp.Core.ReusableLibraryCode.Icons.IconProvision; +using Rdmp.UI.ItemActivation; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; + +namespace Rdmp.UI.CommandExecution.AtomicCommands; + +public sealed class ExecuteCommandDeleteDatasetUI : BasicUICommandExecution +{ + private readonly IActivateItems _activateItems; + private readonly Dataset _dataset; + + public ExecuteCommandDeleteDatasetUI(IActivateItems activator, Dataset dataset) : base(activator) + { + _dataset = dataset; + _activateItems = activator; + } + + public override string GetCommandHelp() => + "Delete this dataset and remove all links to it within RDMP"; + + public override void Execute() + { + base.Execute(); + var confirmDelete = YesNo( $"Are you sure you want to delete the dataset \"{_dataset.Name}\"?", $"Delete Dataset: {_dataset.Name}"); + if (!confirmDelete) return; + + var cmd = new Core.CommandExecution.AtomicCommands.ExecuteCommandDeleteDataset(_activateItems, _dataset); + cmd.Execute(); + _activateItems.RefreshBus.Publish(this, new Refreshing.RefreshObjectEventArgs(_dataset)); + } + + + public override Image GetImage(IIconProvider iconProvider) => + iconProvider.GetImage(RDMPConcept.Dataset, OverlayKind.Delete); +} diff --git a/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandDeletePlugin.cs b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandDeletePlugin.cs new file mode 100644 index 0000000000..f57f67de6d --- /dev/null +++ b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandDeletePlugin.cs @@ -0,0 +1,44 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using Rdmp.Core.Curation.Data; +using Rdmp.Core.Icons.IconProvision; +using Rdmp.Core.ReusableLibraryCode.Icons.IconProvision; +using Rdmp.UI.ItemActivation; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using System; +namespace Rdmp.UI.CommandExecution.AtomicCommands; + +public class ExecuteCommandDeletePlugin : BasicUICommandExecution +{ + private readonly LoadModuleAssembly _assembly; + public ExecuteCommandDeletePlugin(IActivateItems activator, LoadModuleAssembly assembly) : base(activator) + { + _assembly = assembly; + } + + public override Image GetImage(IIconProvider iconProvider) => + iconProvider.GetImage(RDMPConcept.Plugin, OverlayKind.Delete); + + public override void Execute() + { + base.Execute(); + if (YesNo($"Are you sure you want to delete {_assembly}?", "Delete Plugin")) + { + _assembly.Delete(); + try + { + _assembly.Delete(); + Show("Changes will take effect on restart"); + } + catch (SystemException ex) + { + Show($"Could not delete the {_assembly} plugin.", ex); + } + } + } +} \ No newline at end of file diff --git a/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandLinkCatalogueToDatasetUI.cs b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandLinkCatalogueToDatasetUI.cs new file mode 100644 index 0000000000..d0b99eb69d --- /dev/null +++ b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandLinkCatalogueToDatasetUI.cs @@ -0,0 +1,54 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using Rdmp.Core.CommandExecution; +using Rdmp.Core.CommandExecution.AtomicCommands; +using Rdmp.Core.Curation.Data; +using Rdmp.Core.Icons.IconProvision; +using Rdmp.Core.ReusableLibraryCode.Annotations; +using Rdmp.Core.ReusableLibraryCode.Icons.IconProvision; +using Rdmp.UI.ItemActivation; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; + +namespace Rdmp.UI.CommandExecution.AtomicCommands; + +public sealed class ExecuteCommandLinkCatalogueToDatasetUI : BasicUICommandExecution +{ + private readonly Catalogue _catalogue; + private Dataset _selectedDataset; + private readonly IActivateItems _activateItems; + + public ExecuteCommandLinkCatalogueToDatasetUI(IActivateItems activator, Catalogue catalogue) : base(activator) + { + _catalogue = catalogue; + _activateItems = activator; + } + + public override string GetCommandHelp() => + "Link all columns of this catalogue to a dataset"; + + public override void Execute() + { + base.Execute(); + var datasets = _activateItems.RepositoryLocator.CatalogueRepository.GetAllObjects(); + DialogArgs da = new() + { + WindowTitle = "Link a dataset with this catalogue", + TaskDescription = + "Select the Dataset that this catalogue information came from" + }; + _selectedDataset = SelectOne(da, datasets); + if (_selectedDataset is null) return; + + var backfill = YesNo("Link all other columns that match the source table?", "Do you want to link this dataset to all other columns that reference the same table as this column?"); + var cmd = new ExecuteCommandLinkCatalogueToDataset(_activateItems, _catalogue, _selectedDataset, backfill); + cmd.Execute(); + } + + public override Image GetImage([NotNull] IIconProvider iconProvider) => + iconProvider.GetImage(RDMPConcept.Dataset, OverlayKind.Link); +} \ No newline at end of file diff --git a/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandLinkColumnInfoToDataSetUI.cs b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandLinkColumnInfoToDataSetUI.cs new file mode 100644 index 0000000000..d59809fc9e --- /dev/null +++ b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandLinkColumnInfoToDataSetUI.cs @@ -0,0 +1,54 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using Rdmp.Core.CommandExecution; +using Rdmp.Core.CommandExecution.AtomicCommands; +using Rdmp.Core.Curation.Data; +using Rdmp.Core.Icons.IconProvision; +using Rdmp.Core.ReusableLibraryCode.Annotations; +using Rdmp.Core.ReusableLibraryCode.Icons.IconProvision; +using Rdmp.UI.ItemActivation; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; + +namespace Rdmp.UI.CommandExecution.AtomicCommands; + +public sealed class ExecuteCommandLinkColumnInfoToDataSetUI : BasicUICommandExecution +{ + private readonly ColumnInfo _columnInfo; + private Dataset _selectedDataset; + private readonly IActivateItems _activateItems; + + public ExecuteCommandLinkColumnInfoToDataSetUI(IActivateItems activator, ColumnInfo columnInfo) : base(activator) + { + _columnInfo = columnInfo; + _activateItems = activator; + } + + [NotNull] + public override string GetCommandHelp() => + "Link this column to an existing dataset"; + + public override void Execute() + { + base.Execute(); + var datasets = _activateItems.RepositoryLocator.CatalogueRepository.GetAllObjects(); + DialogArgs da = new() + { + WindowTitle = "Link a dataset with this column", + TaskDescription = + "Select the Dataset that this column information came from" + }; + _selectedDataset = SelectOne(da, datasets); + var backfill = YesNo("Link all other columns that match the source table?","Do you want to link this dataset to all other columns that reference the same table as this column?"); + var cmd = new ExecuteCommandLinkColumnInfoToDataset(_activateItems,_columnInfo, _selectedDataset,backfill); + cmd.Execute(); + + } + + public override Image GetImage([NotNull] IIconProvider iconProvider) => + iconProvider.GetImage(RDMPConcept.Dataset, OverlayKind.Link); +} \ No newline at end of file diff --git a/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandOpenExtractionDirectory.cs b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandOpenExtractionDirectory.cs index 5281b48a7c..10936e4cf2 100644 --- a/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandOpenExtractionDirectory.cs +++ b/Rdmp.UI/CommandExecution/AtomicCommands/ExecuteCommandOpenExtractionDirectory.cs @@ -73,13 +73,13 @@ public ExecuteCommandOpenExtractionDirectory(IActivateItems activator, IExtracti // all datasets have been extracted to disk // but do they have a shared parent dir? - var files = cumulativeExtractionResults.Select(c => new FileInfo(c.DestinationDescription)).ToArray(); + var files = cumulativeExtractionResults.Select(static c => new FileInfo(c.DestinationDescription)).ToArray(); - var parents = files.Select(f => f.Directory?.Parent?.FullName).Where(d => d != null).Distinct() + var parents = files.Select(static f => f.Directory?.Parent?.FullName).Where(static d => d != null).Distinct() .ToArray(); if (parents.Length != 1) - SetImpossible($"Extracted files do not share a common extraction directory"); + SetImpossible("Extracted files do not share a common extraction directory"); else _dir = new DirectoryInfo(parents[0]); } diff --git a/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsDataset.cs b/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsDataset.cs new file mode 100644 index 0000000000..7bc681d63e --- /dev/null +++ b/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsDataset.cs @@ -0,0 +1,36 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using Rdmp.Core.CommandExecution; +using Rdmp.Core.Curation.Data; +using Rdmp.Core.ReusableLibraryCode.Annotations; +using Rdmp.UI.ItemActivation; +using Rdmp.UI.SubComponents; + +namespace Rdmp.UI.CommandExecution.Proposals; + +internal class + ProposeExecutionWhenTargetIsDataset : RDMPCommandExecutionProposal< + Dataset> +{ + public ProposeExecutionWhenTargetIsDataset(IActivateItems itemActivator) : base( + itemActivator) + { + } + + public override bool CanActivate(Dataset target) => true; + + public override void Activate(Dataset target) + { + ItemActivator.Activate(target); + } + + [CanBeNull] + public override ICommandExecution ProposeExecution(ICombineToMakeCommand cmd, + Dataset target, + InsertOption insertOption = InsertOption.Default) => + null; +} \ No newline at end of file diff --git a/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsLoadStageNode.cs b/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsLoadStageNode.cs index 2db97d090c..d3507f524c 100644 --- a/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsLoadStageNode.cs +++ b/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsLoadStageNode.cs @@ -30,7 +30,7 @@ public override ICommandExecution ProposeExecution(ICombineToMakeCommand cmd, Lo InsertOption insertOption = InsertOption.Default) { var sourceFileTaskCommand = cmd as FileCollectionCombineable; - + if (cmd is ProcessTaskCombineable sourceProcessTaskCommand) return new ExecuteCommandChangeLoadStage(ItemActivator, sourceProcessTaskCommand, targetStage); @@ -42,6 +42,9 @@ public override ICommandExecution ProposeExecution(ICombineToMakeCommand cmd, Lo case ".sql": return new ExecuteCommandCreateNewFileBasedProcessTask(ItemActivator, ProcessTaskType.SQLFile, targetStage.LoadMetadata, targetStage.LoadStage, f); + case ".bak": + return new ExecuteCommandCreateNewFileBasedProcessTask(ItemActivator, ProcessTaskType.SQLBakFile, + targetStage.LoadMetadata, targetStage.LoadStage, f); case ".exe": return new ExecuteCommandCreateNewFileBasedProcessTask(ItemActivator, ProcessTaskType.Executable, targetStage.LoadMetadata, targetStage.LoadStage, f); diff --git a/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsProcessTask.cs b/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsProcessTask.cs index 762e13eec4..74c0735dcf 100644 --- a/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsProcessTask.cs +++ b/Rdmp.UI/CommandExecution/Proposals/ProposeExecutionWhenTargetIsProcessTask.cs @@ -32,6 +32,9 @@ public override void Activate(ProcessTask processTask) case ProcessTaskType.SQLFile: ItemActivator.Activate(processTask); break; + case ProcessTaskType.SQLBakFile: + ItemActivator.Activate(processTask); + break; } } diff --git a/Rdmp.UI/DataLoadUIs/LoadMetadataUIs/LoadDiagram/LoadDiagramUI.cs b/Rdmp.UI/DataLoadUIs/LoadMetadataUIs/LoadDiagram/LoadDiagramUI.cs index ca5a76ee1f..ed58abf45f 100644 --- a/Rdmp.UI/DataLoadUIs/LoadMetadataUIs/LoadDiagram/LoadDiagramUI.cs +++ b/Rdmp.UI/DataLoadUIs/LoadMetadataUIs/LoadDiagram/LoadDiagramUI.cs @@ -19,6 +19,7 @@ using Rdmp.Core.DataLoad.Engine.DatabaseManagement.EntityNaming; using Rdmp.Core.DataViewing; using Rdmp.Core.Icons.IconProvision; +using Rdmp.Core.ReusableLibraryCode.Annotations; using Rdmp.Core.ReusableLibraryCode.Icons.IconProvision; using Rdmp.UI.Collections; using Rdmp.UI.Collections.Providers.Copying; @@ -128,29 +129,28 @@ private void tlvLoadedTables_FormatCell(object sender, FormatCellEventArgs e) : Color.LightGray, LoadDiagramState.Different => Color.Red, LoadDiagramState.New => Color.Red, - _ => throw new ArgumentOutOfRangeException() + _ => throw new ArgumentOutOfRangeException(nameof(e),$"Invalid state for LoadDiagramState {state}") }; } - private object olvState_AspectGetter(object rowobject) - { - return rowobject switch + [CanBeNull] + private static object olvState_AspectGetter(object rowObject) => + rowObject switch { DiscoveredTable or DiscoveredColumn => LoadDiagramState.New, IHasLoadDiagramState stateHaver => stateHaver.State, _ => null }; - } - private object olvDataType_AspectGetter(object rowobject) - { - return rowobject switch + [CanBeNull] + private static object olvDataType_AspectGetter(object rowObject) => + rowObject switch { LoadDiagramColumnNode colNode => colNode.GetDataType(), DiscoveredColumn discCol => discCol.DataType.SQLType, _ => null }; - } + private string CellToolTipGetter(OLVColumn column, object modelObject) => modelObject is LoadDiagramServerNode loadDiagramServerNode ? loadDiagramServerNode.ErrorDescription diff --git a/Rdmp.UI/DataLoadUIs/LoadMetadataUIs/LoadProgressAndCacheUIs/Diagrams/LoadProgressDiagramUI.cs b/Rdmp.UI/DataLoadUIs/LoadMetadataUIs/LoadProgressAndCacheUIs/Diagrams/LoadProgressDiagramUI.cs index aa53b1b6a7..2452ee565f 100644 --- a/Rdmp.UI/DataLoadUIs/LoadMetadataUIs/LoadProgressAndCacheUIs/Diagrams/LoadProgressDiagramUI.cs +++ b/Rdmp.UI/DataLoadUIs/LoadMetadataUIs/LoadProgressAndCacheUIs/Diagrams/LoadProgressDiagramUI.cs @@ -11,6 +11,7 @@ using BrightIdeasSoftware; using Rdmp.Core.Curation.Data; using Rdmp.Core.DataQualityEngine.Reports; +using Rdmp.Core.ReusableLibraryCode.Annotations; using Rdmp.UI.CommandExecution.AtomicCommands; using Rdmp.UI.ItemActivation; using Rdmp.UI.TestsAndSetup.ServicePropogation; @@ -52,13 +53,13 @@ private void olvDQERuns_ButtonClick(object sender, CellClickEventArgs e) new ExecuteCommandRunDQEOnCatalogue(Activator).SetTarget(c).Execute(); } + [NotNull] private object AspectGetterLastDQERun(object rowObject) { - var c = (Catalogue)rowObject; + if (rowObject is not Catalogue c) return "Not a catalogue"; - return !_report.CataloguesWithDQERuns.ContainsKey(c) - ? "Never" - : _report.CataloguesWithDQERuns[c].DateOfEvaluation; + return !_report.CataloguesWithDQERuns.TryGetValue(c, out var value) ? "Never" + : value.DateOfEvaluation; } public void SetLoadProgress(LoadProgress lp, IActivateItems activator) diff --git a/Rdmp.UI/ExtractionUIs/FilterUIs/ParameterUIs/ParameterCollectionUI.cs b/Rdmp.UI/ExtractionUIs/FilterUIs/ParameterUIs/ParameterCollectionUI.cs index 41f977a79c..b6a7cd3c86 100644 --- a/Rdmp.UI/ExtractionUIs/FilterUIs/ParameterUIs/ParameterCollectionUI.cs +++ b/Rdmp.UI/ExtractionUIs/FilterUIs/ParameterUIs/ParameterCollectionUI.cs @@ -230,18 +230,14 @@ public void SetUp(ParameterCollectionUIOptions options, IActivateItems activator private void miAddParameter_Click(object sender, EventArgs e) { var r = new Random(); + using var dialog = new TypeTextOrCancelDialog("Parameter Name", "Name", 100, $"@MyParam{r.Next()}"); + if (dialog.ShowDialog() != DialogResult.OK) return; -#pragma warning disable SCS0005 // Weak random generator: This is only used to create an initial value for a parameter. - var dialog = new TypeTextOrCancelDialog("Parameter Name", "Name", 100, $"@MyParam{r.Next()}"); -#pragma warning restore SCS0005 // Weak random generator - if (dialog.ShowDialog() == DialogResult.OK) - { - var newParameter = Options.CreateNewParameter(dialog.ResultText.Trim()); + var newParameter = Options.CreateNewParameter(dialog.ResultText.Trim()); - Options.ParameterManager.ParametersFoundSoFarInQueryGeneration[Options.CurrentLevel].Add(newParameter); + Options.ParameterManager.ParametersFoundSoFarInQueryGeneration[Options.CurrentLevel].Add(newParameter); - RefreshParametersFromDatabase(); - } + RefreshParametersFromDatabase(); } private void olvParameters_KeyDown(object sender, KeyEventArgs e) diff --git a/Rdmp.UI/ExtractionUIs/JoinsAndLookups/LookupConfigurationUI.cs b/Rdmp.UI/ExtractionUIs/JoinsAndLookups/LookupConfigurationUI.cs index b965eae4d2..094a9627d5 100644 --- a/Rdmp.UI/ExtractionUIs/JoinsAndLookups/LookupConfigurationUI.cs +++ b/Rdmp.UI/ExtractionUIs/JoinsAndLookups/LookupConfigurationUI.cs @@ -233,7 +233,7 @@ private void LookupConfiguration_Paint(object sender, PaintEventArgs e) LookupCreationStage.DragAPrimaryKey => 2, LookupCreationStage.DragAForeignKey => 3, LookupCreationStage.DragADescription => 4, - _ => throw new ArgumentOutOfRangeException() + _ => throw new InvalidOperationException() }; DrawArrows(e.Graphics); diff --git a/Rdmp.UI/MainFormUITabs/CatalogueItemUI.Designer.cs b/Rdmp.UI/MainFormUITabs/CatalogueItemUI.Designer.cs index 9b50ab9c65..8effa716c1 100644 --- a/Rdmp.UI/MainFormUITabs/CatalogueItemUI.Designer.cs +++ b/Rdmp.UI/MainFormUITabs/CatalogueItemUI.Designer.cs @@ -28,377 +28,386 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.ci_tbID = new System.Windows.Forms.TextBox(); - this.label28 = new System.Windows.Forms.Label(); - this.label27 = new System.Windows.Forms.Label(); - this.label26 = new System.Windows.Forms.Label(); - this.ci_tbComments = new System.Windows.Forms.TextBox(); - this.label30 = new System.Windows.Forms.Label(); - this.ci_tbLimitations = new System.Windows.Forms.TextBox(); - this.label31 = new System.Windows.Forms.Label(); - this.ci_tbTopics = new System.Windows.Forms.TextBox(); - this.label32 = new System.Windows.Forms.Label(); - this.ci_tbAggregationMethod = new System.Windows.Forms.TextBox(); - this.label33 = new System.Windows.Forms.Label(); - this.label34 = new System.Windows.Forms.Label(); - this.ci_tbResearchRelevance = new System.Windows.Forms.TextBox(); - this.ci_ddPeriodicity = new System.Windows.Forms.ComboBox(); - this.ci_tbStatisticalConsiderations = new System.Windows.Forms.TextBox(); - this.label35 = new System.Windows.Forms.Label(); - this.label36 = new System.Windows.Forms.Label(); - this.ci_tbName = new System.Windows.Forms.TextBox(); - this.splitContainer1 = new System.Windows.Forms.SplitContainer(); - this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); - this.panel1 = new System.Windows.Forms.Panel(); - this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); - ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); - this.splitContainer1.Panel1.SuspendLayout(); - this.splitContainer1.Panel2.SuspendLayout(); - this.splitContainer1.SuspendLayout(); - this.tableLayoutPanel1.SuspendLayout(); - this.tableLayoutPanel2.SuspendLayout(); - this.SuspendLayout(); + ci_tbID = new System.Windows.Forms.TextBox(); + label28 = new System.Windows.Forms.Label(); + label27 = new System.Windows.Forms.Label(); + label26 = new System.Windows.Forms.Label(); + ci_tbComments = new System.Windows.Forms.TextBox(); + label30 = new System.Windows.Forms.Label(); + ci_tbLimitations = new System.Windows.Forms.TextBox(); + label31 = new System.Windows.Forms.Label(); + ci_tbTopics = new System.Windows.Forms.TextBox(); + label32 = new System.Windows.Forms.Label(); + ci_tbAggregationMethod = new System.Windows.Forms.TextBox(); + label33 = new System.Windows.Forms.Label(); + label34 = new System.Windows.Forms.Label(); + ci_tbResearchRelevance = new System.Windows.Forms.TextBox(); + ci_ddPeriodicity = new System.Windows.Forms.ComboBox(); + ci_tbStatisticalConsiderations = new System.Windows.Forms.TextBox(); + label35 = new System.Windows.Forms.Label(); + label36 = new System.Windows.Forms.Label(); + ci_tbName = new System.Windows.Forms.TextBox(); + splitContainer1 = new System.Windows.Forms.SplitContainer(); + tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + panel1 = new System.Windows.Forms.Panel(); + lbDataset = new System.Windows.Forms.Label(); + lbDatasetValue = new System.Windows.Forms.Label(); + tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); + splitContainer1.Panel1.SuspendLayout(); + splitContainer1.Panel2.SuspendLayout(); + splitContainer1.SuspendLayout(); + tableLayoutPanel1.SuspendLayout(); + tableLayoutPanel2.SuspendLayout(); + SuspendLayout(); // // ci_tbID // - this.ci_tbID.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.ci_tbID.Location = new System.Drawing.Point(117, 3); - this.ci_tbID.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.ci_tbID.Name = "ci_tbID"; - this.ci_tbID.ReadOnly = true; - this.ci_tbID.Size = new System.Drawing.Size(302, 23); - this.ci_tbID.TabIndex = 137; + ci_tbID.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + ci_tbID.Location = new System.Drawing.Point(117, 3); + ci_tbID.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); + ci_tbID.Name = "ci_tbID"; + ci_tbID.ReadOnly = true; + ci_tbID.Size = new System.Drawing.Size(302, 23); + ci_tbID.TabIndex = 137; // // label28 // - this.label28.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label28.AutoSize = true; - this.label28.Location = new System.Drawing.Point(4, 7); - this.label28.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label28.Name = "label28"; - this.label28.Size = new System.Drawing.Size(105, 15); - this.label28.TabIndex = 147; - this.label28.Text = "Catalogue Item ID:"; - this.label28.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label28.Anchor = System.Windows.Forms.AnchorStyles.Right; + label28.AutoSize = true; + label28.Location = new System.Drawing.Point(4, 7); + label28.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label28.Name = "label28"; + label28.Size = new System.Drawing.Size(105, 15); + label28.TabIndex = 147; + label28.Text = "Catalogue Item ID:"; + label28.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label27 // - this.label27.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label27.AutoSize = true; - this.label27.Location = new System.Drawing.Point(15, 0); - this.label27.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label27.Name = "label27"; - this.label27.Size = new System.Drawing.Size(105, 30); - this.label27.TabIndex = 148; - this.label27.Text = "Statistical Concept\r\nand Methodology:"; - this.label27.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label27.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; + label27.AutoSize = true; + label27.Location = new System.Drawing.Point(15, 0); + label27.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label27.Name = "label27"; + label27.Size = new System.Drawing.Size(105, 30); + label27.TabIndex = 148; + label27.Text = "Statistical Concept\r\nand Methodology:"; + label27.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label26 // - this.label26.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label26.AutoSize = true; - this.label26.Location = new System.Drawing.Point(67, 36); - this.label26.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label26.Name = "label26"; - this.label26.Size = new System.Drawing.Size(42, 15); - this.label26.TabIndex = 149; - this.label26.Text = "Name:"; - this.label26.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label26.Anchor = System.Windows.Forms.AnchorStyles.Right; + label26.AutoSize = true; + label26.Location = new System.Drawing.Point(67, 36); + label26.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label26.Name = "label26"; + label26.Size = new System.Drawing.Size(42, 15); + label26.TabIndex = 149; + label26.Text = "Name:"; + label26.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // ci_tbComments // - this.ci_tbComments.AcceptsReturn = true; - this.ci_tbComments.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.ci_tbComments.Location = new System.Drawing.Point(128, 485); - this.ci_tbComments.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.ci_tbComments.Multiline = true; - this.ci_tbComments.Name = "ci_tbComments"; - this.ci_tbComments.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.ci_tbComments.Size = new System.Drawing.Size(287, 102); - this.ci_tbComments.TabIndex = 146; + ci_tbComments.AcceptsReturn = true; + ci_tbComments.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + ci_tbComments.Location = new System.Drawing.Point(128, 485); + ci_tbComments.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + ci_tbComments.Multiline = true; + ci_tbComments.Name = "ci_tbComments"; + ci_tbComments.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + ci_tbComments.Size = new System.Drawing.Size(287, 152); + ci_tbComments.TabIndex = 146; // // label30 // - this.label30.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label30.AutoSize = true; - this.label30.Location = new System.Drawing.Point(7, 106); - this.label30.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label30.Name = "label30"; - this.label30.Size = new System.Drawing.Size(113, 15); - this.label30.TabIndex = 150; - this.label30.Text = "Research Relevance:"; - this.label30.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label30.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; + label30.AutoSize = true; + label30.Location = new System.Drawing.Point(7, 106); + label30.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label30.Name = "label30"; + label30.Size = new System.Drawing.Size(113, 15); + label30.TabIndex = 150; + label30.Text = "Research Relevance:"; + label30.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // ci_tbLimitations // - this.ci_tbLimitations.AcceptsReturn = true; - this.ci_tbLimitations.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.ci_tbLimitations.Location = new System.Drawing.Point(128, 379); - this.ci_tbLimitations.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.ci_tbLimitations.Multiline = true; - this.ci_tbLimitations.Name = "ci_tbLimitations"; - this.ci_tbLimitations.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.ci_tbLimitations.Size = new System.Drawing.Size(287, 100); - this.ci_tbLimitations.TabIndex = 145; + ci_tbLimitations.AcceptsReturn = true; + ci_tbLimitations.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + ci_tbLimitations.Location = new System.Drawing.Point(128, 379); + ci_tbLimitations.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + ci_tbLimitations.Multiline = true; + ci_tbLimitations.Name = "ci_tbLimitations"; + ci_tbLimitations.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + ci_tbLimitations.Size = new System.Drawing.Size(287, 100); + ci_tbLimitations.TabIndex = 145; // // label31 // - this.label31.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label31.AutoSize = true; - this.label31.Location = new System.Drawing.Point(39, 58); - this.label31.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label31.Name = "label31"; - this.label31.Size = new System.Drawing.Size(70, 15); - this.label31.TabIndex = 151; - this.label31.Text = "Description:"; - this.label31.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label31.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; + label31.AutoSize = true; + label31.Location = new System.Drawing.Point(39, 58); + label31.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label31.Name = "label31"; + label31.Size = new System.Drawing.Size(70, 15); + label31.TabIndex = 151; + label31.Text = "Description:"; + label31.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // ci_tbTopics // - this.ci_tbTopics.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.ci_tbTopics.Location = new System.Drawing.Point(128, 215); - this.ci_tbTopics.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.ci_tbTopics.Name = "ci_tbTopics"; - this.ci_tbTopics.Size = new System.Drawing.Size(287, 23); - this.ci_tbTopics.TabIndex = 142; + ci_tbTopics.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + ci_tbTopics.Location = new System.Drawing.Point(128, 215); + ci_tbTopics.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + ci_tbTopics.Name = "ci_tbTopics"; + ci_tbTopics.Size = new System.Drawing.Size(287, 23); + ci_tbTopics.TabIndex = 142; // // label32 // - this.label32.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label32.AutoSize = true; - this.label32.Location = new System.Drawing.Point(4, 270); - this.label32.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label32.Name = "label32"; - this.label32.Size = new System.Drawing.Size(116, 30); - this.label32.TabIndex = 152; - this.label32.Text = "Aggregation\r\nProcessPipelineData:"; - this.label32.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label32.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; + label32.AutoSize = true; + label32.Location = new System.Drawing.Point(4, 270); + label32.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label32.Name = "label32"; + label32.Size = new System.Drawing.Size(116, 30); + label32.TabIndex = 152; + label32.Text = "Aggregation\r\nProcessPipelineData:"; + label32.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // ci_tbAggregationMethod // - this.ci_tbAggregationMethod.AcceptsReturn = true; - this.ci_tbAggregationMethod.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.ci_tbAggregationMethod.Location = new System.Drawing.Point(128, 273); - this.ci_tbAggregationMethod.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.ci_tbAggregationMethod.Multiline = true; - this.ci_tbAggregationMethod.Name = "ci_tbAggregationMethod"; - this.ci_tbAggregationMethod.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.ci_tbAggregationMethod.Size = new System.Drawing.Size(287, 100); - this.ci_tbAggregationMethod.TabIndex = 144; + ci_tbAggregationMethod.AcceptsReturn = true; + ci_tbAggregationMethod.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + ci_tbAggregationMethod.Location = new System.Drawing.Point(128, 273); + ci_tbAggregationMethod.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + ci_tbAggregationMethod.Multiline = true; + ci_tbAggregationMethod.Name = "ci_tbAggregationMethod"; + ci_tbAggregationMethod.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + ci_tbAggregationMethod.Size = new System.Drawing.Size(287, 100); + ci_tbAggregationMethod.TabIndex = 144; // // label33 // - this.label33.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label33.AutoSize = true; - this.label33.Location = new System.Drawing.Point(82, 219); - this.label33.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label33.Name = "label33"; - this.label33.Size = new System.Drawing.Size(38, 15); - this.label33.TabIndex = 153; - this.label33.Text = "Topic:"; - this.label33.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label33.Anchor = System.Windows.Forms.AnchorStyles.Right; + label33.AutoSize = true; + label33.Location = new System.Drawing.Point(82, 219); + label33.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label33.Name = "label33"; + label33.Size = new System.Drawing.Size(38, 15); + label33.TabIndex = 153; + label33.Text = "Topic:"; + label33.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label34 // - this.label34.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label34.AutoSize = true; - this.label34.Location = new System.Drawing.Point(54, 248); - this.label34.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label34.Name = "label34"; - this.label34.Size = new System.Drawing.Size(66, 15); - this.label34.TabIndex = 154; - this.label34.Text = "Periodicity:"; - this.label34.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label34.Anchor = System.Windows.Forms.AnchorStyles.Right; + label34.AutoSize = true; + label34.Location = new System.Drawing.Point(54, 248); + label34.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label34.Name = "label34"; + label34.Size = new System.Drawing.Size(66, 15); + label34.TabIndex = 154; + label34.Text = "Periodicity:"; + label34.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // ci_tbResearchRelevance // - this.ci_tbResearchRelevance.AcceptsReturn = true; - this.ci_tbResearchRelevance.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.ci_tbResearchRelevance.Location = new System.Drawing.Point(128, 109); - this.ci_tbResearchRelevance.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.ci_tbResearchRelevance.Multiline = true; - this.ci_tbResearchRelevance.Name = "ci_tbResearchRelevance"; - this.ci_tbResearchRelevance.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.ci_tbResearchRelevance.Size = new System.Drawing.Size(287, 100); - this.ci_tbResearchRelevance.TabIndex = 141; + ci_tbResearchRelevance.AcceptsReturn = true; + ci_tbResearchRelevance.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + ci_tbResearchRelevance.Location = new System.Drawing.Point(128, 109); + ci_tbResearchRelevance.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + ci_tbResearchRelevance.Multiline = true; + ci_tbResearchRelevance.Name = "ci_tbResearchRelevance"; + ci_tbResearchRelevance.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + ci_tbResearchRelevance.Size = new System.Drawing.Size(287, 100); + ci_tbResearchRelevance.TabIndex = 141; // // ci_ddPeriodicity // - this.ci_ddPeriodicity.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.ci_ddPeriodicity.FormattingEnabled = true; - this.ci_ddPeriodicity.Location = new System.Drawing.Point(128, 244); - this.ci_ddPeriodicity.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.ci_ddPeriodicity.Name = "ci_ddPeriodicity"; - this.ci_ddPeriodicity.Size = new System.Drawing.Size(250, 23); - this.ci_ddPeriodicity.TabIndex = 143; + ci_ddPeriodicity.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + ci_ddPeriodicity.FormattingEnabled = true; + ci_ddPeriodicity.Location = new System.Drawing.Point(128, 244); + ci_ddPeriodicity.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + ci_ddPeriodicity.Name = "ci_ddPeriodicity"; + ci_ddPeriodicity.Size = new System.Drawing.Size(250, 23); + ci_ddPeriodicity.TabIndex = 143; // // ci_tbStatisticalConsiderations // - this.ci_tbStatisticalConsiderations.AcceptsReturn = true; - this.ci_tbStatisticalConsiderations.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.ci_tbStatisticalConsiderations.Location = new System.Drawing.Point(128, 3); - this.ci_tbStatisticalConsiderations.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.ci_tbStatisticalConsiderations.Multiline = true; - this.ci_tbStatisticalConsiderations.Name = "ci_tbStatisticalConsiderations"; - this.ci_tbStatisticalConsiderations.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.ci_tbStatisticalConsiderations.Size = new System.Drawing.Size(287, 100); - this.ci_tbStatisticalConsiderations.TabIndex = 140; + ci_tbStatisticalConsiderations.AcceptsReturn = true; + ci_tbStatisticalConsiderations.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + ci_tbStatisticalConsiderations.Location = new System.Drawing.Point(128, 3); + ci_tbStatisticalConsiderations.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + ci_tbStatisticalConsiderations.Multiline = true; + ci_tbStatisticalConsiderations.Name = "ci_tbStatisticalConsiderations"; + ci_tbStatisticalConsiderations.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + ci_tbStatisticalConsiderations.Size = new System.Drawing.Size(287, 100); + ci_tbStatisticalConsiderations.TabIndex = 140; // // label35 // - this.label35.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label35.AutoSize = true; - this.label35.Location = new System.Drawing.Point(51, 376); - this.label35.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label35.Name = "label35"; - this.label35.Size = new System.Drawing.Size(69, 15); - this.label35.TabIndex = 155; - this.label35.Text = "Limitations:"; - this.label35.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label35.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; + label35.AutoSize = true; + label35.Location = new System.Drawing.Point(51, 376); + label35.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label35.Name = "label35"; + label35.Size = new System.Drawing.Size(69, 15); + label35.TabIndex = 155; + label35.Text = "Limitations:"; + label35.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label36 // - this.label36.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label36.AutoSize = true; - this.label36.Location = new System.Drawing.Point(51, 482); - this.label36.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label36.Name = "label36"; - this.label36.Size = new System.Drawing.Size(69, 15); - this.label36.TabIndex = 156; - this.label36.Text = "Comments:"; - this.label36.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label36.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; + label36.AutoSize = true; + label36.Location = new System.Drawing.Point(51, 482); + label36.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + label36.Name = "label36"; + label36.Size = new System.Drawing.Size(69, 15); + label36.TabIndex = 156; + label36.Text = "Comments:"; + label36.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // ci_tbName // - this.ci_tbName.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.ci_tbName.Location = new System.Drawing.Point(117, 32); - this.ci_tbName.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.ci_tbName.Name = "ci_tbName"; - this.ci_tbName.Size = new System.Drawing.Size(302, 23); - this.ci_tbName.TabIndex = 138; + ci_tbName.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + ci_tbName.Location = new System.Drawing.Point(117, 32); + ci_tbName.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); + ci_tbName.Name = "ci_tbName"; + ci_tbName.Size = new System.Drawing.Size(302, 23); + ci_tbName.TabIndex = 138; // // splitContainer1 // - this.splitContainer1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; - this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; - this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1; - this.splitContainer1.Location = new System.Drawing.Point(0, 0); - this.splitContainer1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.splitContainer1.Name = "splitContainer1"; - this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; + splitContainer1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1; + splitContainer1.Location = new System.Drawing.Point(0, 0); + splitContainer1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + splitContainer1.Name = "splitContainer1"; + splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; // // splitContainer1.Panel1 // - this.splitContainer1.Panel1.Controls.Add(this.tableLayoutPanel1); - this.splitContainer1.Panel1MinSize = 150; + splitContainer1.Panel1.Controls.Add(tableLayoutPanel1); + splitContainer1.Panel1MinSize = 150; // // splitContainer1.Panel2 // - this.splitContainer1.Panel2.AutoScroll = true; - this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel2); - this.splitContainer1.Panel2MinSize = 200; - this.splitContainer1.Size = new System.Drawing.Size(445, 839); - this.splitContainer1.SplitterDistance = 220; - this.splitContainer1.SplitterWidth = 5; - this.splitContainer1.TabIndex = 158; + splitContainer1.Panel2.AutoScroll = true; + splitContainer1.Panel2.Controls.Add(tableLayoutPanel2); + splitContainer1.Panel2MinSize = 200; + splitContainer1.Size = new System.Drawing.Size(445, 839); + splitContainer1.SplitterDistance = 246; + splitContainer1.SplitterWidth = 5; + splitContainer1.TabIndex = 158; + splitContainer1.SplitterMoved += splitContainer1_SplitterMoved; // // tableLayoutPanel1 // - this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.tableLayoutPanel1.ColumnCount = 2; - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.Controls.Add(this.ci_tbID, 1, 0); - this.tableLayoutPanel1.Controls.Add(this.label31, 0, 2); - this.tableLayoutPanel1.Controls.Add(this.panel1, 1, 2); - this.tableLayoutPanel1.Controls.Add(this.label26, 0, 1); - this.tableLayoutPanel1.Controls.Add(this.label28, 0, 0); - this.tableLayoutPanel1.Controls.Add(this.ci_tbName, 1, 1); - this.tableLayoutPanel1.Location = new System.Drawing.Point(1, 1); - this.tableLayoutPanel1.Name = "tableLayoutPanel1"; - this.tableLayoutPanel1.RowCount = 3; - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.Size = new System.Drawing.Size(439, 210); - this.tableLayoutPanel1.TabIndex = 162; + tableLayoutPanel1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + tableLayoutPanel1.ColumnCount = 2; + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel1.Controls.Add(ci_tbID, 1, 0); + tableLayoutPanel1.Controls.Add(label31, 0, 2); + tableLayoutPanel1.Controls.Add(panel1, 1, 2); + tableLayoutPanel1.Controls.Add(label26, 0, 1); + tableLayoutPanel1.Controls.Add(label28, 0, 0); + tableLayoutPanel1.Controls.Add(ci_tbName, 1, 1); + tableLayoutPanel1.Controls.Add(lbDataset, 0, 3); + tableLayoutPanel1.Controls.Add(lbDatasetValue, 1, 3); + tableLayoutPanel1.Location = new System.Drawing.Point(1, 1); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 4; + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + tableLayoutPanel1.Size = new System.Drawing.Size(439, 322); + tableLayoutPanel1.TabIndex = 162; + tableLayoutPanel1.Paint += tableLayoutPanel1_Paint; // // panel1 // - this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.panel1.Location = new System.Drawing.Point(117, 61); - this.panel1.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(302, 146); - this.panel1.TabIndex = 161; + panel1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + panel1.Location = new System.Drawing.Point(117, 61); + panel1.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); + panel1.Name = "panel1"; + panel1.Size = new System.Drawing.Size(302, 146); + panel1.TabIndex = 161; + // + // lbDataset + // + lbDataset.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; + lbDataset.AutoSize = true; + lbDataset.Location = new System.Drawing.Point(61, 210); + lbDataset.Name = "lbDataset"; + lbDataset.Size = new System.Drawing.Size(49, 15); + lbDataset.TabIndex = 162; + lbDataset.Text = "Dataset:"; + lbDataset.Click += label1_Click; + // + // lbDatasetValue + // + lbDatasetValue.AutoSize = true; + lbDatasetValue.Location = new System.Drawing.Point(116, 210); + lbDatasetValue.Name = "lbDatasetValue"; + lbDatasetValue.Size = new System.Drawing.Size(0, 15); + lbDatasetValue.TabIndex = 163; // // tableLayoutPanel2 // - this.tableLayoutPanel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.tableLayoutPanel2.ColumnCount = 2; - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel2.Controls.Add(this.label27, 0, 0); - this.tableLayoutPanel2.Controls.Add(this.ci_tbComments, 1, 6); - this.tableLayoutPanel2.Controls.Add(this.label36, 0, 6); - this.tableLayoutPanel2.Controls.Add(this.ci_tbLimitations, 1, 5); - this.tableLayoutPanel2.Controls.Add(this.label35, 0, 5); - this.tableLayoutPanel2.Controls.Add(this.ci_tbStatisticalConsiderations, 1, 0); - this.tableLayoutPanel2.Controls.Add(this.label30, 0, 1); - this.tableLayoutPanel2.Controls.Add(this.ci_tbResearchRelevance, 1, 1); - this.tableLayoutPanel2.Controls.Add(this.label33, 0, 2); - this.tableLayoutPanel2.Controls.Add(this.ci_tbAggregationMethod, 1, 4); - this.tableLayoutPanel2.Controls.Add(this.ci_tbTopics, 1, 2); - this.tableLayoutPanel2.Controls.Add(this.label32, 0, 4); - this.tableLayoutPanel2.Controls.Add(this.ci_ddPeriodicity, 1, 3); - this.tableLayoutPanel2.Controls.Add(this.label34, 0, 3); - this.tableLayoutPanel2.Location = new System.Drawing.Point(1, 3); - this.tableLayoutPanel2.Name = "tableLayoutPanel2"; - this.tableLayoutPanel2.RowCount = 7; - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.Size = new System.Drawing.Size(419, 590); - this.tableLayoutPanel2.TabIndex = 157; + tableLayoutPanel2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + tableLayoutPanel2.ColumnCount = 2; + tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel2.Controls.Add(label27, 0, 0); + tableLayoutPanel2.Controls.Add(ci_tbComments, 1, 6); + tableLayoutPanel2.Controls.Add(label36, 0, 6); + tableLayoutPanel2.Controls.Add(ci_tbLimitations, 1, 5); + tableLayoutPanel2.Controls.Add(label35, 0, 5); + tableLayoutPanel2.Controls.Add(ci_tbStatisticalConsiderations, 1, 0); + tableLayoutPanel2.Controls.Add(label30, 0, 1); + tableLayoutPanel2.Controls.Add(ci_tbResearchRelevance, 1, 1); + tableLayoutPanel2.Controls.Add(label33, 0, 2); + tableLayoutPanel2.Controls.Add(ci_tbAggregationMethod, 1, 4); + tableLayoutPanel2.Controls.Add(ci_tbTopics, 1, 2); + tableLayoutPanel2.Controls.Add(label32, 0, 4); + tableLayoutPanel2.Controls.Add(ci_ddPeriodicity, 1, 3); + tableLayoutPanel2.Controls.Add(label34, 0, 3); + tableLayoutPanel2.Location = new System.Drawing.Point(1, 53); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 7; + tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel2.Size = new System.Drawing.Size(351, 640); + tableLayoutPanel2.TabIndex = 157; // // CatalogueItemUI // - this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.splitContainer1); - this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.Name = "CatalogueItemUI"; - this.Size = new System.Drawing.Size(445, 839); - this.splitContainer1.Panel1.ResumeLayout(false); - this.splitContainer1.Panel2.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); - this.splitContainer1.ResumeLayout(false); - this.tableLayoutPanel1.ResumeLayout(false); - this.tableLayoutPanel1.PerformLayout(); - this.tableLayoutPanel2.ResumeLayout(false); - this.tableLayoutPanel2.PerformLayout(); - this.ResumeLayout(false); - + AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + Controls.Add(splitContainer1); + Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + Name = "CatalogueItemUI"; + Size = new System.Drawing.Size(445, 839); + splitContainer1.Panel1.ResumeLayout(false); + splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit(); + splitContainer1.ResumeLayout(false); + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel2.PerformLayout(); + ResumeLayout(false); } #endregion @@ -426,5 +435,7 @@ private void InitializeComponent() private System.Windows.Forms.Panel panel1; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.Label lbDataset; + private System.Windows.Forms.Label lbDatasetValue; } } diff --git a/Rdmp.UI/MainFormUITabs/CatalogueItemUI.cs b/Rdmp.UI/MainFormUITabs/CatalogueItemUI.cs index 552d11dea9..983f0b20c5 100644 --- a/Rdmp.UI/MainFormUITabs/CatalogueItemUI.cs +++ b/Rdmp.UI/MainFormUITabs/CatalogueItemUI.cs @@ -6,6 +6,7 @@ using System; using System.ComponentModel; +using System.Linq; using System.Windows.Forms; using Rdmp.Core; using Rdmp.Core.CommandExecution.AtomicCommands; @@ -40,6 +41,7 @@ public CatalogueItemUI() AssociatedCollection = RDMPCollection.Catalogue; ci_ddPeriodicity.DataSource = Enum.GetValues(typeof(Catalogue.CataloguePeriodicity)); + } private bool objectSaverButton1_BeforeSave(DatabaseEntity databaseEntity) @@ -60,6 +62,26 @@ private bool objectSaverButton1_BeforeSave(DatabaseEntity databaseEntity) public override void SetDatabaseObject(IActivateItems activator, CatalogueItem databaseObject) { _catalogueItem = databaseObject; + if (_catalogueItem != null) + { + var columnInfoDatasetValue = _catalogueItem?.ColumnInfo?.Dataset_ID; + if (columnInfoDatasetValue != null) + { + lbDatasetValue.Visible = true; + lbDataset.Visible = true; + var dataset = _catalogueItem.CatalogueRepository.GetAllObjects() + .FirstOrDefault(ds => ds.ID == columnInfoDatasetValue); + if (dataset != null) + { + lbDatasetValue.Text = dataset.Name; + } + } + else + { + lbDatasetValue.Visible = false; + lbDataset.Visible = false; + } + } if (_scintillaDescription == null) { @@ -73,7 +95,7 @@ public override void SetDatabaseObject(IActivateItems activator, CatalogueItem d base.SetDatabaseObject(activator, databaseObject); - if (_catalogueItem.ExtractionInformation == null) + if (_catalogueItem?.ExtractionInformation == null) CommonFunctionality.AddToMenu(new ExecuteCommandMakeCatalogueItemExtractable(activator, _catalogueItem), "Make Extractable"); } @@ -95,6 +117,21 @@ protected override void SetBindings(BinderWithErrorProviderFactory rules, Catalo } public override string GetTabName() => $"{base.GetTabName()} ({_catalogueItem.Catalogue.Name})"; + + private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e) + { + + } + + private void label1_Click(object sender, EventArgs e) + { + + } + + private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) + { + + } } [TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider))] diff --git a/Rdmp.UI/MainFormUITabs/CatalogueItemUI.resx b/Rdmp.UI/MainFormUITabs/CatalogueItemUI.resx index f298a7be80..af32865ec1 100644 --- a/Rdmp.UI/MainFormUITabs/CatalogueItemUI.resx +++ b/Rdmp.UI/MainFormUITabs/CatalogueItemUI.resx @@ -1,4 +1,64 @@ - + + + diff --git a/Rdmp.UI/MainFormUITabs/CatalogueUI.Designer.cs b/Rdmp.UI/MainFormUITabs/CatalogueUI.Designer.cs index ea861d057c..c07ce662af 100644 --- a/Rdmp.UI/MainFormUITabs/CatalogueUI.Designer.cs +++ b/Rdmp.UI/MainFormUITabs/CatalogueUI.Designer.cs @@ -31,1125 +31,1138 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.components = new System.ComponentModel.Container(); - this.tbDatasetStartDate = new System.Windows.Forms.TextBox(); - this.label41 = new System.Windows.Forms.Label(); - this.label28 = new System.Windows.Forms.Label(); - this.c_tbSubjectNumbers = new System.Windows.Forms.TextBox(); - this.tbDataStandards = new System.Windows.Forms.TextBox(); - this.label26 = new System.Windows.Forms.Label(); - this.label27 = new System.Windows.Forms.Label(); - this.tbCountryOfOrigin = new System.Windows.Forms.TextBox(); - this.label23 = new System.Windows.Forms.Label(); - this.label22 = new System.Windows.Forms.Label(); - this.c_ddGranularity = new System.Windows.Forms.ComboBox(); - this.label21 = new System.Windows.Forms.Label(); - this.label64 = new System.Windows.Forms.Label(); - this.label20 = new System.Windows.Forms.Label(); - this.c_tbDetailPageURL = new System.Windows.Forms.TextBox(); - this.label19 = new System.Windows.Forms.Label(); - this.label18 = new System.Windows.Forms.Label(); - this.label16 = new System.Windows.Forms.Label(); - this.c_tbUpdateFrequency = new System.Windows.Forms.TextBox(); - this.label4 = new System.Windows.Forms.Label(); - this.label17 = new System.Windows.Forms.Label(); - this.c_tbSourceUrl = new System.Windows.Forms.TextBox(); - this.c_tbTopics = new System.Windows.Forms.TextBox(); - this.label14 = new System.Windows.Forms.Label(); - this.c_tbQueryToolUrl = new System.Windows.Forms.TextBox(); - this.c_tbBackgroundSummary = new System.Windows.Forms.TextBox(); - this.label6 = new System.Windows.Forms.Label(); - this.c_tbBulkDownloadUrl = new System.Windows.Forms.TextBox(); - this.c_tbTimeCoverage = new System.Windows.Forms.TextBox(); - this.label7 = new System.Windows.Forms.Label(); - this.label12 = new System.Windows.Forms.Label(); - this.c_tbBrowseUrl = new System.Windows.Forms.TextBox(); - this.c_tbUpdateSchedule = new System.Windows.Forms.TextBox(); - this.label13 = new System.Windows.Forms.Label(); - this.c_tbAPIAccessURL = new System.Windows.Forms.TextBox(); - this.label10 = new System.Windows.Forms.Label(); - this.c_ddPeriodicity = new System.Windows.Forms.ComboBox(); - this.c_tbAccessOptions = new System.Windows.Forms.TextBox(); - this.c_tbLastRevisionDate = new System.Windows.Forms.TextBox(); - this.label9 = new System.Windows.Forms.Label(); - this.c_ddType = new System.Windows.Forms.ComboBox(); - this.c_tbResourceOwner = new System.Windows.Forms.TextBox(); - this.c_tbAttributionCitation = new System.Windows.Forms.TextBox(); - this.label8 = new System.Windows.Forms.Label(); - this.c_tbNumberOfThese = new System.Windows.Forms.TextBox(); - this.splitContainer1 = new System.Windows.Forms.SplitContainer(); - this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); - this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); - this.cbDeprecated = new System.Windows.Forms.CheckBox(); - this.cbInternal = new System.Windows.Forms.CheckBox(); - this.cbColdStorage = new System.Windows.Forms.CheckBox(); - this.tbFolder = new System.Windows.Forms.TextBox(); - this.tbAcronym = new System.Windows.Forms.TextBox(); - this.tbName = new System.Windows.Forms.TextBox(); - this.c_tbID = new System.Windows.Forms.TextBox(); - this.label1 = new System.Windows.Forms.Label(); - this.label24 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.label25 = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); - this.panel1 = new System.Windows.Forms.Panel(); - this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); - this.tbSourceOfDataCollection = new System.Windows.Forms.TextBox(); - this.tbEthicsApprover = new System.Windows.Forms.TextBox(); - this.label33 = new System.Windows.Forms.Label(); - this.ddExplicitConsent = new System.Windows.Forms.ComboBox(); - this.label32 = new System.Windows.Forms.Label(); - this.tbAdministrativeContactAddress = new System.Windows.Forms.TextBox(); - this.label31 = new System.Windows.Forms.Label(); - this.tbAdministrativeContactTelephone = new System.Windows.Forms.TextBox(); - this.label11 = new System.Windows.Forms.Label(); - this.tbAdministrativeContactEmail = new System.Windows.Forms.TextBox(); - this.label30 = new System.Windows.Forms.Label(); - this.tbAdministrativeContactName = new System.Windows.Forms.TextBox(); - this.label29 = new System.Windows.Forms.Label(); - this.label15 = new System.Windows.Forms.Label(); - this.label5 = new System.Windows.Forms.Label(); - this.c_tbGeographicalCoverage = new System.Windows.Forms.TextBox(); - this.ticketingControl1 = new Rdmp.UI.LocationsMenu.Ticketing.TicketingControlUI(); - this.errorProvider1 = new System.Windows.Forms.ErrorProvider(this.components); - ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); - this.splitContainer1.Panel1.SuspendLayout(); - this.splitContainer1.Panel2.SuspendLayout(); - this.splitContainer1.SuspendLayout(); - this.tableLayoutPanel1.SuspendLayout(); - this.flowLayoutPanel1.SuspendLayout(); - this.tableLayoutPanel2.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).BeginInit(); - this.SuspendLayout(); + components = new System.ComponentModel.Container(); + tbDatasetStartDate = new TextBox(); + label41 = new Label(); + label28 = new Label(); + c_tbSubjectNumbers = new TextBox(); + tbDataStandards = new TextBox(); + label26 = new Label(); + label27 = new Label(); + tbCountryOfOrigin = new TextBox(); + label23 = new Label(); + label22 = new Label(); + c_ddGranularity = new ComboBox(); + label21 = new Label(); + label64 = new Label(); + label20 = new Label(); + c_tbDetailPageURL = new TextBox(); + label19 = new Label(); + label18 = new Label(); + label16 = new Label(); + c_tbUpdateFrequency = new TextBox(); + label4 = new Label(); + label17 = new Label(); + c_tbSourceUrl = new TextBox(); + c_tbTopics = new TextBox(); + label14 = new Label(); + c_tbQueryToolUrl = new TextBox(); + c_tbBackgroundSummary = new TextBox(); + label6 = new Label(); + c_tbBulkDownloadUrl = new TextBox(); + c_tbTimeCoverage = new TextBox(); + label7 = new Label(); + label12 = new Label(); + c_tbBrowseUrl = new TextBox(); + c_tbUpdateSchedule = new TextBox(); + label13 = new Label(); + c_tbAPIAccessURL = new TextBox(); + label10 = new Label(); + c_ddPeriodicity = new ComboBox(); + c_tbAccessOptions = new TextBox(); + c_tbLastRevisionDate = new TextBox(); + label9 = new Label(); + c_ddType = new ComboBox(); + c_tbResourceOwner = new TextBox(); + c_tbAttributionCitation = new TextBox(); + label8 = new Label(); + c_tbNumberOfThese = new TextBox(); + splitContainer1 = new SplitContainer(); + tableLayoutPanel1 = new TableLayoutPanel(); + flowLayoutPanel1 = new FlowLayoutPanel(); + cbDeprecated = new CheckBox(); + cbInternal = new CheckBox(); + cbColdStorage = new CheckBox(); + tbFolder = new TextBox(); + tbAcronym = new TextBox(); + tbName = new TextBox(); + c_tbID = new TextBox(); + label1 = new Label(); + label24 = new Label(); + label2 = new Label(); + label25 = new Label(); + label3 = new Label(); + panel1 = new Panel(); + tableLayoutPanel2 = new TableLayoutPanel(); + tbSourceOfDataCollection = new TextBox(); + tbEthicsApprover = new TextBox(); + label33 = new Label(); + ddExplicitConsent = new ComboBox(); + label32 = new Label(); + tbAdministrativeContactAddress = new TextBox(); + label31 = new Label(); + tbAdministrativeContactTelephone = new TextBox(); + label11 = new Label(); + tbAdministrativeContactEmail = new TextBox(); + label30 = new Label(); + tbAdministrativeContactName = new TextBox(); + label29 = new Label(); + label15 = new Label(); + label5 = new Label(); + c_tbGeographicalCoverage = new TextBox(); + ticketingControl1 = new TicketingControlUI(); + errorProvider1 = new ErrorProvider(components); + lbDatasetslbl = new Label(); + lbDatasets = new Label(); + ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); + splitContainer1.Panel1.SuspendLayout(); + splitContainer1.Panel2.SuspendLayout(); + splitContainer1.SuspendLayout(); + tableLayoutPanel1.SuspendLayout(); + flowLayoutPanel1.SuspendLayout(); + tableLayoutPanel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)errorProvider1).BeginInit(); + SuspendLayout(); // // tbDatasetStartDate // - this.tbDatasetStartDate.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.tbDatasetStartDate.Location = new System.Drawing.Point(135, 674); - this.tbDatasetStartDate.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbDatasetStartDate.Name = "tbDatasetStartDate"; - this.tbDatasetStartDate.Size = new System.Drawing.Size(250, 23); - this.tbDatasetStartDate.TabIndex = 14; - this.tbDatasetStartDate.TextChanged += new System.EventHandler(this.tbDatasetStartDate_TextChanged); + tbDatasetStartDate.Anchor = AnchorStyles.Left; + tbDatasetStartDate.Location = new System.Drawing.Point(135, 674); + tbDatasetStartDate.Margin = new Padding(4, 3, 20, 3); + tbDatasetStartDate.Name = "tbDatasetStartDate"; + tbDatasetStartDate.Size = new System.Drawing.Size(250, 23); + tbDatasetStartDate.TabIndex = 14; + tbDatasetStartDate.TextChanged += tbDatasetStartDate_TextChanged; // // label41 // - this.label41.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label41.Location = new System.Drawing.Point(7, 675); - this.label41.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label41.Name = "label41"; - this.label41.Size = new System.Drawing.Size(120, 20); - this.label41.TabIndex = 147; - this.label41.Text = "Dataset Start Date:"; - this.label41.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label41.Anchor = AnchorStyles.Right; + label41.Location = new System.Drawing.Point(7, 675); + label41.Margin = new Padding(4, 0, 4, 0); + label41.Name = "label41"; + label41.Size = new System.Drawing.Size(120, 20); + label41.TabIndex = 147; + label41.Text = "Dataset Start Date:"; + label41.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label28 // - this.label28.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label28.ForeColor = System.Drawing.Color.Black; - this.label28.Location = new System.Drawing.Point(7, 616); - this.label28.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label28.Name = "label28"; - this.label28.Size = new System.Drawing.Size(120, 23); - this.label28.TabIndex = 134; - this.label28.Text = "Subject Numbers:"; - this.label28.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label28.Anchor = AnchorStyles.Right; + label28.ForeColor = System.Drawing.Color.Black; + label28.Location = new System.Drawing.Point(7, 616); + label28.Margin = new Padding(4, 0, 4, 0); + label28.Name = "label28"; + label28.Size = new System.Drawing.Size(120, 23); + label28.TabIndex = 134; + label28.Text = "Subject Numbers:"; + label28.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // c_tbSubjectNumbers // - this.c_tbSubjectNumbers.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbSubjectNumbers.BackColor = System.Drawing.SystemColors.Window; - this.c_tbSubjectNumbers.Location = new System.Drawing.Point(135, 616); - this.c_tbSubjectNumbers.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbSubjectNumbers.Name = "c_tbSubjectNumbers"; - this.c_tbSubjectNumbers.Size = new System.Drawing.Size(369, 23); - this.c_tbSubjectNumbers.TabIndex = 12; + c_tbSubjectNumbers.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbSubjectNumbers.BackColor = System.Drawing.SystemColors.Window; + c_tbSubjectNumbers.Location = new System.Drawing.Point(135, 616); + c_tbSubjectNumbers.Margin = new Padding(4, 3, 20, 3); + c_tbSubjectNumbers.Name = "c_tbSubjectNumbers"; + c_tbSubjectNumbers.Size = new System.Drawing.Size(369, 23); + c_tbSubjectNumbers.TabIndex = 12; // // tbDataStandards // - this.tbDataStandards.AcceptsReturn = true; - this.tbDataStandards.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbDataStandards.Location = new System.Drawing.Point(135, 1012); - this.tbDataStandards.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbDataStandards.Multiline = true; - this.tbDataStandards.Name = "tbDataStandards"; - this.tbDataStandards.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.tbDataStandards.Size = new System.Drawing.Size(369, 100); - this.tbDataStandards.TabIndex = 23; + tbDataStandards.AcceptsReturn = true; + tbDataStandards.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbDataStandards.Location = new System.Drawing.Point(135, 1012); + tbDataStandards.Margin = new Padding(4, 3, 20, 3); + tbDataStandards.Multiline = true; + tbDataStandards.Name = "tbDataStandards"; + tbDataStandards.ScrollBars = ScrollBars.Vertical; + tbDataStandards.Size = new System.Drawing.Size(369, 100); + tbDataStandards.TabIndex = 23; // // label26 // - this.label26.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label26.Location = new System.Drawing.Point(7, 1009); - this.label26.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label26.Name = "label26"; - this.label26.Size = new System.Drawing.Size(120, 20); - this.label26.TabIndex = 115; - this.label26.Text = "Data Standards:"; - this.label26.TextAlign = System.Drawing.ContentAlignment.TopRight; + label26.Anchor = AnchorStyles.Top | AnchorStyles.Right; + label26.Location = new System.Drawing.Point(7, 1009); + label26.Margin = new Padding(4, 0, 4, 0); + label26.Name = "label26"; + label26.Size = new System.Drawing.Size(120, 20); + label26.TabIndex = 115; + label26.Text = "Data Standards:"; + label26.TextAlign = System.Drawing.ContentAlignment.TopRight; // // label27 // - this.label27.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label27.AutoSize = true; - this.label27.Location = new System.Drawing.Point(24, 987); - this.label27.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label27.Name = "label27"; - this.label27.Size = new System.Drawing.Size(103, 15); - this.label27.TabIndex = 114; - this.label27.Text = "Country of Origin:"; - this.label27.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label27.Anchor = AnchorStyles.Right; + label27.AutoSize = true; + label27.Location = new System.Drawing.Point(24, 987); + label27.Margin = new Padding(4, 0, 4, 0); + label27.Name = "label27"; + label27.Size = new System.Drawing.Size(103, 15); + label27.TabIndex = 114; + label27.Text = "Country of Origin:"; + label27.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // tbCountryOfOrigin // - this.tbCountryOfOrigin.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbCountryOfOrigin.Location = new System.Drawing.Point(135, 983); - this.tbCountryOfOrigin.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbCountryOfOrigin.Name = "tbCountryOfOrigin"; - this.tbCountryOfOrigin.Size = new System.Drawing.Size(369, 23); - this.tbCountryOfOrigin.TabIndex = 22; + tbCountryOfOrigin.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbCountryOfOrigin.Location = new System.Drawing.Point(135, 983); + tbCountryOfOrigin.Margin = new Padding(4, 3, 20, 3); + tbCountryOfOrigin.Name = "tbCountryOfOrigin"; + tbCountryOfOrigin.Size = new System.Drawing.Size(369, 23); + tbCountryOfOrigin.TabIndex = 22; // // label23 // - this.label23.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label23.AutoSize = true; - this.label23.Location = new System.Drawing.Point(57, 958); - this.label23.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label23.Name = "label23"; - this.label23.Size = new System.Drawing.Size(70, 15); - this.label23.TabIndex = 104; - this.label23.Text = "Source URL:"; - this.label23.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label23.Anchor = AnchorStyles.Right; + label23.AutoSize = true; + label23.Location = new System.Drawing.Point(57, 958); + label23.Margin = new Padding(4, 0, 4, 0); + label23.Name = "label23"; + label23.Size = new System.Drawing.Size(70, 15); + label23.TabIndex = 104; + label23.Text = "Source URL:"; + label23.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label22 // - this.label22.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label22.AutoSize = true; - this.label22.Location = new System.Drawing.Point(36, 929); - this.label22.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label22.Name = "label22"; - this.label22.Size = new System.Drawing.Size(91, 15); - this.label22.TabIndex = 103; - this.label22.Text = "Query Tool URL:"; - this.label22.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label22.Anchor = AnchorStyles.Right; + label22.AutoSize = true; + label22.Location = new System.Drawing.Point(36, 929); + label22.Margin = new Padding(4, 0, 4, 0); + label22.Name = "label22"; + label22.Size = new System.Drawing.Size(91, 15); + label22.TabIndex = 103; + label22.Text = "Query Tool URL:"; + label22.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // c_ddGranularity // - this.c_ddGranularity.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.c_ddGranularity.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.c_ddGranularity.FormattingEnabled = true; - this.c_ddGranularity.Location = new System.Drawing.Point(135, 167); - this.c_ddGranularity.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_ddGranularity.Name = "c_ddGranularity"; - this.c_ddGranularity.Size = new System.Drawing.Size(250, 23); - this.c_ddGranularity.TabIndex = 3; + c_ddGranularity.Anchor = AnchorStyles.Left; + c_ddGranularity.DropDownStyle = ComboBoxStyle.DropDownList; + c_ddGranularity.FormattingEnabled = true; + c_ddGranularity.Location = new System.Drawing.Point(135, 167); + c_ddGranularity.Margin = new Padding(4, 3, 20, 3); + c_ddGranularity.Name = "c_ddGranularity"; + c_ddGranularity.Size = new System.Drawing.Size(250, 23); + c_ddGranularity.TabIndex = 3; // // label21 // - this.label21.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label21.AutoSize = true; - this.label21.Location = new System.Drawing.Point(13, 900); - this.label21.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label21.Name = "label21"; - this.label21.Size = new System.Drawing.Size(114, 15); - this.label21.TabIndex = 102; - this.label21.Text = "Bulk Download URL:"; - this.label21.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label21.Anchor = AnchorStyles.Right; + label21.AutoSize = true; + label21.Location = new System.Drawing.Point(13, 900); + label21.Margin = new Padding(4, 0, 4, 0); + label21.Name = "label21"; + label21.Size = new System.Drawing.Size(114, 15); + label21.TabIndex = 102; + label21.Text = "Bulk Download URL:"; + label21.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label64 // - this.label64.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label64.AutoSize = true; - this.label64.Location = new System.Drawing.Point(59, 171); - this.label64.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label64.Name = "label64"; - this.label64.Size = new System.Drawing.Size(68, 15); - this.label64.TabIndex = 108; - this.label64.Text = "Granularity:"; - this.label64.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label64.Anchor = AnchorStyles.Right; + label64.AutoSize = true; + label64.Location = new System.Drawing.Point(59, 171); + label64.Margin = new Padding(4, 0, 4, 0); + label64.Name = "label64"; + label64.Size = new System.Drawing.Size(68, 15); + label64.TabIndex = 108; + label64.Text = "Granularity:"; + label64.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label20 // - this.label20.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label20.AutoSize = true; - this.label20.Location = new System.Drawing.Point(55, 871); - this.label20.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label20.Name = "label20"; - this.label20.Size = new System.Drawing.Size(72, 15); - this.label20.TabIndex = 101; - this.label20.Text = "Browse URL:"; - this.label20.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label20.Anchor = AnchorStyles.Right; + label20.AutoSize = true; + label20.Location = new System.Drawing.Point(55, 871); + label20.Margin = new Padding(4, 0, 4, 0); + label20.Name = "label20"; + label20.Size = new System.Drawing.Size(72, 15); + label20.TabIndex = 101; + label20.Text = "Browse URL:"; + label20.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // c_tbDetailPageURL // - this.c_tbDetailPageURL.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbDetailPageURL.Location = new System.Drawing.Point(135, 3); - this.c_tbDetailPageURL.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbDetailPageURL.Name = "c_tbDetailPageURL"; - this.c_tbDetailPageURL.Size = new System.Drawing.Size(369, 23); - this.c_tbDetailPageURL.TabIndex = 0; - this.c_tbDetailPageURL.TextChanged += new System.EventHandler(this.c_tbDetailPageURL_TextChanged); + c_tbDetailPageURL.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbDetailPageURL.Location = new System.Drawing.Point(135, 3); + c_tbDetailPageURL.Margin = new Padding(4, 3, 20, 3); + c_tbDetailPageURL.Name = "c_tbDetailPageURL"; + c_tbDetailPageURL.Size = new System.Drawing.Size(369, 23); + c_tbDetailPageURL.TabIndex = 0; + c_tbDetailPageURL.TextChanged += c_tbDetailPageURL_TextChanged; // // label19 // - this.label19.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label19.AutoSize = true; - this.label19.Location = new System.Drawing.Point(36, 842); - this.label19.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label19.Name = "label19"; - this.label19.Size = new System.Drawing.Size(91, 15); - this.label19.TabIndex = 100; - this.label19.Text = "API Access URL:"; - this.label19.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label19.Anchor = AnchorStyles.Right; + label19.AutoSize = true; + label19.Location = new System.Drawing.Point(36, 842); + label19.Margin = new Padding(4, 0, 4, 0); + label19.Name = "label19"; + label19.Size = new System.Drawing.Size(91, 15); + label19.TabIndex = 100; + label19.Text = "API Access URL:"; + label19.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label18 // - this.label18.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label18.AutoSize = true; - this.label18.Location = new System.Drawing.Point(36, 813); - this.label18.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label18.Name = "label18"; - this.label18.Size = new System.Drawing.Size(91, 15); - this.label18.TabIndex = 99; - this.label18.Text = "Access Options:"; - this.label18.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label18.Anchor = AnchorStyles.Right; + label18.AutoSize = true; + label18.Location = new System.Drawing.Point(36, 813); + label18.Margin = new Padding(4, 0, 4, 0); + label18.Name = "label18"; + label18.Size = new System.Drawing.Size(91, 15); + label18.TabIndex = 99; + label18.Text = "Access Options:"; + label18.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label16 // - this.label16.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label16.Location = new System.Drawing.Point(7, 646); - this.label16.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label16.Name = "label16"; - this.label16.Size = new System.Drawing.Size(120, 20); - this.label16.TabIndex = 98; - this.label16.Text = "Resource Owner:"; - this.label16.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label16.Anchor = AnchorStyles.Right; + label16.Location = new System.Drawing.Point(7, 646); + label16.Margin = new Padding(4, 0, 4, 0); + label16.Name = "label16"; + label16.Size = new System.Drawing.Size(120, 20); + label16.TabIndex = 98; + label16.Text = "Resource Owner:"; + label16.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // c_tbUpdateFrequency // - this.c_tbUpdateFrequency.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbUpdateFrequency.Location = new System.Drawing.Point(135, 500); - this.c_tbUpdateFrequency.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbUpdateFrequency.Name = "c_tbUpdateFrequency"; - this.c_tbUpdateFrequency.Size = new System.Drawing.Size(369, 23); - this.c_tbUpdateFrequency.TabIndex = 7; + c_tbUpdateFrequency.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbUpdateFrequency.Location = new System.Drawing.Point(135, 500); + c_tbUpdateFrequency.Margin = new Padding(4, 3, 20, 3); + c_tbUpdateFrequency.Name = "c_tbUpdateFrequency"; + c_tbUpdateFrequency.Size = new System.Drawing.Size(369, 23); + c_tbUpdateFrequency.TabIndex = 7; // // label4 // - this.label4.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(34, 7); - this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(93, 15); - this.label4.TabIndex = 65; - this.label4.Text = "Detail Page URL:"; - this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label4.Anchor = AnchorStyles.Right; + label4.AutoSize = true; + label4.Location = new System.Drawing.Point(34, 7); + label4.Margin = new Padding(4, 0, 4, 0); + label4.Name = "label4"; + label4.Size = new System.Drawing.Size(93, 15); + label4.TabIndex = 65; + label4.Text = "Detail Page URL:"; + label4.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label17 // - this.label17.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label17.Location = new System.Drawing.Point(7, 700); - this.label17.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label17.Name = "label17"; - this.label17.Size = new System.Drawing.Size(120, 20); - this.label17.TabIndex = 97; - this.label17.Text = "Attribution Citation:"; - this.label17.TextAlign = System.Drawing.ContentAlignment.TopRight; + label17.Anchor = AnchorStyles.Top | AnchorStyles.Right; + label17.Location = new System.Drawing.Point(7, 700); + label17.Margin = new Padding(4, 0, 4, 0); + label17.Name = "label17"; + label17.Size = new System.Drawing.Size(120, 20); + label17.TabIndex = 97; + label17.Text = "Attribution Citation:"; + label17.TextAlign = System.Drawing.ContentAlignment.TopRight; // // c_tbSourceUrl // - this.c_tbSourceUrl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbSourceUrl.Location = new System.Drawing.Point(135, 954); - this.c_tbSourceUrl.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbSourceUrl.Name = "c_tbSourceUrl"; - this.c_tbSourceUrl.Size = new System.Drawing.Size(369, 23); - this.c_tbSourceUrl.TabIndex = 21; - this.c_tbSourceUrl.TextChanged += new System.EventHandler(this.c_tbSourceUrl_TextChanged); + c_tbSourceUrl.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbSourceUrl.Location = new System.Drawing.Point(135, 954); + c_tbSourceUrl.Margin = new Padding(4, 3, 20, 3); + c_tbSourceUrl.Name = "c_tbSourceUrl"; + c_tbSourceUrl.Size = new System.Drawing.Size(369, 23); + c_tbSourceUrl.TabIndex = 21; + c_tbSourceUrl.TextChanged += c_tbSourceUrl_TextChanged; // // c_tbTopics // - this.c_tbTopics.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbTopics.Location = new System.Drawing.Point(135, 331); - this.c_tbTopics.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbTopics.Multiline = true; - this.c_tbTopics.Name = "c_tbTopics"; - this.c_tbTopics.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.c_tbTopics.Size = new System.Drawing.Size(369, 100); - this.c_tbTopics.TabIndex = 6; + c_tbTopics.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbTopics.Location = new System.Drawing.Point(135, 331); + c_tbTopics.Margin = new Padding(4, 3, 20, 3); + c_tbTopics.Multiline = true; + c_tbTopics.Name = "c_tbTopics"; + c_tbTopics.ScrollBars = ScrollBars.Vertical; + c_tbTopics.Size = new System.Drawing.Size(369, 100); + c_tbTopics.TabIndex = 6; // // label14 // - this.label14.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label14.Location = new System.Drawing.Point(7, 587); - this.label14.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label14.Name = "label14"; - this.label14.Size = new System.Drawing.Size(120, 23); - this.label14.TabIndex = 96; - this.label14.Text = "Last Revision Date:"; - this.label14.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label14.Anchor = AnchorStyles.Right; + label14.Location = new System.Drawing.Point(7, 587); + label14.Margin = new Padding(4, 0, 4, 0); + label14.Name = "label14"; + label14.Size = new System.Drawing.Size(120, 23); + label14.TabIndex = 96; + label14.Text = "Last Revision Date:"; + label14.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // c_tbQueryToolUrl // - this.c_tbQueryToolUrl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbQueryToolUrl.Location = new System.Drawing.Point(135, 925); - this.c_tbQueryToolUrl.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbQueryToolUrl.Name = "c_tbQueryToolUrl"; - this.c_tbQueryToolUrl.Size = new System.Drawing.Size(369, 23); - this.c_tbQueryToolUrl.TabIndex = 20; - this.c_tbQueryToolUrl.TextChanged += new System.EventHandler(this.c_tbQueryToolUrl_TextChanged); + c_tbQueryToolUrl.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbQueryToolUrl.Location = new System.Drawing.Point(135, 925); + c_tbQueryToolUrl.Margin = new Padding(4, 3, 20, 3); + c_tbQueryToolUrl.Name = "c_tbQueryToolUrl"; + c_tbQueryToolUrl.Size = new System.Drawing.Size(369, 23); + c_tbQueryToolUrl.TabIndex = 20; + c_tbQueryToolUrl.TextChanged += c_tbQueryToolUrl_TextChanged; // // c_tbBackgroundSummary // - this.c_tbBackgroundSummary.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbBackgroundSummary.Location = new System.Drawing.Point(135, 196); - this.c_tbBackgroundSummary.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbBackgroundSummary.Multiline = true; - this.c_tbBackgroundSummary.Name = "c_tbBackgroundSummary"; - this.c_tbBackgroundSummary.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.c_tbBackgroundSummary.Size = new System.Drawing.Size(369, 100); - this.c_tbBackgroundSummary.TabIndex = 4; + c_tbBackgroundSummary.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbBackgroundSummary.Location = new System.Drawing.Point(135, 196); + c_tbBackgroundSummary.Margin = new Padding(4, 3, 20, 3); + c_tbBackgroundSummary.Multiline = true; + c_tbBackgroundSummary.Name = "c_tbBackgroundSummary"; + c_tbBackgroundSummary.ScrollBars = ScrollBars.Vertical; + c_tbBackgroundSummary.Size = new System.Drawing.Size(369, 100); + c_tbBackgroundSummary.TabIndex = 4; // // label6 // - this.label6.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(42, 36); - this.label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(85, 15); - this.label6.TabIndex = 69; - this.label6.Text = "Resource Type:"; - this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label6.Anchor = AnchorStyles.Right; + label6.AutoSize = true; + label6.Location = new System.Drawing.Point(42, 36); + label6.Margin = new Padding(4, 0, 4, 0); + label6.Name = "label6"; + label6.Size = new System.Drawing.Size(85, 15); + label6.TabIndex = 69; + label6.Text = "Resource Type:"; + label6.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // c_tbBulkDownloadUrl // - this.c_tbBulkDownloadUrl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbBulkDownloadUrl.Location = new System.Drawing.Point(135, 896); - this.c_tbBulkDownloadUrl.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbBulkDownloadUrl.Name = "c_tbBulkDownloadUrl"; - this.c_tbBulkDownloadUrl.Size = new System.Drawing.Size(369, 23); - this.c_tbBulkDownloadUrl.TabIndex = 19; - this.c_tbBulkDownloadUrl.TextChanged += new System.EventHandler(this.c_tbBulkDownloadUrl_TextChanged); + c_tbBulkDownloadUrl.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbBulkDownloadUrl.Location = new System.Drawing.Point(135, 896); + c_tbBulkDownloadUrl.Margin = new Padding(4, 3, 20, 3); + c_tbBulkDownloadUrl.Name = "c_tbBulkDownloadUrl"; + c_tbBulkDownloadUrl.Size = new System.Drawing.Size(369, 23); + c_tbBulkDownloadUrl.TabIndex = 19; + c_tbBulkDownloadUrl.TextChanged += c_tbBulkDownloadUrl_TextChanged; // // c_tbTimeCoverage // - this.c_tbTimeCoverage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbTimeCoverage.Location = new System.Drawing.Point(135, 558); - this.c_tbTimeCoverage.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbTimeCoverage.Name = "c_tbTimeCoverage"; - this.c_tbTimeCoverage.Size = new System.Drawing.Size(369, 23); - this.c_tbTimeCoverage.TabIndex = 10; + c_tbTimeCoverage.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbTimeCoverage.Location = new System.Drawing.Point(135, 558); + c_tbTimeCoverage.Margin = new Padding(4, 3, 20, 3); + c_tbTimeCoverage.Name = "c_tbTimeCoverage"; + c_tbTimeCoverage.Size = new System.Drawing.Size(369, 23); + c_tbTimeCoverage.TabIndex = 10; // // label7 // - this.label7.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(61, 306); - this.label7.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(66, 15); - this.label7.TabIndex = 72; - this.label7.Text = "Periodicity:"; - this.label7.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label7.Anchor = AnchorStyles.Right; + label7.AutoSize = true; + label7.Location = new System.Drawing.Point(61, 306); + label7.Margin = new Padding(4, 0, 4, 0); + label7.Name = "label7"; + label7.Size = new System.Drawing.Size(66, 15); + label7.TabIndex = 72; + label7.Text = "Periodicity:"; + label7.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label12 // - this.label12.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label12.Location = new System.Drawing.Point(7, 529); - this.label12.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label12.Name = "label12"; - this.label12.Size = new System.Drawing.Size(120, 23); - this.label12.TabIndex = 93; - this.label12.Text = "Update Schedule:"; - this.label12.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label12.Anchor = AnchorStyles.Right; + label12.Location = new System.Drawing.Point(7, 529); + label12.Margin = new Padding(4, 0, 4, 0); + label12.Name = "label12"; + label12.Size = new System.Drawing.Size(120, 23); + label12.TabIndex = 93; + label12.Text = "Update Schedule:"; + label12.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // c_tbBrowseUrl // - this.c_tbBrowseUrl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbBrowseUrl.Location = new System.Drawing.Point(135, 867); - this.c_tbBrowseUrl.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbBrowseUrl.Name = "c_tbBrowseUrl"; - this.c_tbBrowseUrl.Size = new System.Drawing.Size(369, 23); - this.c_tbBrowseUrl.TabIndex = 18; - this.c_tbBrowseUrl.TextChanged += new System.EventHandler(this.c_tbBrowseUrl_TextChanged); + c_tbBrowseUrl.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbBrowseUrl.Location = new System.Drawing.Point(135, 867); + c_tbBrowseUrl.Margin = new Padding(4, 3, 20, 3); + c_tbBrowseUrl.Name = "c_tbBrowseUrl"; + c_tbBrowseUrl.Size = new System.Drawing.Size(369, 23); + c_tbBrowseUrl.TabIndex = 18; + c_tbBrowseUrl.TextChanged += c_tbBrowseUrl_TextChanged; // // c_tbUpdateSchedule // - this.c_tbUpdateSchedule.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbUpdateSchedule.Location = new System.Drawing.Point(135, 529); - this.c_tbUpdateSchedule.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbUpdateSchedule.Name = "c_tbUpdateSchedule"; - this.c_tbUpdateSchedule.Size = new System.Drawing.Size(369, 23); - this.c_tbUpdateSchedule.TabIndex = 9; + c_tbUpdateSchedule.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbUpdateSchedule.Location = new System.Drawing.Point(135, 529); + c_tbUpdateSchedule.Margin = new Padding(4, 3, 20, 3); + c_tbUpdateSchedule.Name = "c_tbUpdateSchedule"; + c_tbUpdateSchedule.Size = new System.Drawing.Size(369, 23); + c_tbUpdateSchedule.TabIndex = 9; // // label13 // - this.label13.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label13.Location = new System.Drawing.Point(7, 558); - this.label13.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label13.Name = "label13"; - this.label13.Size = new System.Drawing.Size(120, 23); - this.label13.TabIndex = 89; - this.label13.Text = "Time Coverage:"; - this.label13.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label13.Anchor = AnchorStyles.Right; + label13.Location = new System.Drawing.Point(7, 558); + label13.Margin = new Padding(4, 0, 4, 0); + label13.Name = "label13"; + label13.Size = new System.Drawing.Size(120, 23); + label13.TabIndex = 89; + label13.Text = "Time Coverage:"; + label13.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // c_tbAPIAccessURL // - this.c_tbAPIAccessURL.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbAPIAccessURL.Location = new System.Drawing.Point(135, 838); - this.c_tbAPIAccessURL.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbAPIAccessURL.Name = "c_tbAPIAccessURL"; - this.c_tbAPIAccessURL.Size = new System.Drawing.Size(369, 23); - this.c_tbAPIAccessURL.TabIndex = 17; - this.c_tbAPIAccessURL.TextChanged += new System.EventHandler(this.c_tbAPIAccessURL_TextChanged); + c_tbAPIAccessURL.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbAPIAccessURL.Location = new System.Drawing.Point(135, 838); + c_tbAPIAccessURL.Margin = new Padding(4, 3, 20, 3); + c_tbAPIAccessURL.Name = "c_tbAPIAccessURL"; + c_tbAPIAccessURL.Size = new System.Drawing.Size(369, 23); + c_tbAPIAccessURL.TabIndex = 17; + c_tbAPIAccessURL.TextChanged += c_tbAPIAccessURL_TextChanged; // // label10 // - this.label10.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label10.Location = new System.Drawing.Point(7, 500); - this.label10.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(120, 23); - this.label10.TabIndex = 77; - this.label10.Text = "Update Frequency:"; - this.label10.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label10.Anchor = AnchorStyles.Right; + label10.Location = new System.Drawing.Point(7, 500); + label10.Margin = new Padding(4, 0, 4, 0); + label10.Name = "label10"; + label10.Size = new System.Drawing.Size(120, 23); + label10.TabIndex = 77; + label10.Text = "Update Frequency:"; + label10.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // c_ddPeriodicity // - this.c_ddPeriodicity.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.c_ddPeriodicity.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.c_ddPeriodicity.FormattingEnabled = true; - this.c_ddPeriodicity.Location = new System.Drawing.Point(135, 302); - this.c_ddPeriodicity.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_ddPeriodicity.Name = "c_ddPeriodicity"; - this.c_ddPeriodicity.Size = new System.Drawing.Size(250, 23); - this.c_ddPeriodicity.TabIndex = 5; + c_ddPeriodicity.Anchor = AnchorStyles.Left; + c_ddPeriodicity.DropDownStyle = ComboBoxStyle.DropDownList; + c_ddPeriodicity.FormattingEnabled = true; + c_ddPeriodicity.Location = new System.Drawing.Point(135, 302); + c_ddPeriodicity.Margin = new Padding(4, 3, 20, 3); + c_ddPeriodicity.Name = "c_ddPeriodicity"; + c_ddPeriodicity.Size = new System.Drawing.Size(250, 23); + c_ddPeriodicity.TabIndex = 5; // // c_tbAccessOptions // - this.c_tbAccessOptions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbAccessOptions.Location = new System.Drawing.Point(135, 809); - this.c_tbAccessOptions.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbAccessOptions.Name = "c_tbAccessOptions"; - this.c_tbAccessOptions.Size = new System.Drawing.Size(369, 23); - this.c_tbAccessOptions.TabIndex = 16; + c_tbAccessOptions.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbAccessOptions.Location = new System.Drawing.Point(135, 809); + c_tbAccessOptions.Margin = new Padding(4, 3, 20, 3); + c_tbAccessOptions.Name = "c_tbAccessOptions"; + c_tbAccessOptions.Size = new System.Drawing.Size(369, 23); + c_tbAccessOptions.TabIndex = 16; // // c_tbLastRevisionDate // - this.c_tbLastRevisionDate.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.c_tbLastRevisionDate.Location = new System.Drawing.Point(135, 587); - this.c_tbLastRevisionDate.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbLastRevisionDate.Name = "c_tbLastRevisionDate"; - this.c_tbLastRevisionDate.Size = new System.Drawing.Size(250, 23); - this.c_tbLastRevisionDate.TabIndex = 11; - this.c_tbLastRevisionDate.TextChanged += new System.EventHandler(this.c_tbLastRevisionDate_TextChanged); + c_tbLastRevisionDate.Anchor = AnchorStyles.Left; + c_tbLastRevisionDate.Location = new System.Drawing.Point(135, 587); + c_tbLastRevisionDate.Margin = new Padding(4, 3, 20, 3); + c_tbLastRevisionDate.Name = "c_tbLastRevisionDate"; + c_tbLastRevisionDate.Size = new System.Drawing.Size(250, 23); + c_tbLastRevisionDate.TabIndex = 11; + c_tbLastRevisionDate.TextChanged += c_tbLastRevisionDate_TextChanged; // // label9 // - this.label9.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label9.AutoSize = true; - this.label9.ForeColor = System.Drawing.Color.Black; - this.label9.Location = new System.Drawing.Point(53, 193); - this.label9.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(74, 15); - this.label9.TabIndex = 79; - this.label9.Text = "Background:"; - this.label9.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label9.Anchor = AnchorStyles.Top | AnchorStyles.Right; + label9.AutoSize = true; + label9.ForeColor = System.Drawing.Color.Black; + label9.Location = new System.Drawing.Point(53, 193); + label9.Margin = new Padding(4, 0, 4, 0); + label9.Name = "label9"; + label9.Size = new System.Drawing.Size(74, 15); + label9.TabIndex = 79; + label9.Text = "Background:"; + label9.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // c_ddType // - this.c_ddType.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.c_ddType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.c_ddType.FormattingEnabled = true; - this.c_ddType.Location = new System.Drawing.Point(135, 32); - this.c_ddType.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_ddType.Name = "c_ddType"; - this.c_ddType.Size = new System.Drawing.Size(250, 23); - this.c_ddType.TabIndex = 1; + c_ddType.Anchor = AnchorStyles.Left; + c_ddType.DropDownStyle = ComboBoxStyle.DropDownList; + c_ddType.FormattingEnabled = true; + c_ddType.Location = new System.Drawing.Point(135, 32); + c_ddType.Margin = new Padding(4, 3, 20, 3); + c_ddType.Name = "c_ddType"; + c_ddType.Size = new System.Drawing.Size(250, 23); + c_ddType.TabIndex = 1; // // c_tbResourceOwner // - this.c_tbResourceOwner.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbResourceOwner.Location = new System.Drawing.Point(135, 645); - this.c_tbResourceOwner.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbResourceOwner.Name = "c_tbResourceOwner"; - this.c_tbResourceOwner.Size = new System.Drawing.Size(369, 23); - this.c_tbResourceOwner.TabIndex = 13; + c_tbResourceOwner.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbResourceOwner.Location = new System.Drawing.Point(135, 645); + c_tbResourceOwner.Margin = new Padding(4, 3, 20, 3); + c_tbResourceOwner.Name = "c_tbResourceOwner"; + c_tbResourceOwner.Size = new System.Drawing.Size(369, 23); + c_tbResourceOwner.TabIndex = 13; // // c_tbAttributionCitation // - this.c_tbAttributionCitation.AcceptsReturn = true; - this.c_tbAttributionCitation.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbAttributionCitation.Location = new System.Drawing.Point(135, 703); - this.c_tbAttributionCitation.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbAttributionCitation.Multiline = true; - this.c_tbAttributionCitation.Name = "c_tbAttributionCitation"; - this.c_tbAttributionCitation.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.c_tbAttributionCitation.Size = new System.Drawing.Size(369, 100); - this.c_tbAttributionCitation.TabIndex = 15; + c_tbAttributionCitation.AcceptsReturn = true; + c_tbAttributionCitation.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbAttributionCitation.Location = new System.Drawing.Point(135, 703); + c_tbAttributionCitation.Margin = new Padding(4, 3, 20, 3); + c_tbAttributionCitation.Multiline = true; + c_tbAttributionCitation.Name = "c_tbAttributionCitation"; + c_tbAttributionCitation.ScrollBars = ScrollBars.Vertical; + c_tbAttributionCitation.Size = new System.Drawing.Size(369, 100); + c_tbAttributionCitation.TabIndex = 15; // // label8 // - this.label8.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(28, 328); - this.label8.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(99, 15); - this.label8.TabIndex = 83; - this.label8.Text = "Search Keywords:"; - this.label8.TextAlign = System.Drawing.ContentAlignment.TopRight; + label8.Anchor = AnchorStyles.Top | AnchorStyles.Right; + label8.AutoSize = true; + label8.Location = new System.Drawing.Point(28, 328); + label8.Margin = new Padding(4, 0, 4, 0); + label8.Name = "label8"; + label8.Size = new System.Drawing.Size(99, 15); + label8.TabIndex = 83; + label8.Text = "Search Keywords:"; + label8.TextAlign = System.Drawing.ContentAlignment.TopRight; // // c_tbNumberOfThese // - this.c_tbNumberOfThese.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbNumberOfThese.Location = new System.Drawing.Point(601, 537); - this.c_tbNumberOfThese.Name = "c_tbNumberOfThese"; - this.c_tbNumberOfThese.Size = new System.Drawing.Size(28, 23); - this.c_tbNumberOfThese.TabIndex = 68; - this.c_tbNumberOfThese.Visible = false; + c_tbNumberOfThese.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + c_tbNumberOfThese.Location = new System.Drawing.Point(601, 537); + c_tbNumberOfThese.Name = "c_tbNumberOfThese"; + c_tbNumberOfThese.Size = new System.Drawing.Size(28, 23); + c_tbNumberOfThese.TabIndex = 68; + c_tbNumberOfThese.Visible = false; // // splitContainer1 // - this.splitContainer1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; - this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; - this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1; - this.splitContainer1.Location = new System.Drawing.Point(0, 0); - this.splitContainer1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.splitContainer1.Name = "splitContainer1"; - this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; + splitContainer1.BorderStyle = BorderStyle.Fixed3D; + splitContainer1.Dock = DockStyle.Fill; + splitContainer1.FixedPanel = FixedPanel.Panel1; + splitContainer1.Location = new System.Drawing.Point(0, 0); + splitContainer1.Margin = new Padding(4, 3, 4, 3); + splitContainer1.Name = "splitContainer1"; + splitContainer1.Orientation = Orientation.Horizontal; // // splitContainer1.Panel1 // - this.splitContainer1.Panel1.Controls.Add(this.tableLayoutPanel1); - this.splitContainer1.Panel1MinSize = 200; + splitContainer1.Panel1.Controls.Add(tableLayoutPanel1); + splitContainer1.Panel1MinSize = 200; // // splitContainer1.Panel2 // - this.splitContainer1.Panel2.AutoScroll = true; - this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel2); - this.splitContainer1.Panel2MinSize = 200; - this.splitContainer1.Size = new System.Drawing.Size(551, 1085); - this.splitContainer1.SplitterDistance = 288; - this.splitContainer1.SplitterWidth = 5; - this.splitContainer1.TabIndex = 114; + splitContainer1.Panel2.AutoScroll = true; + splitContainer1.Panel2.Controls.Add(tableLayoutPanel2); + splitContainer1.Panel2MinSize = 200; + splitContainer1.Size = new System.Drawing.Size(551, 1085); + splitContainer1.SplitterDistance = 288; + splitContainer1.SplitterWidth = 5; + splitContainer1.TabIndex = 114; // // tableLayoutPanel1 // - this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.tableLayoutPanel1.ColumnCount = 2; - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel1, 1, 6); - this.tableLayoutPanel1.Controls.Add(this.tbFolder, 1, 3); - this.tableLayoutPanel1.Controls.Add(this.tbAcronym, 1, 2); - this.tableLayoutPanel1.Controls.Add(this.tbName, 1, 1); - this.tableLayoutPanel1.Controls.Add(this.c_tbID, 1, 0); - this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0); - this.tableLayoutPanel1.Controls.Add(this.label24, 0, 3); - this.tableLayoutPanel1.Controls.Add(this.label2, 0, 2); - this.tableLayoutPanel1.Controls.Add(this.label25, 0, 1); - this.tableLayoutPanel1.Controls.Add(this.label3, 0, 7); - this.tableLayoutPanel1.Controls.Add(this.panel1, 1, 7); - this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3); - this.tableLayoutPanel1.Name = "tableLayoutPanel1"; - this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(0, 0, 5, 0); - this.tableLayoutPanel1.RowCount = 8; - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(524, 278); - this.tableLayoutPanel1.TabIndex = 160; + tableLayoutPanel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + tableLayoutPanel1.ColumnCount = 2; + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel1.Controls.Add(flowLayoutPanel1, 1, 6); + tableLayoutPanel1.Controls.Add(tbFolder, 1, 3); + tableLayoutPanel1.Controls.Add(tbAcronym, 1, 2); + tableLayoutPanel1.Controls.Add(tbName, 1, 1); + tableLayoutPanel1.Controls.Add(c_tbID, 1, 0); + tableLayoutPanel1.Controls.Add(label1, 0, 0); + tableLayoutPanel1.Controls.Add(label24, 0, 3); + tableLayoutPanel1.Controls.Add(label2, 0, 2); + tableLayoutPanel1.Controls.Add(label25, 0, 1); + tableLayoutPanel1.Controls.Add(label3, 0, 7); + tableLayoutPanel1.Controls.Add(panel1, 1, 7); + tableLayoutPanel1.Controls.Add(lbDatasetslbl, 0, 8); + tableLayoutPanel1.Controls.Add(lbDatasets, 1, 8); + tableLayoutPanel1.Location = new System.Drawing.Point(3, 3); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.Padding = new Padding(0, 0, 5, 0); + tableLayoutPanel1.RowCount = 9; + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle()); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 112F)); + tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 13F)); + tableLayoutPanel1.Size = new System.Drawing.Size(524, 278); + tableLayoutPanel1.TabIndex = 160; // // flowLayoutPanel1 // - this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.flowLayoutPanel1.Controls.Add(this.cbDeprecated); - this.flowLayoutPanel1.Controls.Add(this.cbInternal); - this.flowLayoutPanel1.Controls.Add(this.cbColdStorage); - this.flowLayoutPanel1.Location = new System.Drawing.Point(132, 119); - this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(3, 3, 20, 3); - this.flowLayoutPanel1.Name = "flowLayoutPanel1"; - this.flowLayoutPanel1.Size = new System.Drawing.Size(367, 23); - this.flowLayoutPanel1.TabIndex = 159; + flowLayoutPanel1.Anchor = AnchorStyles.Left | AnchorStyles.Right; + flowLayoutPanel1.Controls.Add(cbDeprecated); + flowLayoutPanel1.Controls.Add(cbInternal); + flowLayoutPanel1.Controls.Add(cbColdStorage); + flowLayoutPanel1.Location = new System.Drawing.Point(132, 119); + flowLayoutPanel1.Margin = new Padding(3, 3, 20, 3); + flowLayoutPanel1.Name = "flowLayoutPanel1"; + flowLayoutPanel1.Size = new System.Drawing.Size(367, 23); + flowLayoutPanel1.TabIndex = 159; // // cbDeprecated // - this.cbDeprecated.AutoSize = true; - this.cbDeprecated.Location = new System.Drawing.Point(4, 3); - this.cbDeprecated.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.cbDeprecated.Name = "cbDeprecated"; - this.cbDeprecated.Size = new System.Drawing.Size(86, 19); - this.cbDeprecated.TabIndex = 5; - this.cbDeprecated.Text = "Deprecated"; - this.cbDeprecated.UseVisualStyleBackColor = true; + cbDeprecated.AutoSize = true; + cbDeprecated.Location = new System.Drawing.Point(4, 3); + cbDeprecated.Margin = new Padding(4, 3, 4, 3); + cbDeprecated.Name = "cbDeprecated"; + cbDeprecated.Size = new System.Drawing.Size(86, 19); + cbDeprecated.TabIndex = 5; + cbDeprecated.Text = "Deprecated"; + cbDeprecated.UseVisualStyleBackColor = true; // // cbInternal // - this.cbInternal.AutoSize = true; - this.cbInternal.Location = new System.Drawing.Point(98, 3); - this.cbInternal.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.cbInternal.Name = "cbInternal"; - this.cbInternal.Size = new System.Drawing.Size(66, 19); - this.cbInternal.TabIndex = 6; - this.cbInternal.Text = "Internal"; - this.cbInternal.UseVisualStyleBackColor = true; + cbInternal.AutoSize = true; + cbInternal.Location = new System.Drawing.Point(98, 3); + cbInternal.Margin = new Padding(4, 3, 4, 3); + cbInternal.Name = "cbInternal"; + cbInternal.Size = new System.Drawing.Size(66, 19); + cbInternal.TabIndex = 6; + cbInternal.Text = "Internal"; + cbInternal.UseVisualStyleBackColor = true; // // cbColdStorage // - this.cbColdStorage.AutoSize = true; - this.cbColdStorage.Location = new System.Drawing.Point(172, 3); - this.cbColdStorage.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.cbColdStorage.Name = "cbColdStorage"; - this.cbColdStorage.Size = new System.Drawing.Size(91, 19); - this.cbColdStorage.TabIndex = 7; - this.cbColdStorage.Text = "ColdStorage"; - this.cbColdStorage.UseVisualStyleBackColor = true; + cbColdStorage.AutoSize = true; + cbColdStorage.Location = new System.Drawing.Point(172, 3); + cbColdStorage.Margin = new Padding(4, 3, 4, 3); + cbColdStorage.Name = "cbColdStorage"; + cbColdStorage.Size = new System.Drawing.Size(91, 19); + cbColdStorage.TabIndex = 7; + cbColdStorage.Text = "ColdStorage"; + cbColdStorage.UseVisualStyleBackColor = true; // // tbFolder // - this.tbFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbFolder.Location = new System.Drawing.Point(133, 90); - this.tbFolder.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbFolder.Name = "tbFolder"; - this.tbFolder.Size = new System.Drawing.Size(366, 23); - this.tbFolder.TabIndex = 3; - this.tbFolder.TextChanged += new System.EventHandler(this.tbFolder_TextChanged); + tbFolder.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbFolder.Location = new System.Drawing.Point(133, 90); + tbFolder.Margin = new Padding(4, 3, 20, 3); + tbFolder.Name = "tbFolder"; + tbFolder.Size = new System.Drawing.Size(366, 23); + tbFolder.TabIndex = 3; + tbFolder.TextChanged += tbFolder_TextChanged; // // tbAcronym // - this.tbAcronym.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbAcronym.Location = new System.Drawing.Point(133, 61); - this.tbAcronym.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbAcronym.Name = "tbAcronym"; - this.tbAcronym.Size = new System.Drawing.Size(366, 23); - this.tbAcronym.TabIndex = 2; + tbAcronym.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbAcronym.Location = new System.Drawing.Point(133, 61); + tbAcronym.Margin = new Padding(4, 3, 20, 3); + tbAcronym.Name = "tbAcronym"; + tbAcronym.Size = new System.Drawing.Size(366, 23); + tbAcronym.TabIndex = 2; // // tbName // - this.tbName.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbName.Location = new System.Drawing.Point(133, 32); - this.tbName.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbName.Name = "tbName"; - this.tbName.Size = new System.Drawing.Size(366, 23); - this.tbName.TabIndex = 1; - this.tbName.TextChanged += new System.EventHandler(this.tbName_TextChanged); + tbName.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbName.Location = new System.Drawing.Point(133, 32); + tbName.Margin = new Padding(4, 3, 20, 3); + tbName.Name = "tbName"; + tbName.Size = new System.Drawing.Size(366, 23); + tbName.TabIndex = 1; + tbName.TextChanged += tbName_TextChanged; // // c_tbID // - this.c_tbID.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbID.Location = new System.Drawing.Point(133, 3); - this.c_tbID.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbID.Name = "c_tbID"; - this.c_tbID.ReadOnly = true; - this.c_tbID.Size = new System.Drawing.Size(366, 23); - this.c_tbID.TabIndex = 0; + c_tbID.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbID.Location = new System.Drawing.Point(133, 3); + c_tbID.Margin = new Padding(4, 3, 20, 3); + c_tbID.Name = "c_tbID"; + c_tbID.ReadOnly = true; + c_tbID.Size = new System.Drawing.Size(366, 23); + c_tbID.TabIndex = 0; // // label1 // - this.label1.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label1.AutoEllipsis = true; - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(47, 7); - this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(78, 15); - this.label1.TabIndex = 56; - this.label1.Text = "Catalogue ID:"; - this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label1.Anchor = AnchorStyles.Right; + label1.AutoEllipsis = true; + label1.AutoSize = true; + label1.Location = new System.Drawing.Point(47, 7); + label1.Margin = new Padding(4, 0, 4, 0); + label1.Name = "label1"; + label1.Size = new System.Drawing.Size(78, 15); + label1.TabIndex = 56; + label1.Text = "Catalogue ID:"; + label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label24 // - this.label24.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label24.AutoSize = true; - this.label24.Location = new System.Drawing.Point(82, 94); - this.label24.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label24.Name = "label24"; - this.label24.Size = new System.Drawing.Size(43, 15); - this.label24.TabIndex = 152; - this.label24.Text = "Folder:"; - this.label24.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label24.Anchor = AnchorStyles.Right; + label24.AutoSize = true; + label24.Location = new System.Drawing.Point(82, 94); + label24.Margin = new Padding(4, 0, 4, 0); + label24.Name = "label24"; + label24.Size = new System.Drawing.Size(43, 15); + label24.TabIndex = 152; + label24.Text = "Folder:"; + label24.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label2 // - this.label2.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(15, 65); - this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(110, 15); - this.label2.TabIndex = 58; - this.label2.Text = "Resource Acronym:"; - this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label2.Anchor = AnchorStyles.Right; + label2.AutoSize = true; + label2.Location = new System.Drawing.Point(15, 65); + label2.Margin = new Padding(4, 0, 4, 0); + label2.Name = "label2"; + label2.Size = new System.Drawing.Size(110, 15); + label2.TabIndex = 58; + label2.Text = "Resource Acronym:"; + label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label25 // - this.label25.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label25.AutoSize = true; - this.label25.Location = new System.Drawing.Point(5, 36); - this.label25.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label25.Name = "label25"; - this.label25.Size = new System.Drawing.Size(120, 15); - this.label25.TabIndex = 107; - this.label25.Text = "Resource Name/Title:"; - this.label25.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label25.Anchor = AnchorStyles.Right; + label25.AutoSize = true; + label25.Location = new System.Drawing.Point(5, 36); + label25.Margin = new Padding(4, 0, 4, 0); + label25.Name = "label25"; + label25.Size = new System.Drawing.Size(120, 15); + label25.TabIndex = 107; + label25.Text = "Resource Name/Title:"; + label25.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label3 // - this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(4, 145); - this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(121, 15); - this.label3.TabIndex = 61; - this.label3.Text = "Resource Description:"; - this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label3.Anchor = AnchorStyles.Top | AnchorStyles.Right; + label3.AutoSize = true; + label3.Location = new System.Drawing.Point(4, 145); + label3.Margin = new Padding(4, 0, 4, 0); + label3.Name = "label3"; + label3.Size = new System.Drawing.Size(121, 15); + label3.TabIndex = 61; + label3.Text = "Resource Description:"; + label3.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // panel1 // - this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.panel1.Location = new System.Drawing.Point(133, 148); - this.panel1.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(366, 127); - this.panel1.TabIndex = 153; + panel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + panel1.Location = new System.Drawing.Point(133, 148); + panel1.Margin = new Padding(4, 3, 20, 3); + panel1.Name = "panel1"; + panel1.Size = new System.Drawing.Size(366, 106); + panel1.TabIndex = 153; // // tableLayoutPanel2 // - this.tableLayoutPanel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.tableLayoutPanel2.ColumnCount = 2; - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel2.Controls.Add(this.tbSourceOfDataCollection, 1, 30); - this.tableLayoutPanel2.Controls.Add(this.tbEthicsApprover, 1, 29); - this.tableLayoutPanel2.Controls.Add(this.label33, 0, 30); - this.tableLayoutPanel2.Controls.Add(this.ddExplicitConsent, 1, 28); - this.tableLayoutPanel2.Controls.Add(this.label32, 0, 29); - this.tableLayoutPanel2.Controls.Add(this.tbAdministrativeContactAddress, 1, 27); - this.tableLayoutPanel2.Controls.Add(this.label31, 0, 28); - this.tableLayoutPanel2.Controls.Add(this.tbAdministrativeContactTelephone, 1, 26); - this.tableLayoutPanel2.Controls.Add(this.label11, 0, 27); - this.tableLayoutPanel2.Controls.Add(this.tbAdministrativeContactEmail, 1, 25); - this.tableLayoutPanel2.Controls.Add(this.label30, 0, 26); - this.tableLayoutPanel2.Controls.Add(this.tbAdministrativeContactName, 1, 24); - this.tableLayoutPanel2.Controls.Add(this.label29, 0, 25); - this.tableLayoutPanel2.Controls.Add(this.tbDataStandards, 1, 23); - this.tableLayoutPanel2.Controls.Add(this.label15, 0, 24); - this.tableLayoutPanel2.Controls.Add(this.tbCountryOfOrigin, 1, 22); - this.tableLayoutPanel2.Controls.Add(this.label26, 0, 23); - this.tableLayoutPanel2.Controls.Add(this.c_tbSourceUrl, 1, 21); - this.tableLayoutPanel2.Controls.Add(this.label27, 0, 22); - this.tableLayoutPanel2.Controls.Add(this.c_tbQueryToolUrl, 1, 20); - this.tableLayoutPanel2.Controls.Add(this.label23, 0, 21); - this.tableLayoutPanel2.Controls.Add(this.c_tbBulkDownloadUrl, 1, 19); - this.tableLayoutPanel2.Controls.Add(this.label22, 0, 20); - this.tableLayoutPanel2.Controls.Add(this.c_tbBrowseUrl, 1, 18); - this.tableLayoutPanel2.Controls.Add(this.label21, 0, 19); - this.tableLayoutPanel2.Controls.Add(this.c_tbAPIAccessURL, 1, 17); - this.tableLayoutPanel2.Controls.Add(this.label20, 0, 18); - this.tableLayoutPanel2.Controls.Add(this.c_tbAccessOptions, 1, 16); - this.tableLayoutPanel2.Controls.Add(this.label19, 0, 17); - this.tableLayoutPanel2.Controls.Add(this.tbDatasetStartDate, 1, 14); - this.tableLayoutPanel2.Controls.Add(this.label18, 0, 16); - this.tableLayoutPanel2.Controls.Add(this.label17, 0, 15); - this.tableLayoutPanel2.Controls.Add(this.c_tbResourceOwner, 1, 13); - this.tableLayoutPanel2.Controls.Add(this.label41, 0, 14); - this.tableLayoutPanel2.Controls.Add(this.c_tbSubjectNumbers, 1, 12); - this.tableLayoutPanel2.Controls.Add(this.label16, 0, 13); - this.tableLayoutPanel2.Controls.Add(this.c_tbLastRevisionDate, 1, 11); - this.tableLayoutPanel2.Controls.Add(this.label28, 0, 12); - this.tableLayoutPanel2.Controls.Add(this.c_tbTimeCoverage, 1, 10); - this.tableLayoutPanel2.Controls.Add(this.label14, 0, 11); - this.tableLayoutPanel2.Controls.Add(this.c_tbBackgroundSummary, 1, 4); - this.tableLayoutPanel2.Controls.Add(this.label13, 0, 10); - this.tableLayoutPanel2.Controls.Add(this.c_tbUpdateSchedule, 1, 9); - this.tableLayoutPanel2.Controls.Add(this.c_tbUpdateFrequency, 1, 8); - this.tableLayoutPanel2.Controls.Add(this.label12, 0, 9); - this.tableLayoutPanel2.Controls.Add(this.c_tbTopics, 1, 6); - this.tableLayoutPanel2.Controls.Add(this.c_ddPeriodicity, 1, 5); - this.tableLayoutPanel2.Controls.Add(this.label10, 0, 8); - this.tableLayoutPanel2.Controls.Add(this.c_ddGranularity, 1, 3); - this.tableLayoutPanel2.Controls.Add(this.label8, 0, 6); - this.tableLayoutPanel2.Controls.Add(this.c_ddType, 1, 1); - this.tableLayoutPanel2.Controls.Add(this.label7, 0, 5); - this.tableLayoutPanel2.Controls.Add(this.c_tbDetailPageURL, 1, 0); - this.tableLayoutPanel2.Controls.Add(this.label64, 0, 3); - this.tableLayoutPanel2.Controls.Add(this.label4, 0, 0); - this.tableLayoutPanel2.Controls.Add(this.label6, 0, 1); - this.tableLayoutPanel2.Controls.Add(this.label5, 0, 2); - this.tableLayoutPanel2.Controls.Add(this.c_tbGeographicalCoverage, 1, 2); - this.tableLayoutPanel2.Controls.Add(this.label9, 0, 4); - this.tableLayoutPanel2.Controls.Add(this.ticketingControl1, 1, 7); - this.tableLayoutPanel2.Controls.Add(this.c_tbAttributionCitation, 1, 15); - this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 3); - this.tableLayoutPanel2.Name = "tableLayoutPanel2"; - this.tableLayoutPanel2.RowCount = 31; - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.Size = new System.Drawing.Size(473, 1475); - this.tableLayoutPanel2.TabIndex = 194; + tableLayoutPanel2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tableLayoutPanel2.ColumnCount = 2; + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle()); + tableLayoutPanel2.Controls.Add(tbSourceOfDataCollection, 1, 30); + tableLayoutPanel2.Controls.Add(tbEthicsApprover, 1, 29); + tableLayoutPanel2.Controls.Add(label33, 0, 30); + tableLayoutPanel2.Controls.Add(ddExplicitConsent, 1, 28); + tableLayoutPanel2.Controls.Add(label32, 0, 29); + tableLayoutPanel2.Controls.Add(tbAdministrativeContactAddress, 1, 27); + tableLayoutPanel2.Controls.Add(label31, 0, 28); + tableLayoutPanel2.Controls.Add(tbAdministrativeContactTelephone, 1, 26); + tableLayoutPanel2.Controls.Add(label11, 0, 27); + tableLayoutPanel2.Controls.Add(tbAdministrativeContactEmail, 1, 25); + tableLayoutPanel2.Controls.Add(label30, 0, 26); + tableLayoutPanel2.Controls.Add(tbAdministrativeContactName, 1, 24); + tableLayoutPanel2.Controls.Add(label29, 0, 25); + tableLayoutPanel2.Controls.Add(tbDataStandards, 1, 23); + tableLayoutPanel2.Controls.Add(label15, 0, 24); + tableLayoutPanel2.Controls.Add(tbCountryOfOrigin, 1, 22); + tableLayoutPanel2.Controls.Add(label26, 0, 23); + tableLayoutPanel2.Controls.Add(c_tbSourceUrl, 1, 21); + tableLayoutPanel2.Controls.Add(label27, 0, 22); + tableLayoutPanel2.Controls.Add(c_tbQueryToolUrl, 1, 20); + tableLayoutPanel2.Controls.Add(label23, 0, 21); + tableLayoutPanel2.Controls.Add(c_tbBulkDownloadUrl, 1, 19); + tableLayoutPanel2.Controls.Add(label22, 0, 20); + tableLayoutPanel2.Controls.Add(c_tbBrowseUrl, 1, 18); + tableLayoutPanel2.Controls.Add(label21, 0, 19); + tableLayoutPanel2.Controls.Add(c_tbAPIAccessURL, 1, 17); + tableLayoutPanel2.Controls.Add(label20, 0, 18); + tableLayoutPanel2.Controls.Add(c_tbAccessOptions, 1, 16); + tableLayoutPanel2.Controls.Add(label19, 0, 17); + tableLayoutPanel2.Controls.Add(tbDatasetStartDate, 1, 14); + tableLayoutPanel2.Controls.Add(label18, 0, 16); + tableLayoutPanel2.Controls.Add(label17, 0, 15); + tableLayoutPanel2.Controls.Add(c_tbResourceOwner, 1, 13); + tableLayoutPanel2.Controls.Add(label41, 0, 14); + tableLayoutPanel2.Controls.Add(c_tbSubjectNumbers, 1, 12); + tableLayoutPanel2.Controls.Add(label16, 0, 13); + tableLayoutPanel2.Controls.Add(c_tbLastRevisionDate, 1, 11); + tableLayoutPanel2.Controls.Add(label28, 0, 12); + tableLayoutPanel2.Controls.Add(c_tbTimeCoverage, 1, 10); + tableLayoutPanel2.Controls.Add(label14, 0, 11); + tableLayoutPanel2.Controls.Add(c_tbBackgroundSummary, 1, 4); + tableLayoutPanel2.Controls.Add(label13, 0, 10); + tableLayoutPanel2.Controls.Add(c_tbUpdateSchedule, 1, 9); + tableLayoutPanel2.Controls.Add(c_tbUpdateFrequency, 1, 8); + tableLayoutPanel2.Controls.Add(label12, 0, 9); + tableLayoutPanel2.Controls.Add(c_tbTopics, 1, 6); + tableLayoutPanel2.Controls.Add(c_ddPeriodicity, 1, 5); + tableLayoutPanel2.Controls.Add(label10, 0, 8); + tableLayoutPanel2.Controls.Add(c_ddGranularity, 1, 3); + tableLayoutPanel2.Controls.Add(label8, 0, 6); + tableLayoutPanel2.Controls.Add(c_ddType, 1, 1); + tableLayoutPanel2.Controls.Add(label7, 0, 5); + tableLayoutPanel2.Controls.Add(c_tbDetailPageURL, 1, 0); + tableLayoutPanel2.Controls.Add(label64, 0, 3); + tableLayoutPanel2.Controls.Add(label4, 0, 0); + tableLayoutPanel2.Controls.Add(label6, 0, 1); + tableLayoutPanel2.Controls.Add(label5, 0, 2); + tableLayoutPanel2.Controls.Add(c_tbGeographicalCoverage, 1, 2); + tableLayoutPanel2.Controls.Add(label9, 0, 4); + tableLayoutPanel2.Controls.Add(ticketingControl1, 1, 7); + tableLayoutPanel2.Controls.Add(c_tbAttributionCitation, 1, 15); + tableLayoutPanel2.Location = new System.Drawing.Point(3, 3); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 31; + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.RowStyles.Add(new RowStyle()); + tableLayoutPanel2.Size = new System.Drawing.Size(456, 1475); + tableLayoutPanel2.TabIndex = 194; // // tbSourceOfDataCollection // - this.tbSourceOfDataCollection.AcceptsReturn = true; - this.tbSourceOfDataCollection.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbSourceOfDataCollection.Location = new System.Drawing.Point(135, 1370); - this.tbSourceOfDataCollection.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbSourceOfDataCollection.Multiline = true; - this.tbSourceOfDataCollection.Name = "tbSourceOfDataCollection"; - this.tbSourceOfDataCollection.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.tbSourceOfDataCollection.Size = new System.Drawing.Size(369, 100); - this.tbSourceOfDataCollection.TabIndex = 30; + tbSourceOfDataCollection.AcceptsReturn = true; + tbSourceOfDataCollection.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbSourceOfDataCollection.Location = new System.Drawing.Point(135, 1370); + tbSourceOfDataCollection.Margin = new Padding(4, 3, 20, 3); + tbSourceOfDataCollection.Multiline = true; + tbSourceOfDataCollection.Name = "tbSourceOfDataCollection"; + tbSourceOfDataCollection.ScrollBars = ScrollBars.Vertical; + tbSourceOfDataCollection.Size = new System.Drawing.Size(369, 100); + tbSourceOfDataCollection.TabIndex = 30; // // tbEthicsApprover // - this.tbEthicsApprover.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbEthicsApprover.Location = new System.Drawing.Point(135, 1340); - this.tbEthicsApprover.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbEthicsApprover.Name = "tbEthicsApprover"; - this.tbEthicsApprover.Size = new System.Drawing.Size(369, 23); - this.tbEthicsApprover.TabIndex = 29; + tbEthicsApprover.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbEthicsApprover.Location = new System.Drawing.Point(135, 1340); + tbEthicsApprover.Margin = new Padding(4, 3, 20, 3); + tbEthicsApprover.Name = "tbEthicsApprover"; + tbEthicsApprover.Size = new System.Drawing.Size(369, 23); + tbEthicsApprover.TabIndex = 29; // // label33 // - this.label33.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label33.AutoSize = true; - this.label33.Location = new System.Drawing.Point(43, 1366); - this.label33.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label33.Name = "label33"; - this.label33.Size = new System.Drawing.Size(84, 30); - this.label33.TabIndex = 163; - this.label33.Text = "Source of Data\r\nCollection:"; - this.label33.TextAlign = System.Drawing.ContentAlignment.TopRight; + label33.Anchor = AnchorStyles.Top | AnchorStyles.Right; + label33.AutoSize = true; + label33.Location = new System.Drawing.Point(43, 1366); + label33.Margin = new Padding(4, 0, 4, 0); + label33.Name = "label33"; + label33.Size = new System.Drawing.Size(84, 30); + label33.TabIndex = 163; + label33.Text = "Source of Data\r\nCollection:"; + label33.TextAlign = System.Drawing.ContentAlignment.TopRight; // // ddExplicitConsent // - this.ddExplicitConsent.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.ddExplicitConsent.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.ddExplicitConsent.FormattingEnabled = true; - this.ddExplicitConsent.Items.AddRange(new object[] { - "", - "Yes", - "No"}); - this.ddExplicitConsent.Location = new System.Drawing.Point(135, 1311); - this.ddExplicitConsent.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.ddExplicitConsent.Name = "ddExplicitConsent"; - this.ddExplicitConsent.Size = new System.Drawing.Size(250, 23); - this.ddExplicitConsent.TabIndex = 28; - this.ddExplicitConsent.SelectedIndexChanged += new System.EventHandler(this.ddExplicitConsent_SelectedIndexChanged); + ddExplicitConsent.Anchor = AnchorStyles.Left; + ddExplicitConsent.DropDownStyle = ComboBoxStyle.DropDownList; + ddExplicitConsent.FormattingEnabled = true; + ddExplicitConsent.Items.AddRange(new object[] { "", "Yes", "No" }); + ddExplicitConsent.Location = new System.Drawing.Point(135, 1311); + ddExplicitConsent.Margin = new Padding(4, 3, 20, 3); + ddExplicitConsent.Name = "ddExplicitConsent"; + ddExplicitConsent.Size = new System.Drawing.Size(250, 23); + ddExplicitConsent.TabIndex = 28; + ddExplicitConsent.SelectedIndexChanged += ddExplicitConsent_SelectedIndexChanged; // // label32 // - this.label32.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label32.AutoSize = true; - this.label32.Location = new System.Drawing.Point(34, 1344); - this.label32.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label32.Name = "label32"; - this.label32.Size = new System.Drawing.Size(93, 15); - this.label32.TabIndex = 162; - this.label32.Text = "Ethics Approver:"; - this.label32.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label32.Anchor = AnchorStyles.Right; + label32.AutoSize = true; + label32.Location = new System.Drawing.Point(34, 1344); + label32.Margin = new Padding(4, 0, 4, 0); + label32.Name = "label32"; + label32.Size = new System.Drawing.Size(93, 15); + label32.TabIndex = 162; + label32.Text = "Ethics Approver:"; + label32.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // tbAdministrativeContactAddress // - this.tbAdministrativeContactAddress.AcceptsReturn = true; - this.tbAdministrativeContactAddress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbAdministrativeContactAddress.Location = new System.Drawing.Point(135, 1205); - this.tbAdministrativeContactAddress.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbAdministrativeContactAddress.Multiline = true; - this.tbAdministrativeContactAddress.Name = "tbAdministrativeContactAddress"; - this.tbAdministrativeContactAddress.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.tbAdministrativeContactAddress.Size = new System.Drawing.Size(369, 100); - this.tbAdministrativeContactAddress.TabIndex = 27; + tbAdministrativeContactAddress.AcceptsReturn = true; + tbAdministrativeContactAddress.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbAdministrativeContactAddress.Location = new System.Drawing.Point(135, 1205); + tbAdministrativeContactAddress.Margin = new Padding(4, 3, 20, 3); + tbAdministrativeContactAddress.Multiline = true; + tbAdministrativeContactAddress.Name = "tbAdministrativeContactAddress"; + tbAdministrativeContactAddress.ScrollBars = ScrollBars.Vertical; + tbAdministrativeContactAddress.Size = new System.Drawing.Size(369, 100); + tbAdministrativeContactAddress.TabIndex = 27; // // label31 // - this.label31.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label31.AutoSize = true; - this.label31.Location = new System.Drawing.Point(32, 1315); - this.label31.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label31.Name = "label31"; - this.label31.Size = new System.Drawing.Size(95, 15); - this.label31.TabIndex = 161; - this.label31.Text = "Explicit Consent:"; - this.label31.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label31.Anchor = AnchorStyles.Right; + label31.AutoSize = true; + label31.Location = new System.Drawing.Point(32, 1315); + label31.Margin = new Padding(4, 0, 4, 0); + label31.Name = "label31"; + label31.Size = new System.Drawing.Size(95, 15); + label31.TabIndex = 161; + label31.Text = "Explicit Consent:"; + label31.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // tbAdministrativeContactTelephone // - this.tbAdministrativeContactTelephone.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbAdministrativeContactTelephone.Location = new System.Drawing.Point(135, 1176); - this.tbAdministrativeContactTelephone.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbAdministrativeContactTelephone.Name = "tbAdministrativeContactTelephone"; - this.tbAdministrativeContactTelephone.Size = new System.Drawing.Size(369, 23); - this.tbAdministrativeContactTelephone.TabIndex = 26; + tbAdministrativeContactTelephone.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbAdministrativeContactTelephone.Location = new System.Drawing.Point(135, 1176); + tbAdministrativeContactTelephone.Margin = new Padding(4, 3, 20, 3); + tbAdministrativeContactTelephone.Name = "tbAdministrativeContactTelephone"; + tbAdministrativeContactTelephone.Size = new System.Drawing.Size(369, 23); + tbAdministrativeContactTelephone.TabIndex = 26; // // label11 // - this.label11.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label11.Location = new System.Drawing.Point(7, 1202); - this.label11.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label11.Name = "label11"; - this.label11.Size = new System.Drawing.Size(120, 20); - this.label11.TabIndex = 160; - this.label11.Text = "Admin Address:"; - this.label11.TextAlign = System.Drawing.ContentAlignment.TopRight; + label11.Anchor = AnchorStyles.Top | AnchorStyles.Right; + label11.Location = new System.Drawing.Point(7, 1202); + label11.Margin = new Padding(4, 0, 4, 0); + label11.Name = "label11"; + label11.Size = new System.Drawing.Size(120, 20); + label11.TabIndex = 160; + label11.Text = "Admin Address:"; + label11.TextAlign = System.Drawing.ContentAlignment.TopRight; // // tbAdministrativeContactEmail // - this.tbAdministrativeContactEmail.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbAdministrativeContactEmail.Location = new System.Drawing.Point(135, 1147); - this.tbAdministrativeContactEmail.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbAdministrativeContactEmail.Name = "tbAdministrativeContactEmail"; - this.tbAdministrativeContactEmail.Size = new System.Drawing.Size(369, 23); - this.tbAdministrativeContactEmail.TabIndex = 25; + tbAdministrativeContactEmail.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbAdministrativeContactEmail.Location = new System.Drawing.Point(135, 1147); + tbAdministrativeContactEmail.Margin = new Padding(4, 3, 20, 3); + tbAdministrativeContactEmail.Name = "tbAdministrativeContactEmail"; + tbAdministrativeContactEmail.Size = new System.Drawing.Size(369, 23); + tbAdministrativeContactEmail.TabIndex = 25; // // label30 // - this.label30.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label30.AutoSize = true; - this.label30.Location = new System.Drawing.Point(19, 1180); - this.label30.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label30.Name = "label30"; - this.label30.Size = new System.Drawing.Size(108, 15); - this.label30.TabIndex = 159; - this.label30.Text = "Admin Contact Tel:"; - this.label30.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label30.Anchor = AnchorStyles.Right; + label30.AutoSize = true; + label30.Location = new System.Drawing.Point(19, 1180); + label30.Margin = new Padding(4, 0, 4, 0); + label30.Name = "label30"; + label30.Size = new System.Drawing.Size(108, 15); + label30.TabIndex = 159; + label30.Text = "Admin Contact Tel:"; + label30.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // tbAdministrativeContactName // - this.tbAdministrativeContactName.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.tbAdministrativeContactName.Location = new System.Drawing.Point(135, 1118); - this.tbAdministrativeContactName.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.tbAdministrativeContactName.Name = "tbAdministrativeContactName"; - this.tbAdministrativeContactName.Size = new System.Drawing.Size(369, 23); - this.tbAdministrativeContactName.TabIndex = 24; + tbAdministrativeContactName.Anchor = AnchorStyles.Left | AnchorStyles.Right; + tbAdministrativeContactName.Location = new System.Drawing.Point(135, 1118); + tbAdministrativeContactName.Margin = new Padding(4, 3, 20, 3); + tbAdministrativeContactName.Name = "tbAdministrativeContactName"; + tbAdministrativeContactName.Size = new System.Drawing.Size(369, 23); + tbAdministrativeContactName.TabIndex = 24; // // label29 // - this.label29.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label29.AutoSize = true; - this.label29.Location = new System.Drawing.Point(4, 1151); - this.label29.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label29.Name = "label29"; - this.label29.Size = new System.Drawing.Size(123, 15); - this.label29.TabIndex = 158; - this.label29.Text = "Admin Contact Email:"; - this.label29.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label29.Anchor = AnchorStyles.Right; + label29.AutoSize = true; + label29.Location = new System.Drawing.Point(4, 1151); + label29.Margin = new Padding(4, 0, 4, 0); + label29.Name = "label29"; + label29.Size = new System.Drawing.Size(123, 15); + label29.TabIndex = 158; + label29.Text = "Admin Contact Email:"; + label29.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label15 // - this.label15.Anchor = System.Windows.Forms.AnchorStyles.Right; - this.label15.AutoSize = true; - this.label15.Location = new System.Drawing.Point(36, 1122); - this.label15.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label15.Name = "label15"; - this.label15.Size = new System.Drawing.Size(91, 15); - this.label15.TabIndex = 157; - this.label15.Text = "Admin Contact:"; - this.label15.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label15.Anchor = AnchorStyles.Right; + label15.AutoSize = true; + label15.Location = new System.Drawing.Point(36, 1122); + label15.Margin = new Padding(4, 0, 4, 0); + label15.Name = "label15"; + label15.Size = new System.Drawing.Size(91, 15); + label15.TabIndex = 157; + label15.Text = "Admin Contact:"; + label15.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // label5 // - this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.label5.AutoSize = true; - this.label5.ForeColor = System.Drawing.Color.Black; - this.label5.Location = new System.Drawing.Point(43, 58); - this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(84, 15); - this.label5.TabIndex = 67; - this.label5.Text = "Geo Coverage:"; - this.label5.TextAlign = System.Drawing.ContentAlignment.TopRight; + label5.Anchor = AnchorStyles.Top | AnchorStyles.Right; + label5.AutoSize = true; + label5.ForeColor = System.Drawing.Color.Black; + label5.Location = new System.Drawing.Point(43, 58); + label5.Margin = new Padding(4, 0, 4, 0); + label5.Name = "label5"; + label5.Size = new System.Drawing.Size(84, 15); + label5.TabIndex = 67; + label5.Text = "Geo Coverage:"; + label5.TextAlign = System.Drawing.ContentAlignment.TopRight; // // c_tbGeographicalCoverage // - this.c_tbGeographicalCoverage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); - this.c_tbGeographicalCoverage.Location = new System.Drawing.Point(135, 61); - this.c_tbGeographicalCoverage.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.c_tbGeographicalCoverage.Multiline = true; - this.c_tbGeographicalCoverage.Name = "c_tbGeographicalCoverage"; - this.c_tbGeographicalCoverage.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.c_tbGeographicalCoverage.Size = new System.Drawing.Size(369, 100); - this.c_tbGeographicalCoverage.TabIndex = 2; + c_tbGeographicalCoverage.Anchor = AnchorStyles.Left | AnchorStyles.Right; + c_tbGeographicalCoverage.Location = new System.Drawing.Point(135, 61); + c_tbGeographicalCoverage.Margin = new Padding(4, 3, 20, 3); + c_tbGeographicalCoverage.Multiline = true; + c_tbGeographicalCoverage.Name = "c_tbGeographicalCoverage"; + c_tbGeographicalCoverage.ScrollBars = ScrollBars.Vertical; + c_tbGeographicalCoverage.Size = new System.Drawing.Size(369, 100); + c_tbGeographicalCoverage.TabIndex = 2; // // ticketingControl1 // - this.ticketingControl1.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.ticketingControl1.Location = new System.Drawing.Point(135, 437); - this.ticketingControl1.Margin = new System.Windows.Forms.Padding(4, 3, 20, 3); - this.ticketingControl1.Name = "ticketingControl1"; - this.ticketingControl1.Size = new System.Drawing.Size(350, 57); - this.ticketingControl1.TabIndex = 8; - this.ticketingControl1.TicketText = ""; + ticketingControl1.Anchor = AnchorStyles.Left; + ticketingControl1.Location = new System.Drawing.Point(135, 437); + ticketingControl1.Margin = new Padding(4, 3, 20, 3); + ticketingControl1.Name = "ticketingControl1"; + ticketingControl1.Size = new System.Drawing.Size(350, 57); + ticketingControl1.TabIndex = 8; + ticketingControl1.TicketText = ""; // // errorProvider1 // - this.errorProvider1.ContainerControl = this; + errorProvider1.ContainerControl = this; + // + // lbDatasetslbl + // + lbDatasetslbl.Anchor = AnchorStyles.Top | AnchorStyles.Right; + lbDatasetslbl.AutoSize = true; + lbDatasetslbl.Location = new System.Drawing.Point(72, 257); + lbDatasetslbl.Name = "lbDatasetslbl"; + lbDatasetslbl.Size = new System.Drawing.Size(54, 15); + lbDatasetslbl.TabIndex = 160; + lbDatasetslbl.Text = "Datasets:"; + // + // lbDatasets + // + lbDatasets.AutoSize = true; + lbDatasets.Location = new System.Drawing.Point(132, 257); + lbDatasets.Name = "lbDatasets"; + lbDatasets.Size = new System.Drawing.Size(0, 15); + lbDatasets.TabIndex = 161; // // CatalogueUI // - this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.splitContainer1); - this.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.Name = "CatalogueUI"; - this.Size = new System.Drawing.Size(551, 1085); - this.splitContainer1.Panel1.ResumeLayout(false); - this.splitContainer1.Panel2.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); - this.splitContainer1.ResumeLayout(false); - this.tableLayoutPanel1.ResumeLayout(false); - this.tableLayoutPanel1.PerformLayout(); - this.flowLayoutPanel1.ResumeLayout(false); - this.flowLayoutPanel1.PerformLayout(); - this.tableLayoutPanel2.ResumeLayout(false); - this.tableLayoutPanel2.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).EndInit(); - this.ResumeLayout(false); - + AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(splitContainer1); + Margin = new Padding(4, 3, 4, 3); + Name = "CatalogueUI"; + Size = new System.Drawing.Size(551, 1085); + splitContainer1.Panel1.ResumeLayout(false); + splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit(); + splitContainer1.ResumeLayout(false); + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + flowLayoutPanel1.ResumeLayout(false); + flowLayoutPanel1.PerformLayout(); + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)errorProvider1).EndInit(); + ResumeLayout(false); } #endregion @@ -1233,5 +1246,7 @@ private void InitializeComponent() private TextBox c_tbGeographicalCoverage; private Label label5; private TableLayoutPanel tableLayoutPanel2; + private Label lbDatasetslbl; + private Label lbDatasets; } } diff --git a/Rdmp.UI/MainFormUITabs/CatalogueUI.cs b/Rdmp.UI/MainFormUITabs/CatalogueUI.cs index b86a6e7de5..a2b6884032 100644 --- a/Rdmp.UI/MainFormUITabs/CatalogueUI.cs +++ b/Rdmp.UI/MainFormUITabs/CatalogueUI.cs @@ -5,6 +5,7 @@ // You should have received a copy of the GNU General Public License along with RDMP. If not, see . using System; +using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; @@ -122,6 +123,24 @@ public override void SetDatabaseObject(IActivateItems activator, Catalogue datab base.SetDatabaseObject(activator, databaseObject); _catalogue = databaseObject; + var associatedDatasets = _catalogue.CatalogueItems + .Select(static catalogueItem => catalogueItem.ColumnInfo.Dataset_ID) + .Where(static datasetId => datasetId != null) + .Select(datasetId => + _catalogue.CatalogueRepository.GetAllObjectsWhere("ID", datasetId).First()) + .Select(static ds=>ds.Name).ToList(); + if (associatedDatasets.Count > 0) + { + lbDatasets.Visible = true; + lbDatasetslbl.Visible = true; + var finalString = associatedDatasets.Count == 1 ? associatedDatasets[0] : string.Join(", ", associatedDatasets.ToArray(), 0, associatedDatasets.Count - 1) + " and " + associatedDatasets.LastOrDefault(); + lbDatasets.Text = $"This catalogues contains data from the datasets:{finalString}"; + } + else + { + lbDatasets.Visible = false; + lbDatasetslbl.Visible = false; + } RefreshUIFromDatabase(); } diff --git a/Rdmp.UI/MainFormUITabs/CatalogueUI.resx b/Rdmp.UI/MainFormUITabs/CatalogueUI.resx index f298a7be80..54b06b46cc 100644 --- a/Rdmp.UI/MainFormUITabs/CatalogueUI.resx +++ b/Rdmp.UI/MainFormUITabs/CatalogueUI.resx @@ -1,4 +1,64 @@ - + + + @@ -57,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/Rdmp.UI/MainFormUITabs/ExtractionProgressUI.cs b/Rdmp.UI/MainFormUITabs/ExtractionProgressUI.cs index 2396090a7d..b779f9e97c 100644 --- a/Rdmp.UI/MainFormUITabs/ExtractionProgressUI.cs +++ b/Rdmp.UI/MainFormUITabs/ExtractionProgressUI.cs @@ -62,7 +62,7 @@ public override void SetDatabaseObject(IActivateItems activator, ExtractionProgr } else { - lblEvaluationDate.Text = $"(DQE has not been run)"; + lblEvaluationDate.Text = "(DQE has not been run)"; btnFromDQE.Enabled = false; } diff --git a/Rdmp.UI/Menus/CatalogueMenu.cs b/Rdmp.UI/Menus/CatalogueMenu.cs index e4debe2e5b..d4689f85ae 100644 --- a/Rdmp.UI/Menus/CatalogueMenu.cs +++ b/Rdmp.UI/Menus/CatalogueMenu.cs @@ -24,7 +24,7 @@ internal class CatalogueMenu : RDMPContextMenuStrip public CatalogueMenu(RDMPContextMenuStripArgs args, Catalogue catalogue) : base(args, catalogue) { var isApiCall = catalogue.IsApiCall(); - + Add(new ExecuteCommandLinkCatalogueToDatasetUI(_activator, catalogue)); Add(new ExecuteCommandGenerateMetadataReport(_activator, catalogue) { Weight = -99.059f diff --git a/Rdmp.UI/Menus/ColumnInfoMenu.cs b/Rdmp.UI/Menus/ColumnInfoMenu.cs index 1ff63f0a64..3031589617 100644 --- a/Rdmp.UI/Menus/ColumnInfoMenu.cs +++ b/Rdmp.UI/Menus/ColumnInfoMenu.cs @@ -16,7 +16,7 @@ internal sealed class ColumnInfoMenu : RDMPContextMenuStrip public ColumnInfoMenu(RDMPContextMenuStripArgs args, ColumnInfo columnInfo) : base(args, columnInfo) { Add(new ExecuteCommandAddNewLookupTableRelationship(_activator, null, columnInfo.TableInfo)); - + Add(new ExecuteCommandLinkColumnInfoToDataSetUI(_activator, columnInfo)); Items.Add(new ToolStripSeparator()); Add(new ExecuteCommandAddJoinInfo(_activator, columnInfo.TableInfo)); diff --git a/Rdmp.UI/Menus/DatasetMenu.cs b/Rdmp.UI/Menus/DatasetMenu.cs new file mode 100644 index 0000000000..8326c6342e --- /dev/null +++ b/Rdmp.UI/Menus/DatasetMenu.cs @@ -0,0 +1,20 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see .using Rdmp.Core.Curation.Data; +using Rdmp.Core.Curation.Data; +using Rdmp.UI.CommandExecution.AtomicCommands; + +namespace Rdmp.UI.Menus; +/// +/// Menu item for datasets +/// +public class DatasetMenu: RDMPContextMenuStrip +{ + + public DatasetMenu(RDMPContextMenuStripArgs args, Dataset dataset): base(args, dataset) + { + Add(new ExecuteCommandDeleteDatasetUI(_activator,dataset)); + } +} diff --git a/Rdmp.UI/Menus/LoadModuleAssemblyMenu.cs b/Rdmp.UI/Menus/LoadModuleAssemblyMenu.cs new file mode 100644 index 0000000000..b3f7a6d831 --- /dev/null +++ b/Rdmp.UI/Menus/LoadModuleAssemblyMenu.cs @@ -0,0 +1,18 @@ +// Copyright (c) The University of Dundee 2018-2023 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using Rdmp.Core.Curation.Data; +using Rdmp.UI.CommandExecution.AtomicCommands; + +namespace Rdmp.UI.Menus; + +internal class LoadModuleAssemblyMenu : RDMPContextMenuStrip +{ + public LoadModuleAssemblyMenu(RDMPContextMenuStripArgs args, LoadModuleAssembly assembly) : base(args, assembly) + { + Add(new ExecuteCommandDeletePlugin(_activator, assembly)); + } +} \ No newline at end of file diff --git a/Rdmp.UI/Menus/RDMPContextMenuStrip.cs b/Rdmp.UI/Menus/RDMPContextMenuStrip.cs index f44c5d70ac..428977af85 100644 --- a/Rdmp.UI/Menus/RDMPContextMenuStrip.cs +++ b/Rdmp.UI/Menus/RDMPContextMenuStrip.cs @@ -142,13 +142,13 @@ protected void Add(IAtomicCommand cmd, Keys shortcutKey, string submenu, Image i private ToolStripMenuItem AddMenuIfNotExists(string submenu, Image image = null) { - if (!_subMenuDictionary.ContainsKey(submenu)) + if (!_subMenuDictionary.TryGetValue(submenu, out var menuItem)) { - var m = new ToolStripMenuItem(submenu, image); - _subMenuDictionary.Add(submenu, m); + menuItem = new ToolStripMenuItem(submenu, image); + _subMenuDictionary.Add(submenu, menuItem); } - return _subMenuDictionary[submenu]; + return menuItem; } public void AddCommonMenuItems(RDMPCollectionCommonFunctionality commonFunctionality) diff --git a/Rdmp.Core/Providers/Nodes/AllExpiredPluginsNode.cs b/Rdmp.UI/PieCharts/CatalogueToDatasetLinkageObjectCollection.cs similarity index 64% rename from Rdmp.Core/Providers/Nodes/AllExpiredPluginsNode.cs rename to Rdmp.UI/PieCharts/CatalogueToDatasetLinkageObjectCollection.cs index edc10e3967..9911e1c867 100644 --- a/Rdmp.Core/Providers/Nodes/AllExpiredPluginsNode.cs +++ b/Rdmp.UI/PieCharts/CatalogueToDatasetLinkageObjectCollection.cs @@ -1,14 +1,15 @@ -// Copyright (c) The University of Dundee 2018-2019 +// Copyright (c) The University of Dundee 2018-2023 // This file is part of the Research Data Management Platform (RDMP). // RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. // RDMP 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 General Public License for more details. -// You should have received a copy of the GNU General Public License along with RDMP. If not, see . +// You should have received a copy of the GNU General Public License along with RDMP. If not, see .using Rdmp.Core.Curation.Data.Dashboarding; +using Rdmp.Core.Curation.Data.Dashboarding; -namespace Rdmp.Core.Providers.Nodes; +namespace Rdmp.UI.PieCharts; -internal class AllExpiredPluginsNode : SingletonNode +/// +/// Input object for . +/// +public class CatalogueToDatasetLinkageObjectCollection : PersistableObjectCollection { - public AllExpiredPluginsNode() : base("Old Plugins") - { - } -} \ No newline at end of file +} diff --git a/Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.Designer.cs b/Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.Designer.cs new file mode 100644 index 0000000000..66739831e0 --- /dev/null +++ b/Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.Designer.cs @@ -0,0 +1,136 @@ +namespace Rdmp.UI.PieCharts +{ + partial class CatalogueToDatasetLinkagePieChartUI + { + /// + /// 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() + { + System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea(); + System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend(); + System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GoodBadCataloguePieChart)); + this.chart1 = new System.Windows.Forms.DataVisualization.Charting.Chart(); + this.gbWhatThisIs = new System.Windows.Forms.GroupBox(); + this.btnViewDataTable = new System.Windows.Forms.Button(); + this.lblNoIssues = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.chart1)).BeginInit(); + this.gbWhatThisIs.SuspendLayout(); + this.SuspendLayout(); + // + // chart1 + // + this.chart1.BackColor = System.Drawing.Color.DarkGray; + this.chart1.BackGradientStyle = System.Windows.Forms.DataVisualization.Charting.GradientStyle.TopBottom; + this.chart1.BorderSkin.PageColor = System.Drawing.Color.Black; + chartArea1.Area3DStyle.Enable3D = true; + chartArea1.Area3DStyle.WallWidth = 10; + chartArea1.BackColor = System.Drawing.Color.DarkGray; + chartArea1.BackGradientStyle = System.Windows.Forms.DataVisualization.Charting.GradientStyle.TopBottom; + chartArea1.Name = "ChartArea1"; + this.chart1.ChartAreas.Add(chartArea1); + this.chart1.Dock = System.Windows.Forms.DockStyle.Fill; + legend1.BackColor = System.Drawing.Color.Gainsboro; + legend1.BackGradientStyle = System.Windows.Forms.DataVisualization.Charting.GradientStyle.TopBottom; + legend1.BorderColor = System.Drawing.Color.White; + legend1.BorderWidth = 2; + legend1.Name = "Legend1"; + this.chart1.Legends.Add(legend1); + this.chart1.Location = new System.Drawing.Point(3, 16); + this.chart1.Name = "chart1"; + this.chart1.Palette = System.Windows.Forms.DataVisualization.Charting.ChartColorPalette.None; + this.chart1.PaletteCustomColors = new System.Drawing.Color[] { + System.Drawing.Color.Red, + System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(192)))), ((int)(((byte)(0)))))}; + series1.ChartArea = "ChartArea1"; + series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Pie; + series1.CustomProperties = "PieDrawingStyle=SoftEdge, PieLabelStyle=Disabled"; + series1.Legend = "Legend1"; + series1.Name = "Series1"; + this.chart1.Series.Add(series1); + this.chart1.Size = new System.Drawing.Size(387, 203); + this.chart1.TabIndex = 0; + this.chart1.Text = "chart1"; + // + // gbWhatThisIs + // + this.gbWhatThisIs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gbWhatThisIs.Controls.Add(this.btnViewDataTable); + this.gbWhatThisIs.Controls.Add(this.lblNoIssues); + this.gbWhatThisIs.Controls.Add(this.chart1); + this.gbWhatThisIs.Location = new System.Drawing.Point(0, 28); + this.gbWhatThisIs.Name = "gbWhatThisIs"; + this.gbWhatThisIs.Size = new System.Drawing.Size(393, 222); + this.gbWhatThisIs.TabIndex = 1; + this.gbWhatThisIs.TabStop = false; + this.gbWhatThisIs.Text = "What This Is"; + // + // btnViewDataTable + // + this.btnViewDataTable.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnViewDataTable.Image = ((System.Drawing.Image)(resources.GetObject("btnViewDataTable.Image"))); + this.btnViewDataTable.Location = new System.Drawing.Point(360, 193); + this.btnViewDataTable.Name = "btnViewDataTable"; + this.btnViewDataTable.Size = new System.Drawing.Size(27, 23); + this.btnViewDataTable.TabIndex = 4; + this.btnViewDataTable.UseVisualStyleBackColor = true; + this.btnViewDataTable.Click += new System.EventHandler(this.btnViewDataTable_Click); + // + // lblNoIssues + // + this.lblNoIssues.Anchor = System.Windows.Forms.AnchorStyles.None; + this.lblNoIssues.AutoSize = true; + this.lblNoIssues.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblNoIssues.Location = new System.Drawing.Point(100, 111); + this.lblNoIssues.Name = "lblNoIssues"; + this.lblNoIssues.Size = new System.Drawing.Size(153, 13); + this.lblNoIssues.TabIndex = 1; + this.lblNoIssues.Text = "No Issues Reported In Dataset"; + // + // GoodBadCataloguePieChart + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.gbWhatThisIs); + this.Name = "GoodBadCataloguePieChart"; + this.Size = new System.Drawing.Size(393, 250); + ((System.ComponentModel.ISupportInitialize)(this.chart1)).EndInit(); + this.gbWhatThisIs.ResumeLayout(false); + this.gbWhatThisIs.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.DataVisualization.Charting.Chart chart1; + private System.Windows.Forms.GroupBox gbWhatThisIs; + private System.Windows.Forms.Label lblNoIssues; + private System.Windows.Forms.Button btnViewDataTable; + } +} diff --git a/Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.cs b/Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.cs new file mode 100644 index 0000000000..e08d7786ae --- /dev/null +++ b/Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.cs @@ -0,0 +1,303 @@ +// Copyright (c) The University of Dundee 2018-2019 +// This file is part of the Research Data Management Platform (RDMP). +// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +// RDMP 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 General Public License for more details. +// You should have received a copy of the GNU General Public License along with RDMP. If not, see . + +using System; +using System.Collections.Generic; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using Rdmp.Core.CommandExecution; +using Rdmp.Core.CommandExecution.AtomicCommands; +using Rdmp.Core.Curation.Data; +using Rdmp.Core.Curation.Data.Dashboarding; +using Rdmp.Core.Icons.IconProvision; +using Rdmp.UI.DashboardTabs.Construction; +using Rdmp.UI.ItemActivation; +using Rdmp.UI.Refreshing; +using Rdmp.UI.SimpleDialogs; +using Rdmp.UI.TestsAndSetup.ServicePropogation; + + +namespace Rdmp.UI.PieCharts; + +/// +/// Part of OverviewScreen, shows a pie chart showing how many columns there are which do not yet have associated datasets in the Data Catalogue Database (See CatalogueItemUI) +/// +/// Each of these can either be displayed for a single catalogue or as a combined total across all active catalogues (not deprecated / internal etc) +/// +/// +public partial class CatalogueToDatasetLinkagePieChartUI : RDMPUserControl, IDashboardableControl +{ + private readonly ToolStripButton _btnSingleCatalogue = new("Single", CatalogueIcons.Catalogue.ImageToBitmap()) + { Name = "btnSingleCatalogue" }; + + private readonly ToolStripButton _btnAllCatalogues = + new("All", CatalogueIcons.AllCataloguesUsedByLoadMetadataNode.ImageToBitmap()) { Name = "btnAllCatalogues" }; + + private readonly ToolStripButton _btnRefresh = new("Refresh", FamFamFamIcons.text_list_bullets.ImageToBitmap()) + { Name = "btnRefresh" }; + + private readonly ToolStripLabel _toolStripLabel1 = new("Type:") { Name = "toolStripLabel1" }; + + private readonly ToolStripButton _btnShowLabels = new("Labels", FamFamFamIcons.text_align_left.ImageToBitmap()) + { Name = "btnShowLabels", CheckOnClick = true }; + + private readonly List _flagOptions = new(); + + public CatalogueToDatasetLinkagePieChartUI() + { + InitializeComponent(); + + btnViewDataTable.Image = CatalogueIcons.TableInfo.ImageToBitmap(); + + _btnAllCatalogues.Click += btnAllCatalogues_Click; + _btnSingleCatalogue.Click += btnSingleCatalogue_Click; + _btnShowLabels.CheckStateChanged += btnShowLabels_CheckStateChanged; + _btnRefresh.Click += btnRefresh_Click; + + //put edit mode on for the designer + NotifyEditModeChange(false); + } + + private void SetupFlags() + { + if (!_firstTime) + return; + + AddFlag("Non Extractable Catalogues", c => c.IncludeNonExtractableCatalogues, + (c, r) => c.IncludeNonExtractableCatalogues = r); + AddFlag("Deprecated Catalogues", c => c.IncludeDeprecatedCatalogues, + (c, r) => c.IncludeDeprecatedCatalogues = r); + AddFlag("Internal Catalogues", c => c.IncludeInternalCatalogues, (c, r) => c.IncludeInternalCatalogues = r); + AddFlag("Cold Storage Catalogues", c => c.IncludeColdStorageCatalogues, + (c, r) => c.IncludeColdStorageCatalogues = r); + AddFlag("Project Specific Catalogues", c => c.IncludeProjectSpecificCatalogues, + (c, r) => c.IncludeProjectSpecificCatalogues = r); + + AddFlag("Non Extractable CatalogueItems", c => c.IncludeNonExtractableCatalogueItems, + (c, r) => c.IncludeNonExtractableCatalogueItems = r); + AddFlag("Internal Catalogue Items", c => c.IncludeInternalCatalogueItems, + (c, r) => c.IncludeInternalCatalogueItems = r); + AddFlag("Deprecated Catalogue Items", c => c.IncludeDeprecatedCatalogueItems, + (c, r) => c.IncludeDeprecatedCatalogueItems = r); + _firstTime = false; + } + + private void AddFlag(string caption, Func getProp, + Action setProp) + { + var btn = new ToolStripMenuItem(caption) + { + Checked = getProp(_collection) + }; + btn.CheckedChanged += (sender, e) => { setProp(_collection, ((ToolStripMenuItem)sender).Checked); }; + btn.CheckedChanged += (s, e) => GenerateChart(); + btn.CheckOnClick = true; + _flagOptions.Add(btn); + } + + private DashboardControl _dashboardControlDatabaseRecord; + private GoodBadCataloguePieChartObjectCollection _collection; + + private void GenerateChart() + { + chart1.Visible = false; + lblNoIssues.Visible = false; + + gbWhatThisIs.Text = _collection.IsSingleCatalogueMode + ? $"Column Descriptions in {_collection.GetSingleCatalogueModeCatalogue()}" + : "Column Descriptions"; + + PopulateAsEmptyDescriptionsChart(); + } + + private void PopulateAsEmptyDescriptionsChart() + { + try + { + var catalogueItems = GetCatalogueItems(); + + if (!catalogueItems.Any()) + { + chart1.DataSource = null; + chart1.Visible = false; + lblNoIssues.Visible = true; + + return; + } + + var countPopulated = 0; + var countNotPopulated = 0; + foreach (var ci in catalogueItems) + if (ci.ColumnInfo.Dataset_ID is null) + countNotPopulated++; + else + countPopulated++; + + var dt = new DataTable(); + dt.Columns.Add("Count"); + dt.Columns.Add("State"); + + dt.Rows.Add(new object[] { countNotPopulated, $"Missing ({countNotPopulated})" }); + dt.Rows.Add(new object[] { countPopulated, $"Populated ({countPopulated})" }); + + chart1.Series[0].XValueMember = dt.Columns[1].ColumnName; + chart1.Series[0].YValueMembers = dt.Columns[0].ColumnName; + + chart1.DataSource = dt; + chart1.DataBind(); + chart1.Visible = true; + lblNoIssues.Visible = false; + } + catch (Exception e) + { + ExceptionViewer.Show($"{GetType().Name} failed to load data", e); + } + } + + private CatalogueItem[] GetCatalogueItems() + { + if (!_collection.IsSingleCatalogueMode) + { + var catalogues = Activator.CoreChildProvider.AllCatalogues + .Where(c => _collection.Include(c, Activator.RepositoryLocator.DataExportRepository)).ToArray(); + + //if there are some + return catalogues.Any() + ? catalogues.SelectMany(c => c.CatalogueItems).Where(ci => _collection.Include(ci)).ToArray() + : //get the extractable columns + Array.Empty(); //there weren't any so Catalogues so won't be any ExtractionInformationsEither + } + + return _collection.GetSingleCatalogueModeCatalogue().CatalogueItems; + } + + public void RefreshBus_RefreshObject(object sender, RefreshObjectEventArgs e) + { + } + + private bool _bLoading; + private bool _firstTime = true; + + public void SetCollection(IActivateItems activator, IPersistableObjectCollection collection) + { + _bLoading = true; + SetItemActivator(activator); + + _collection = (GoodBadCataloguePieChartObjectCollection)collection; + + if (_firstTime) + SetupFlags(); + + _btnAllCatalogues.Checked = !_collection.IsSingleCatalogueMode; + _btnSingleCatalogue.Checked = _collection.IsSingleCatalogueMode; + _btnShowLabels.Checked = _collection.ShowLabels; + + CommonFunctionality.Add(_btnAllCatalogues); + CommonFunctionality.Add(_toolStripLabel1); + CommonFunctionality.Add(_btnAllCatalogues); + CommonFunctionality.Add(_btnSingleCatalogue); + CommonFunctionality.Add(_btnShowLabels); + CommonFunctionality.Add(_btnRefresh); + + foreach (var mi in _flagOptions) + CommonFunctionality.AddToMenu(mi); + + GenerateChart(); + _bLoading = false; + } + + public IPersistableObjectCollection GetCollection() => _collection; + + public string GetTabName() => Text; + + public string GetTabToolTip() => null; + + public IPersistableObjectCollection ConstructEmptyCollection(DashboardControl databaseRecord) + { + _dashboardControlDatabaseRecord = databaseRecord; + + return new GoodBadCataloguePieChartObjectCollection(); + } + + public void NotifyEditModeChange(bool isEditModeOn) + { + var l = new Point(Margin.Left, Margin.Right); + var s = new Size(Width - Margin.Horizontal, Height - Margin.Vertical); + + CommonFunctionality.ToolStrip.Visible = isEditModeOn; + + if (isEditModeOn) + { + gbWhatThisIs.Location = l with { Y = l.Y + 25 }; //move it down 25 to allow space for tool bar + gbWhatThisIs.Size = s with { Height = s.Height - 25 }; //and adjust height accordingly + } + else + { + gbWhatThisIs.Location = l; + gbWhatThisIs.Size = s; + } + } + + private void btnAllCatalogues_Click(object sender, EventArgs e) + { + _btnAllCatalogues.Checked = true; + _btnSingleCatalogue.Checked = false; + _collection.SetAllCataloguesMode(); + GenerateChart(); + SaveCollectionChanges(); + } + + private void btnSingleCatalogue_Click(object sender, EventArgs e) + { + if (!Activator.SelectObject(new DialogArgs + { + TaskDescription = "Which Catalogue should the graph depict?" + }, Activator.RepositoryLocator.CatalogueRepository.GetAllObjects(), out var selected)) return; + _collection.SetSingleCatalogueMode(selected); + + _btnAllCatalogues.Checked = false; + _btnSingleCatalogue.Checked = true; + + SaveCollectionChanges(); + GenerateChart(); + } + + private void btnRefresh_Click(object sender, EventArgs e) + { + GenerateChart(); + } + + private void SaveCollectionChanges() + { + if (_bLoading) + return; + + _dashboardControlDatabaseRecord.SaveCollectionState(_collection); + } + + private void btnShowLabels_CheckStateChanged(object sender, EventArgs e) + { + _collection.ShowLabels = _btnShowLabels.Checked; + + chart1.Series[0]["PieLabelStyle"] = _collection.ShowLabels ? "Inside" : "Disabled"; + SaveCollectionChanges(); + } + + private void btnViewDataTable_Click(object sender, EventArgs e) + { + if (Activator.SelectObject(new DialogArgs + { + TaskDescription = + "The following CatalogueItem(s) do not currently have descriptions. Select one to navigate to it" + }, GetCatalogueItems().Where(ci => string.IsNullOrWhiteSpace(ci.Description)).ToArray(), out var selected)) + { + var cmd = new ExecuteCommandShow(Activator, selected, 1); + cmd.Execute(); + } + } +} \ No newline at end of file diff --git a/Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.resx b/Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.resx new file mode 100644 index 0000000000..cf09fa6f52 --- /dev/null +++ b/Rdmp.UI/PieCharts/CatalogueToDatasetLinkagePieChartUI.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + 17, 17 + + \ No newline at end of file diff --git a/Rdmp.UI/Progress/ProgressUI.cs b/Rdmp.UI/Progress/ProgressUI.cs index ff1648037f..a7e7a9b4c3 100644 --- a/Rdmp.UI/Progress/ProgressUI.cs +++ b/Rdmp.UI/Progress/ProgressUI.cs @@ -224,7 +224,7 @@ private void ProcessAndClearQueuedProgressMessages(object sender, EventArgs e) { ProgressType.Records => "records", ProgressType.Kilobytes => "KB", - _ => throw new ArgumentOutOfRangeException("type") + _ => throw new InvalidOperationException("type") }; var handledByFlood = HandleFloodOfMessagesFromJob(message.Value.Sender, args.TaskDescription, @@ -251,14 +251,13 @@ private void ProcessAndClearQueuedProgressMessages(object sender, EventArgs e) { if (_notificationQueue.Any()) { + olvProgressEvents.BeginUpdate(); olvProgressEvents.AddObjects(_notificationQueue); + olvProgressEvents.EndUpdate(); _notificationQueue.Clear(); - AutoResizeColumns(); } } - - olvProgressEvents.Sort(); } private void AutoResizeColumns() diff --git a/Rdmp.UI/ProjectUI/Datasets/ConfigureDatasetUI.cs b/Rdmp.UI/ProjectUI/Datasets/ConfigureDatasetUI.cs index fbeada3b42..5a837f9e57 100644 --- a/Rdmp.UI/ProjectUI/Datasets/ConfigureDatasetUI.cs +++ b/Rdmp.UI/ProjectUI/Datasets/ConfigureDatasetUI.cs @@ -488,7 +488,7 @@ private void HandleReorder(ModelDropEventArgs e) private void HandleReorder(ExtractableColumn sourceColumn, IOrderable targetOrderable, DropTargetLocation location) { - targetOrderable ??= olvSelected.Objects.Cast().MaxBy(o => o.Order); + targetOrderable ??= olvSelected.Objects.Cast().MaxBy(static o => o.Order); if (targetOrderable == null) return; @@ -500,12 +500,12 @@ private void HandleReorder(ExtractableColumn sourceColumn, IOrderable targetOrde case DropTargetLocation.AboveItem: //bump down the other columns - foreach (var c in olvSelected.Objects.OfType().ToArray()) - if (c.Order >= destinationOrder && !Equals(c, sourceColumn)) - { - c.Order++; - c.SaveToDatabase(); - } + foreach (var c in olvSelected.Objects.OfType().ToArray() + .Where(c => c.Order >= destinationOrder && !Equals(c, sourceColumn))) + { + c.Order++; + c.SaveToDatabase(); + } //should now be space at the destination order position sourceColumn.Order = destinationOrder; @@ -514,17 +514,17 @@ private void HandleReorder(ExtractableColumn sourceColumn, IOrderable targetOrde case DropTargetLocation.BelowItem: //bump up other columns - foreach (var c in olvSelected.Objects.OfType().ToArray()) - if (c.Order <= destinationOrder && !Equals(c, sourceColumn)) - { - c.Order--; - c.SaveToDatabase(); - } + foreach (var c in olvSelected.Objects.OfType().ToArray() + .Where(c => c.Order <= destinationOrder && !Equals(c, sourceColumn))) + { + c.Order--; + c.SaveToDatabase(); + } sourceColumn.Order = destinationOrder; break; default: - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(location)); } sourceColumn.SaveToDatabase(); diff --git a/Rdmp.UI/ProjectUI/ExecuteExtractionUI.cs b/Rdmp.UI/ProjectUI/ExecuteExtractionUI.cs index 2b194f77ca..e15547a4f5 100644 --- a/Rdmp.UI/ProjectUI/ExecuteExtractionUI.cs +++ b/Rdmp.UI/ProjectUI/ExecuteExtractionUI.cs @@ -149,7 +149,7 @@ private HelpWorkflow BuildHelpFlow() private void CheckAndExecuteUI1OnStateChanged(object sender, EventArgs eventArgs) { - tlvDatasets.RefreshObjects(tlvDatasets.Objects.Cast().ToArray()); + tlvDatasets.Refresh(); } private bool CanExpandGetter(object model) diff --git a/Rdmp.UI/ProjectUI/ExtractCommandStateMonitor.cs b/Rdmp.UI/ProjectUI/ExtractCommandStateMonitor.cs index f98a39534d..7e7f8850af 100644 --- a/Rdmp.UI/ProjectUI/ExtractCommandStateMonitor.cs +++ b/Rdmp.UI/ProjectUI/ExtractCommandStateMonitor.cs @@ -52,15 +52,15 @@ public void SaveState(GlobalsBundle globals) public IEnumerable GetAllChangedObjects(GlobalsBundle globals) { - foreach (var (key, value) in globals.States) - if (!GlobalsStates.ContainsKey(key)) + foreach (var (key, state) in globals.States) + if (!GlobalsStates.TryGetValue(key, out var commandState)) { - GlobalsStates.Add(key, value); + GlobalsStates.Add(key, state); yield return key; //new objects also are returned as changed } else //State has changed since last save - if (GlobalsStates[key] != value) + if (commandState != state) { yield return key; } diff --git a/Rdmp.UI/Rdmp.UI.csproj b/Rdmp.UI/Rdmp.UI.csproj index e7ab6abfda..3b3f0493ab 100644 --- a/Rdmp.UI/Rdmp.UI.csproj +++ b/Rdmp.UI/Rdmp.UI.csproj @@ -43,21 +43,15 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - all - runtime; build; native; contentfiles; analyzers - - - - + @@ -117,6 +111,9 @@ AtomicCommandLinkLabel.cs + + UserControl + True True diff --git a/Rdmp.UI/Refreshing/RefreshBus.cs b/Rdmp.UI/Refreshing/RefreshBus.cs index 2a3aa3c580..590342de85 100644 --- a/Rdmp.UI/Refreshing/RefreshBus.cs +++ b/Rdmp.UI/Refreshing/RefreshBus.cs @@ -139,7 +139,7 @@ public void EstablishLifetimeSubscription(ILifetimeSubscriber c) public void EstablishSelfDestructProtocol(RDMPSingleDatabaseObjectControl user, IActivateItems activator, T originalObject) where T : DatabaseEntity { - //they already subscribed to self destruct protocols - repeat subscriptions can be caused by registering in SetDatabaseObject and then refresh callbacks triggering more calls to SetDatabaseObject within the Controls lifetime + //they already subscribed to self-destruct protocols - repeat subscriptions can be caused by registering in SetDatabaseObject and then refresh callbacks triggering more calls to SetDatabaseObject within the Controls lifetime var existingSubscription = _selfDestructors.OfType>().SingleOrDefault(s => s.User == user); @@ -164,7 +164,7 @@ public void EstablishSelfDestructProtocol(RDMPSingleDatabaseObjectControl var parentForm = user.ParentForm ?? throw new ArgumentException( "Control must have an established ParentForm, you should not attempt to establish a lifetime subscription until your control is loaded (i.e. don't call this in your constructor)", - "c"); + nameof(user)); //when their parent closes we unsubscribe them parentForm.FormClosed += (s, e) => diff --git a/Rdmp.UI/SimpleControls/ObjectSaverButton.cs b/Rdmp.UI/SimpleControls/ObjectSaverButton.cs index 8a8da1ab75..4f13b38999 100644 --- a/Rdmp.UI/SimpleControls/ObjectSaverButton.cs +++ b/Rdmp.UI/SimpleControls/ObjectSaverButton.cs @@ -25,13 +25,13 @@ namespace Rdmp.UI.SimpleControls; /// and call SetupFor on the DatabaseObject. You should also mark your control as ISaveableUI and implement the single method on that interface so that shortcuts /// are correctly routed to this control. /// -public partial class ObjectSaverButton +public class ObjectSaverButton { - private Bitmap _undoImage; - private Bitmap _redoImage; + private static readonly Bitmap UndoImage = FamFamFamIcons.Undo.ImageToBitmap(); + private static readonly Bitmap RedoImage = FamFamFamIcons.Redo.ImageToBitmap(); - private ToolStripButton btnSave = new("Save", FamFamFamIcons.disk.ImageToBitmap()); - private ToolStripButton btnUndoRedo = new("Undo", FamFamFamIcons.Undo.ImageToBitmap()); + private readonly ToolStripButton _btnSave = new("Save", FamFamFamIcons.disk.ImageToBitmap()); + private readonly ToolStripButton _btnUndoRedo = new("Undo", FamFamFamIcons.Undo.ImageToBitmap()); private RevertableObjectReport _undoneChanges; private IRDMPControl _parent; @@ -39,13 +39,8 @@ public partial class ObjectSaverButton public ObjectSaverButton() { - btnSave.Click += btnSave_Click; - btnUndoRedo.Click += btnUndoRedo_Click; - - _undoImage = FamFamFamIcons.Undo.ImageToBitmap(); - _redoImage = FamFamFamIcons.Redo.ImageToBitmap(); - - btnUndoRedo.Image = _undoImage; + _btnSave.Click += btnSave_Click; + _btnUndoRedo.Click += btnUndoRedo_Click; } private DatabaseEntity _o; @@ -53,7 +48,7 @@ public ObjectSaverButton() public event Action AfterSave; /// - /// Function to carry out some kind of proceedure before the object is saved. Return true if you want the save to carry on and be applied or false to abandon the save attempt. + /// Function to carry out some kind of procedure before the object is saved. Return true if you want the save to carry on and be applied or false to abandon the save attempt. /// public event Func BeforeSave; @@ -62,8 +57,8 @@ public ObjectSaverButton() public void SetupFor(IRDMPControl control, DatabaseEntity o, IActivateItems activator) { - control.CommonFunctionality.Add(btnSave); - control.CommonFunctionality.Add(btnUndoRedo); + control.CommonFunctionality.Add(_btnSave); + control.CommonFunctionality.Add(_btnUndoRedo); var f = (control as Form ?? ((Control)control).FindForm()) ?? throw new NotSupportedException( @@ -116,8 +111,8 @@ public void Enable(bool b) _parent.SetUnSavedChanges(b); - btnSave.Enabled = b; - btnUndoRedo.Enabled = b; + _btnSave.Enabled = b; + _btnUndoRedo.Enabled = b; _isEnabled = b; } @@ -158,20 +153,19 @@ private void btnUndoRedo_Click(object sender, EventArgs e) public void Redo() { - if (_undoneChanges is { Evaluation: ChangeDescription.DatabaseCopyDifferent }) - { - foreach (var difference in _undoneChanges.Differences) - difference.Property.SetValue(_o, difference.LocalValue); + if (_undoneChanges is not { Evaluation: ChangeDescription.DatabaseCopyDifferent }) return; - SetReadyToUndo(); - } + foreach (var difference in _undoneChanges.Differences) + difference.Property.SetValue(_o, difference.LocalValue); + + SetReadyToUndo(); } public void Undo() { var changes = _o.HasLocalChanges(); - //no changes anyway user must have made a change and then unapplyed it + //no changes anyway user must have made a change and then reverted it if (changes.Evaluation != ChangeDescription.DatabaseCopyDifferent) return; @@ -194,59 +188,53 @@ private void SetReadyToRedo(RevertableObjectReport changes) _undoneChanges = changes; _undo = false; - btnUndoRedo.Image = _redoImage; - btnUndoRedo.Text = "Redo"; + _btnUndoRedo.Image = RedoImage; + _btnUndoRedo.Text = "Redo"; } private void SetReadyToUndo() { _undo = true; - btnUndoRedo.Image = _undoImage; + _btnUndoRedo.Image = UndoImage; _undoneChanges = null; - btnUndoRedo.Text = "Undo"; + _btnUndoRedo.Text = "Undo"; } public void CheckForOutOfDateObjectAndOfferToFix() { - if (IsDifferent()) - if ( - //if we didn't think there were changes - !_isEnabled && - - //but there are! - _activator.ShouldReloadFreshCopy(_o)) - { - _o.RevertToDatabaseState(); - - //if we are not in the middle of a publish already - if (!_activator.RefreshBus.PublishInProgress) - _activator.RefreshBus.Publish(this, new RefreshObjectEventArgs(_o)); - } + if (!IsDifferent()) return; + + if ( + //if we didn't think there were changes + !_isEnabled && + + //but there are! + _activator.ShouldReloadFreshCopy(_o)) + { + _o.RevertToDatabaseState(); + + //if we are not in the middle of publishing already + if (!_activator.RefreshBus.PublishInProgress) + _activator.RefreshBus.Publish(this, new RefreshObjectEventArgs(_o)); + } } private bool IsDifferent() { - if (_o == null) - return false; - - var changes = _o.HasLocalChanges(); + var changes = _o?.HasLocalChanges(); //are there changes - if (changes.Evaluation == ChangeDescription.DatabaseCopyDifferent) - return changes.Differences.Any(); //are the changes to properties - - return false; + return changes?.Evaluation == ChangeDescription.DatabaseCopyDifferent && changes.Differences.Any(); //are there changes to properties } public void CheckForUnsavedChangesAnOfferToSave() { - // If there is no object or it does not exist don't try to save it - if (_o == null || !_o.Exists()) + // If there is no object, or it does not exist don't try to save it + if (_o == null || !_o.Exists() || !_isEnabled) return; - if (_isEnabled) - if (_activator.YesNo($"Save Changes To '{_o}'?", "Save Changes")) - Save(); - else - _o.RevertToDatabaseState(); + if (_activator.YesNo($"Save Changes To '{_o}'?", "Save Changes")) + Save(); + else + _o.RevertToDatabaseState(); } } \ No newline at end of file diff --git a/Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.Designer.cs b/Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.Designer.cs new file mode 100644 index 0000000000..1b07484472 --- /dev/null +++ b/Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.Designer.cs @@ -0,0 +1,139 @@ +namespace Rdmp.UI.SimpleDialogs.Datasets +{ + partial class CreateNewDatasetUI + { + /// + /// 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 Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + tbName = new System.Windows.Forms.TextBox(); + label1 = new System.Windows.Forms.Label(); + tbDOI = new System.Windows.Forms.TextBox(); + label2 = new System.Windows.Forms.Label(); + label3 = new System.Windows.Forms.Label(); + tbSource = new System.Windows.Forms.TextBox(); + btnCancel = new System.Windows.Forms.Button(); + btnCreate = new System.Windows.Forms.Button(); + SuspendLayout(); + // + // tbName + // + tbName.Location = new System.Drawing.Point(64, 75); + tbName.Name = "tbName"; + tbName.Size = new System.Drawing.Size(301, 23); + tbName.TabIndex = 0; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new System.Drawing.Point(66, 52); + label1.Name = "label1"; + label1.Size = new System.Drawing.Size(113, 15); + label1.TabIndex = 1; + label1.Text = "1. Name the Dataset"; + // + // tbDOI + // + tbDOI.Location = new System.Drawing.Point(64, 142); + tbDOI.Name = "tbDOI"; + tbDOI.Size = new System.Drawing.Size(301, 23); + tbDOI.TabIndex = 2; + // + // label2 + // + label2.AutoSize = true; + label2.Location = new System.Drawing.Point(64, 124); + label2.Name = "label2"; + label2.Size = new System.Drawing.Size(106, 15); + label2.TabIndex = 3; + label2.Text = "2. What is the DOI?"; + // + // label3 + // + label3.AutoSize = true; + label3.Location = new System.Drawing.Point(66, 185); + label3.Name = "label3"; + label3.Size = new System.Drawing.Size(200, 15); + label3.TabIndex = 4; + label3.Text = "3. What is the Source of this Dataset?"; + // + // tbSource + // + tbSource.Location = new System.Drawing.Point(64, 203); + tbSource.Name = "tbSource"; + tbSource.Size = new System.Drawing.Size(301, 23); + tbSource.TabIndex = 5; + // + // btnCancel + // + btnCancel.Location = new System.Drawing.Point(191, 270); + btnCancel.Name = "btnCancel"; + btnCancel.Size = new System.Drawing.Size(75, 23); + btnCancel.TabIndex = 6; + btnCancel.Text = "Cancel"; + btnCancel.UseVisualStyleBackColor = true; + btnCancel.Click += btnCancel_Click; + // + // btnCreate + // + btnCreate.Location = new System.Drawing.Point(290, 270); + btnCreate.Name = "btnCreate"; + btnCreate.Size = new System.Drawing.Size(75, 23); + btnCreate.TabIndex = 7; + btnCreate.Text = "Create"; + btnCreate.UseVisualStyleBackColor = true; + btnCreate.Click += btnCreate_Click; + // + // CreateNewDatasetUI + // + AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + ClientSize = new System.Drawing.Size(425, 346); + Controls.Add(btnCreate); + Controls.Add(btnCancel); + Controls.Add(tbSource); + Controls.Add(label3); + Controls.Add(label2); + Controls.Add(tbDOI); + Controls.Add(label1); + Controls.Add(tbName); + Name = "CreateNewDatasetUI"; + Text = "Create a new Dataset"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private System.Windows.Forms.TextBox tbName; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox tbDOI; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox tbSource; + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Button btnCreate; + } +} \ No newline at end of file diff --git a/Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.cs b/Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.cs new file mode 100644 index 0000000000..7972539175 --- /dev/null +++ b/Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.cs @@ -0,0 +1,31 @@ +using Rdmp.Core.CommandExecution.AtomicCommands; +using Rdmp.UI.CommandExecution.AtomicCommands; +using Rdmp.UI.ItemActivation; +using Rdmp.UI.TestsAndSetup.ServicePropogation; +using System; + +namespace Rdmp.UI.SimpleDialogs.Datasets; + +public partial class CreateNewDatasetUI : RDMPForm +{ + private readonly IActivateItems _activator; + public CreateNewDatasetUI(IActivateItems activator, ExecuteCommandCreateNewDatasetUI command) : base(activator) + { + _activator = activator; + InitializeComponent(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + Close(); + } + + private void btnCreate_Click(object sender, EventArgs e) + { + var cmd = new ExecuteCommandCreateDataset(_activator,tbName.Text,tbDOI.Text,tbSource.Text); + cmd.Execute(); + Close(); + } + + +} \ No newline at end of file diff --git a/Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.resx b/Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.resx new file mode 100644 index 0000000000..af32865ec1 --- /dev/null +++ b/Rdmp.UI/SimpleDialogs/Datasets/CreateNewDatasetUI.resx @@ -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 diff --git a/Rdmp.UI/SimpleDialogs/ForwardEngineering/ConfigureCatalogueExtractabilityUI.cs b/Rdmp.UI/SimpleDialogs/ForwardEngineering/ConfigureCatalogueExtractabilityUI.cs index a79c8f8bfd..2eb50687b4 100644 --- a/Rdmp.UI/SimpleDialogs/ForwardEngineering/ConfigureCatalogueExtractabilityUI.cs +++ b/Rdmp.UI/SimpleDialogs/ForwardEngineering/ConfigureCatalogueExtractabilityUI.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.Drawing; using System.Linq; +using System.Text; using System.Windows.Forms; using BrightIdeasSoftware; using FAnsi.Discovery; @@ -392,18 +393,22 @@ private void ddCategoriseMany_SelectedIndexChanged(object sender, EventArgs e) { var filteredObjects = olvColumnExtractability.FilteredObjects.Cast().ToArray(); var toChangeTo = ddCategoriseMany.SelectedItem; + var itemsToChange = filteredObjects.Where(obj => obj.ExtractionInformation is null || !obj.ExtractionInformation.ExtractionCategory.Equals(toChangeTo)).Select(static cp => cp.CatalogueItem.Name).ToArray(); + var columnChangeDetails = itemsToChange.Length < 3 + ? new StringBuilder().AppendJoin(", ", itemsToChange[..^1]) + .Append(itemsToChange.Length > 1 ? " and " : "").Append(itemsToChange[^1]).ToString() + : $"{(itemsToChange.Length == filteredObjects.Length ? "all " : "")}{itemsToChange.Length} columns"; + + if (MessageBox.Show($"Set {columnChangeDetails} to '{toChangeTo}'?", + "Confirm Overwrite?", MessageBoxButtons.OKCancel) != DialogResult.OK) return; + + foreach (var o in filteredObjects) + if (toChangeTo.Equals(NotExtractable)) + MakeExtractable(o, false); + else + MakeExtractable(o, true, (ExtractionCategory)toChangeTo); - if (MessageBox.Show($"Set {filteredObjects.Length} to '{toChangeTo}'?", - "Confirm Overwrite?", MessageBoxButtons.OKCancel) == DialogResult.OK) - { - foreach (object o in filteredObjects) - if (toChangeTo.Equals(NotExtractable)) - MakeExtractable(o, false); - else - MakeExtractable(o, true, (ExtractionCategory)toChangeTo); - - _ddChangeAllChanged = true; - } + _ddChangeAllChanged = true; } private void FinaliseExtractability() diff --git a/Rdmp.UI/SimpleDialogs/SelectDialog`1.resx b/Rdmp.UI/SimpleDialogs/SelectDialog`1.resx index 68cc010e31..6252b1ef07 100644 --- a/Rdmp.UI/SimpleDialogs/SelectDialog`1.resx +++ b/Rdmp.UI/SimpleDialogs/SelectDialog`1.resx @@ -57,926 +57,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 17, 17 + + True - - - - R0lGODlhZABkAPcAAPhw5P7+/v78/vLc8P5K5P4g3P4K2v6a8Pym7vxE4Pw24PTE7vy68vyi8Pb29v5q - 6P484P4W2v6q8vx86PqW6vz6/Pj4+Ppq5PpM4PiO6Pz6+viC5vh45vi68PiK6Pz4/Pzr+fj2+PbE8Paa - 6PrO8vTS8PLy8vTM7vj0+Pjt9vTw8vTs9PLs8v5a5v4w4Pxg5vqM6v5x6P464v4a3PyS7Pqi7vpu5vpm - 5Piy7viA6Pau7Pbn9Pai6PTW7vyF7Pqd7PqY7Pic7PqE6PyE6vx+6vx86viW6vas6vxC4PTo8vxU5PzU - 9v4Y2vTm8v4c3P5Y5P5M5Ppu5Pps5Ppc5Pjc8/bW8PxI4vxC4vTi8P4q3vxG4Pw+4P5A4PTg8v4e3P4o - 3v4k3v4i3v4e3v4m3P4W3PTc8vjI8PbS8PzH9PbM8Pqz8PzC8vjC8P5C4vi88P5I5Py+8vy88vut8P6q - 8Pyo8P6i8Pym8Pyk8PqQ6v566vqK6vp+6PqO6vpw5viK5vpg5PqI6v5/6/6K7vye7vyK7PyI6vyA6vyC - 6vx16Pxc5PxM4vxK4PxI4Pi47va27Pig6vie6v6Q7fyM6vxv5/6c7vyO6vyO7PyQ7Pxr5/5i5vqm7vqg - 7P5W5Pxi5vyg7vqm7PxY5Pqo7v5U5Pqq7v6x8v5S5Pqs7v5Q5P669Pqw7v5O5Pqy7vxK4va87P689PbA - 7vz8/P7S9/464P4t3/444P424P404P4y4PxS4v76/v7n+vro9/ya7vxe5PyW7Pxe5vxg5Pp05vxk5Prf - 9vy48vyS7vp25vzb9/qC6P7E9f7g+P76/Pp45vbW8vq68Pp66Pz4+vrA8vr4+fz0/PrX9ffw9/Xx9Pbu - 9PzY9/ji9PbS8vjT8vbQ8vzN9fu28fzC8/jE8PjA8Py99Puw8Pyq8P6o8P649P7A9P78/P7a+P7w/Pry - +Prj9/zh+P7L9v7j+vbf8vrI8vy28vyv8vzy+vrO9P546vqk7vyJ6/jK8P6I7P4w3vrs+Pz2/Pz2+gAA - ACH5BAAFAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAZABkAAAI/gADCBxIsKDBgwgTCtTgwIRDBxUU - SpxIsaLFiwJR6GnzxkO1iBhDihwZkpCMkzL4aCDJsqVLgRXaoJRBYOXLmzgphpgpA4LNnECDDnTA06fQ - owhhSZMG0qK1otJCwtIAC+lFaeMmxRjXlOLTmRCiWqzgSZSSTRasVrxDoC0BBBe/ogxrERaNLHizUJBW - VW3CCk/cEjjFzilUi2Vc5M0CwUFfvwcrqBJMwEdXhXJP0qXo4MLiLLfSQk44hDKBehVVHKb46nMWG49H - GxwGhTImsRJVg8WNWdFnF1Rk/6VgWg1F3XN5J33kWk9s4QVTBBb8ZN1E5JqVH9wh4zOEFNAT/sLCYZrX - c4PYe2ovKC2H61HhFTrARFnVsNyrE5aY9VnJ+vgDpWHaBJcVlN5mCDkAjGvxAKiQNEKY1mBCB/4XACyO - uIZIgQ4SBM8plGViYYUJWaPFZ7dk06FCFfxgmhwU5ldQBUa4RsN5KxJUTSKUccIPQiQe1IUtn11hXY4K - dWDajQcFWZAFzLiGw2gVLIWjRA7EYBo1TcoYoGuJWPiXABVcGZkcD/wiyTBmInSGaRsalJl6BjkAimvb - YKTBNr2IkQUMHB7kTQuEEurJkRVJA4Np0cjpJSw6uDZBmzM2wYEYM2Q6QxAUwVJEoYU+wECg25VC2Qso - FDQnggKtwMVn/rXs4tQIWWiqqSJiCgQLEaCCas8SlMKkiWn3qCqjBhm49kOwATjQChK22oqBaBIR02uv - kcg6kTUvUFaKtgIRBdZPAST2GQGpSqRBD39EG+0j5CYkgBwvXFvoC3QgmhAbphHSlLhz/SSNDa65IVEF - SWxQgLuaFoBHrgVlY4m9oa5BagAWIGJangJJU1RTIrgmTLyq8uACw5rewGZIGnBjD8WEEkGNmVXUJtgk - YsU00xt9SVPKZ7M0k5AFC1iBcqYJgHPxRA408gDMLfgCAkIa0GAaGgOZhFIlfRHjmhA4VjDABUfPMEsN - EHeawiZQZzKOPwelwAllcAnkDyFttAFD/roB3LWYDD8WBAsLHoBxtBd7gJeTBtkUAvUk8VwGyziUfTNQ - BRY4YI0DuMnzmSZ16qBA2VM0szRJ0uQTA9RDrHx5Hm4VcXoFmeQlDG8WnIBL2Vt0cLpLKKySCdSDTD2Q - AOIMIs7vAXwwjiRqfHA5FsE4cfQXQIQgGyw7AAH1A94wLx5BH1DwxdFOGLMLs0BpQIUhrIsv0QellK3E - NvIHJQ0bT1Ns+Ut0OJoCcJA2yFRjFPW6Vt1cQgSGgQEPfEPShXZAg2v9zyUBjJYUssG+8OzpU4TSR/4S - 8gElaGoRZhhheCrQjXm4QwA5qYAa+OAMFUowJx28oQ4vAosKaOCH/kAMohCHSMQyqYUhDkmiEpfIxCVy - biCwQAECYvCAKlrxiljMYhZjgADpCWUak4iAAcZIxjKa8YxnJMMkrFMBBGjxjXDUIh2OMgk02vGOaLTB - D6kYxz7CMQY5rEgFxIjHQt4xAhaoAB/9yMgrxkAo0iCkISdZxgg4RgKNzGQVJSCUCvSBkqAcIwDSUgEJ - LFKTb4yBBHJxlHX0gQmhLGQEAHCNn1TJAbjMpS53yctcWoBkQdFA5npJzGL6Epg7TKYylxmZJTAgFjDM - iS7SoQtmEgQWxyhGHrZJCRsexB2oCKc7jLdMENhhm+jMQzduootwuhMVsZhGMvvBgECkE52o/rhJOt7p - Tlccw5tAYaE+7pnOWLCTn+9Mhi4CCRRYtOMABE1nHaLpEgGAE6HudAc9AAQCckQUnT5AA0Vv0o5zYNSd - S+iHcD4AB3t+tAjj0FcFYiEOaFZEAMqIhTIK8gFsnDScrlAGQAW5BEF8dJuDYEdXKmAHQTi1HCNFiADO - IYGqniOq9LjoSRXKUIuwYxBHzUMktkGybjj1rOmAogakoYGutKOqcE2rQXSRjJ+iQqNBWQcpinDUQERD - ewaZRiTO6lSswSQZdahDMpoSC7hWlRQqNUgFlOEKu2LDiy6pABp8EFY5pOBKxCCsU48xkGQc4LQHSMZA - 3uHYqq4TIR+I/oVdz9EOgMICG5EIKy+GQSpdiFYQdXhMHVB7gDocDxWtlQA5D6IOrWI0Gcu9CAgaEFZB - kEBMsGiqaAszEOKe9jEgSO45lqYLk/40nhepQD37yoAIIgQbv1VDbLx7gK6gIbntmEgFjlHZk/qzIrBY - Q1gRsL6JfOAAoo1E4HRFX3JNI7nm+N00ZPvTd1CkAtqMaDGGgUyDoOG3hoVigwuyhORiwyIgQMNJ3XFh - XxDUB/EoYADoMVjCHgCwIvZuvCpgjtaSYqMWeYd538liiqAhnYHwhr4oIo/fcklwIy7IW1uLhhxWwKfv - tDBFBAAHfQTCDgW+SDt+SweSwSLKBXFF/nKjS5EJu+IcO4VMBerwW+5C2bvrCW9rXTFUyBRVtMTA0Znx - jBB34NeaAeiHLxJcjaTQ9z/9IIWPMavMc/x2QgcZNHEthI3kLoGZIPgtJSykadRaSAA9bu2SbziP35JW - PI9WCGup3FW1DOO35OjwhWKtEKq2FlwSrACCRQvsTPM6IfRILir6nBOzilYclCr1aSHWjeS+GknTKIZo - i+FeYxN6fpJ2LCko3SFX/BY1E5H2AdJ2jOS+dkWhFm0d0qbutAkAua0Fcock8Nv7dOrYEtFFclXboQr8 - lhTMU7euC5KM5K5IA9o+q4LrguaJJFvcK4LFh88a4n/r+CIlhuuJQB/ejcS+G8AVp0g6XPFfCXZV4VKp - tQ7VzWxEO9q7Mrf5RIaLWuPq/CimRS3Bfx4UaCBWsTUn+oykYQG25vwlAQEAIfkEAAUAAAAsAAAAAGQA - ZACH9nzk/v7+/vz+8t7w/kTi/iTe/gTa/pTu/Jzs/Eri/Bzc8szs/Jru+Pj4/mjm/jTg/gba/qTw/I7q - +oTo+vr6+lLi+j7e+qTu+Ijm+vj6+vj4+Gzi+GLi+LTu/Pb79ojm9sLu8vLy9pLo/hTc+fP49vL19PL0 - 9OLy9NTw9Mbu9Lbq9Kzq9KLo/Mj08ujw8uLw9erz9Oby9Njw9M7u/lTm/jLg/HLo/ELg/nTq/jrh/hLa - /Jbs+pLs+lji+Ibo+tn1+Jjq+HDk9rDs/hnc9Lzs/JTs/JLs/JDs/I7s/Izs/mTo+pLq+orq+JLq9p7q - /Fzk+obo+JDo+Ijo9try/iLc/mrm/kbi/FLi+OD09OTy/FDi/Ezi+lTi/ibe/DLc+kjg+kTg/CTc/CDc - /B7c+Mvy/hDa/gza/gra/gja+rfw9Nbw9tLy9s7w+L7w/kLi/LXx+Lzw+Lru+Lbu+rDw/Krw+qju/KXv - +qbu/KDu/qLw/qDw/pnv/J7u/Jzu/n3q/mzo/nbo/IPq/Gnm/Fjk/E7i+mLk+H3m/oTs+nvn/Dze/Cjc - /Hjo+pjs+pTq+pDq/ovs/pLu/HTo+Jrs9rLs9MTs+JTq9qbq+prq/GTm+pzs+Jzq/lvm/GDk/lTk+p7s - +KLq+qDs+KLs+KTq/qrx/C7c+Kzs/rT0/FTi/lLk/lDk/kzk9r7s/Eji/rjz/Ebi/Ebg/Pz8/Dzg/vr+ - /sn2/D7g/DTe/jDe/Frk/tX4/Nr3/izg/ize/ire/ije+mTk/uL6+mjk8uzy/Gzm+r3x+mrk/Gzo+nDm - /G7m/Of4/HTm+snz9N7w+Ov2/vr8+nLk+nLm/MPz+pbs+eT1/iDc+NTz9N7y/Pr7/Pj8+vb69vX29PT0 - /NT29e70+t/29uXy+OL2+NDy+rrx9tTy+Mbw/L3y+Lzu+rPw/K7w+qru/Kjw/KLu/p7w/rTy/sL0/vz8 - /s/2/t34/OD4/uT68vDy+sPy/O36+tD0+ez4/MX0+eb2+Nr0+q7u/KTu+rDu/Mv1AAAACP4AAwgcSLCg - wYMIEwqkkE1bCG0NrCmcSLGixYsYBZKQkCrVEhISM4ocSVLkEQIoCRQJWbKly5ewVKUkgIrly5s4LTaY - ScAKhZxAgyLMxtOn0KMKYTWgYLNiiaINRML6iTSjNXOAFplrOvHpTCtRL1qzs+nJnbBVK9KhwZYGHYxe - U4K9CGvHg7sPLqFNm1CAkrY0NuW7GBflXItTcuB9cJhv302AaSSBZbFwz70KGxhb/CAHZscGH0WmYc+i - CagWQXB+EIky6IRYRuPIUPH0188HTZzinKPb66SZRqepjXoiLFGrj7j+jZDZX8BKSFC0LRd3QRhuOFu5 - xzypnNF8lv4jpG7Y+sAGUFbP6T4xm43RvhWSvzwRxeonXNkXBDc6UP6B8zV2UDaCrEaGfhM1wMRo/shX - HEJwrLbIfwgOdAJkgP1B23gPGlSCFrxJU+FE1lww2noc3oaQNZqsxsiIFJWASWSbcJdbhwSdkN1iCUgH - 40RtjLaDeADiKFADE6w2HGjWMEVkRQ0sMtoPN6poEBurYUIVRrAIAMuTCVkzBw4OHCBiRtSM5gdXlgko - UDacrEZNRhSIg0kXD/AA5kHhKOGnEg7Y4aNFFPAwGj0eGjnJahPseRAsMBjSRQGUFgBKRbAc8uefNpBD - oUHeYNiWA9gU1CZm3CTAmRvIEObEA/6VVnqFeQRpuumfh2zjKEGwoDPaWwSdShAFjax2KZSrJBBrrFzQ - OhA5t966Q6sxVkEjtQK1uWUA1Si22BWlTkSBDMAsu2wo2yr0hgPR/unAOYMmNM5oyg1E1FcsNZDMam0Y - B4MUvJhb6S6NpDuRNDu0+ycO+OzagB9TDpRBUSyNs5owBhOUjSU5CFzpMVjsihAF1PihsJ+H5OLoFKMB - ElJMM6XimjW38EYlQg2kcIXHlG4xzqcUNTCMDScrgYCNBlHAyGgtDHRSSkW4Fs5qTIBpzTJB8FzAA3U4 - exEzd7Cr8B9vhFsQM6KyBWwA2BjREQ+D7sEZAUgPBAs3UejCc/4vEzATlDVYSFA0DsoQCYs5keEzkDUN - ZOM4Wq1wVodB2QjhhtaY6CNySQ2QsUjRScRTkDUQs+UfRc0UeJeGBDUwQw9aW9EG0Ddlk8YfRdtRD0EC - tBNBO7QLdJURb7AESxaITOpxDZmY7RgszOBR9B/hBJ8UQRlIUgPPXSDCzOZCUaBPEkU/Yj1F1wyi9RPU - gF9VA8oAcrLiN43CMy0dZKxfCXNU0e4oODmEwHTRiHj9KACwyAcDokW/l9hvWc+QhvvYI75A/AkSAsBJ - BjYhKzKcr0LWeIcp3pHBnFzjDTyo3gF/NMEVulAq1oihDGdIwxraMIYtHAlDQsDDHvrwh/5A9GE20AIL - EtDBDzhIohKXyMQmNtEP57gGUjwACCqM4IpYzKIWt7jFaQCiVNaggxPHSEYnngMpgOCiGtfIxUgwBYll - jCMZ/ZDDiljDimzM4xqpEBE4yvGPS/TDURqARz0aMot8hMU5AMnIJJriKNZYxCEnecVkRKUZ5/BjI8fo - B1OUUCgkqCIl80iFZHBjS1NpgCpXycpWupKV+gMKBV5Jy1q6MpYvzKUud5kQWOCiHboCSjOOOAevHbAb - DDiEMiPwSZdggwAGiGYtiGBMBNXjHMrM5iFwgRM8RPObBuiBDKr5Gw+Q4xHazGY7cJIMcH7TDIZwQR2P - AottQCKd2v7cRjfdCU4qsMAEMJIHHvCpzQjkhASs4Cc4LZACcgLFA28gaDYf0YJmvgQbSxiBQr/JgQHg - 8m/4QKdED5GGeDXjl7iwaF9+gQt58CofxIDARg2gAwwEY55c2sYBRnoIO+RDPIo8gFDPodKDzMIUSJ3F - 6NgAhpkaQBEryEZVkBEBnh7gBwZ7h1C3Cg+7Ncka4pEHUsfa1YI0oBRhcOoXFuDQipCgFTx9BD5w44E9 - bFWoShXeLEYxill8EhdjRWorPHAQEvigDDNFwwZO8MEwtUCkEn1D3QpCjrsKtawBmEUENhuBvAYAGYFF - qj4fhYVCOHUIIpiHS3KxB57iQRoUQv6GZQ8wiuWMgrMRAOBA2hFaU+xuZONIhFNJoYK2CqQeo+ApJOxB - q6BaFlsBwO1mCVKP3rbAYZ8Qg1MroIbzwYIccSWHAQ+Si9m2QjzSjYBNRBha6DbHEGaYqRkahSl88PQc - 99jcNfJg2T1MNr028UArQgs8isDiBz1wahHs2FqC9qEb1vPHbJvGq/SmKxe9zQWh2uCFjcaCdrBYBz6X - +1Hq2vWuediQ3SxckGaQI7StcF6CgDAEfiaixAFoQTrFm5FWzPZmFZauwcQa2ndkhBnOOAM4gXARfEDi - EaNARg5la9lzGAwWLDYIPnr7W7GsoQJmUAAGjDsSAYxitu4VCP6WhXyQ6oYWH40NwCyH+BpczJYcYFoz - bvXH3sCKbiQ4FYkH1tHf8ao5ywa5xoAD2wop8jIA+JhtaRCiZ87GEh4ZfnQ9TrzVCKjYIJXebCxhwVtG - E3aXPrZsfCiN6IOANrT+CHRV4jFbdnwq1BH46FHbm0ssz3ayoG71QTzQ23bIWig6tSw0RIbrEgM2tH8+ - 4KAtuw5DF6TZ6Fv0WBu9wnbMdrTGETZC4tFbbv6oHrMdRfCwTZHecflH7JjtNyzCboq4ObCeRRAszOu+ - elNk19uGkTUIvVX/0kXcCSE2o2EECwlvtUEHZ/NFMEzWH1ljG3wFN70RrhB4tKMd0WYhoCs5bpxHYwTA - JudLeo+d8onclrO6bTlSNMvZfMv8b3vta5xvbpEmLWXnQQkIACH5BAAFAAAALAAAAABkAGQAh/aM5v7+ - /v78/vLe8P5M5P4e3P4M2v6c8Pyk7vwk3PSw6vy48vyi8Pb09v5s6P4+4P4O2v6s8vx66Pz6/Pr4+vp6 - 5vpY4vpE4Pqu8PqY6vz6+vj4+Phy5Pho4viY6vz4/Pz4+vj2+Pj0+Pj09vaW6PbE8Pam6Pzc9/rr9/b2 - 9vTW8PLq8vTG7vS47Pjk9fTy9PTY8PLk8P5c5v404Pxa5P587P484v4c3PyK7PqG6vpw5viC5vqh7fig - 7PTp8/TQ7vTI7vS+7v4a3PyE6vqc7PqW7P5y6fx86Pic6via6vaq6vp+6Pp66P5O5Pq88Pp85vpm5PxK - 4vpY5Pbd8vw83vjS8v4s4PpO4P4u3v4q3v4o3vww3vwm3P4g3P4U3P4S3P4Q3PzN9P4Y2v4W2v4U2v4Q - 2vbU8PbQ8vq48PzE9PzB8v5D4vy88v5K5Py08Pq28Pqy8Pys8P6q8vyo8P6k8Pym8P6e8PqT6vp25viO - 6PqM6PqA5vpu5vpe5P6H7P6A6vqM6vqC6PyS7PyI7Px+6vyA6v6M7vxr5vxY4vxC4Pw23vws3v6T7v6a - 7v5j5/5a5vyU7PyW7Pqk7Pim7PTO7vqe7PqY7Pii6vyY7Pya7Pxh5vya7vyc7vxf5Pyg7vqq7vxc5P5Y - 5vqk7vqo7v5W5Pio7P5T5PxS4/i47viw7vqs7v6y8vqu7vxO4v689Pa07PbC7vi+7vw63v7A9Pz8/P7c - +P464P4w4P444P424PxG4vxM4PrS9Pp45vxY5P76/v76/Pzx+vTa8P7I9vTe8PyQ7PjA8Prd9vLy8vyN - 7PrF8vzn+fby9P5+6vja9P7s+v586vx05/7n+v7Q9vr6+vzi+Pr2+vfs9vT09PTs9Pq/8fTk8vjW8/zV - 9vbW8PzJ9PzA9Py+8vu18vq08Pyu8Pyq8P6o8v6g8P669P7D9v78/P7g+frX9fzz+/7M9vjG8Prj9vrM - 8/zs+vfx9vjf9P7q+v7U+Pq/8vyv8vjK8vr0+Pbt9P566vzQ9f5K4gAAAAj+AAMIHEiwoMGDCBMKpLah - wYsGG2gpnEixosWLGAVag0QqVJEGEjOKHElSJCQCKAlYmlCypcuXAieESkngEUuYOHNWpECTQBNqOoMK - LRii58+hSBHSokDt5sUGRimIpAU0KcYJCwj9WeC0IlSaTaRenDDHkaNPG6xaJCejrQwMGL+mDHuRViYb - eG3wqKo2oQAHbmU4WvY06kV6a/LaaJK2r19HgWUICklRLkq6FTdIUGxjjVjHCItFltHN4gvDFUtwtiGB - MmiDLiAHhtY14WmwnxU2kMF5zbHXCWkhGM2m4u25uZWWWg3JNfCC1wAHdqCP4vHLyQ/6IMC5SfXnSp3+ - jEbg3OB1n9kLUgO0Gg543RIiO4I38TzmhN4ecHZU+33BKqPh0B9B9qU30AY6rBaPfwpRIFpkYShUoEKx - rEbIgAwO5IImkRlhYAATIsRMKL25kKFCZI3mhm2oGTQBD6sRceJE80jnlgPyIBSiQdvowpkp382YkDGj - cVIeiC0SREEOqzkB2lITHDnRBn+M9pt5SQ5UhX6KHYKhQrQI8OVBE4jDjxGb0JcRN6MN0Z9l6BkUwiGc - PcBLRtRw48AtNhQxJkHhOCCoA0bEEQxG1BQxmjIGwXnfQK+sloOUB9Hiww63WKGpFZJURAsOgw7Kjxp/ - EuSDbG4ZYU1Bjia3jyn+nLWBwlOX2LDppjR8SJAhoYbqBzuUEkQLBqORw2qS1GSwWqeZwXLKrbfS0NhE - s/Ta6wGzVmaEfNkK5ChfAUyRmGI0rDoRNcLwAS20k4Cr0AJGWDuoEW6Yq9A7o0VCWVFgOUXNE6tpM5Gl - esyw7qYzZKArbJzIO2gN34xJgR+jsTMQT2BRls9qOrjLqhJrHLxpNGriyY0fDguazAmUOjPahQIJYApN - j4Q0gSO9OZPQBkAgIrKmpORTqkIhqMFPyg4w0G1BE1QyWoQCMUITJiGFs1oxR05ADB4/W/HAJwtfNE8c - 8TpsxALpRReZsQJ9EElHmNh7AGcELD3QPncYLPL+LTjY/dIELkSC9B9h1EbLApF9M9BSDW3wmSucwUXU - K210fYgzwbZEQRVDIC1INUxT3BYOAlA0gRF5eUjQBj9o0nUTxgztUghOlC2vEXMcOpAA6ciRjuxYRcLV - 4tsskanItvAQwmu0XIMA0vyEI3twSlZiy89YBOK3Y9TQU4zn00/0ges/a8JN5mpRkE8zKSsOEzk/64JG - 2KCJII7toa6CEw4H55KBCEISlgs8YS33vQQf6+pFyQJIEGo4A1SCYkTpYPIBR+AqHuHzzwSmsYBpTBAn - WCmCNjLIwBKa8IQFocUEVsjCFrrwhTBcIfpcMoEUvOCGOMyhDneYwxTwhRb+1nCDH2pAxCIa8YhIRKIf - VkFCi3xAAlkogBSnSMUqWtGKWpBAdSbghiR68YtJ1N9QJHDFMprxihJY4RDByMYv+mGGGZlAFM9IRzNm - gQITWGMb92hEPwyFGnOsoyCpmIWIdJGPiKyBGIMygSMM8pFSrIBUuKjHRHpxiR8MigigCEk6ZqECzHAK - VTZAylKa8pSoLCVT+jIBCqTylbA0JR5RSMta2tJFtUhDN5qYkAnEYQhuoN+MqsEAQxhTDplsiTWiYIBm - UiEI0zphMFZhzGoawh44QUAzt2mATsBAmK+hQBoYYc1qpgMnveDmNsewgxXAUS206EYjymlNbMJEEur+ - 5GYWTNCAEy2jDvS0ZgRyYo0m5JObF2BBNF/TjgUEtJqMCEMyZ5eBAhy0mRDowAA8lpQJfIOcDzUEG4IU - AAHUYhi1mChCBCCNWkhDgDoAw0UNIAQAZOOdJKHFCQ4QUkNEAAWu4eIBhroAi0zDFUidBtOqsIuZGmAL - CkhBUpYRgZ7agR39scdQt7qOxU2gKa6RBlLH+tKCUCAVWHDqFX6w0Je0gw09ZcQ30vMBOmx1qEqNyTRW - sQoPDqQWY0VqOj5wEBHoQQwz/QIHYsBLpoUBpA9dwPYEkoa7DrWrAplGBDYbgbwGoB6BRWotlAIPKEBg - pgUgwQtccoJz9HQO8Pj+kjzsYNlFBmAVnI2AbYcRWlfo7iDUyEcinKqIFrS1IvLAR08b0Q2OLm4Vlj0A - YQaS280S5Bm9nUawKDAJLTjVAiqY3gTGGVJGpGF5E9mpZWfhmupGwDX26O10FSKCPXhhpl7IwdBo8Y2e - ugGoppODZc9B0gC4tysfmEVoh1EqWhyjE07FREUmQIeHMiC2Ro0u1BZ34IIANrSYpQg1YiGLi66hwRUu - ZyP6Ac5gnMOyckgOLTpMEN6FdhaEtQgFiNCFfCbCuQUJgzUZAY4CU2QW0T2BQWZc3f6INbSlwcg18PAF - bsrIIsM4ACNWAWCMSCO64ugPk3M7IHf09rcWmYD+GWgwhgTkAZwtEQB072qH7Y2ZsxwNRm/dgdOFbCAF - cG6Jeu+ahiPdebPOjW9o55uRPpfkA+awLB2MLJBDR8C5H0hHaH9nS3dEtx/BcS+Q19Hb0dLSxZaNwIcs - DWQB8Daws2gHLV0RXdCFurpA/mx2UbiM6A7v1rnNdQCOGtpnmHACEbCsHXIEJlFPpB29HYZKGdSN6A4j - c6ymyIcDa2sh1VXS9gI2nk2n6cByWkhZtmyUB+ZsilSj1EKarWXxsd92T8TVvZX1idAR3QU2G9cWwW5o - 7cmgCdD2rmyAo6Wnp+ixzuJEFL7rOdDM7iZfJMHmPhEtpnFXz3qKxhYh9Vg+Q1zwbvCV4BZZeEaq4Q53 - dPuW4t5sY2FOEZDTPCjudfTNK4Jbztp25znRLGc9DnQQ7rWvMy86majB9KTDJCAAIfkEAAUAAAAsAAAA - AGQAZACH9obm/v7+/vz+8uDw/kbk/hbc/gba/pbw/Jbu/Bra8srs/KDw+Pj4/mbo/ibe/gja/rb0/Kru - /HLo+vr6+mTk+jze+q7w+pLq+vj6+Hzk+Gzk+GLi+Fjg+MDw9pro/Pf79szw8vLy9pbo/M/1+fb49/P2 - 9vL09O709OTy9Nrw9NLw9Kro/hTa+uj39PL08ury8tbu+Nz09vD29PD09Ory9ODw8uzy/lbm/hjc/Kju - /Kbu/KTu/KLu/KDu/J7u/Jzu/Jru/E7i/nbq/i3e/hDa/Ijs+oDo+lbi+prs+Iro+G7k+Jrq9uXz9MTu - 9Kjq8tzu+pDs+KDs9Lrs/m3o/IDq/Hbo+prq+JTq+nTo+Ijo+JLo+nDm+Ibm9Oby/lTk/kjk+mzk+s/y - 9tjy/Dze+lLi+kbg/DDe/Cje/CLc9Nzw/g7a/gza/gra+NHy/jbg9tLy9tLw/Lzy+rzw+Mjw/j3h+MLw - /kzi/LXw+rrw+rbw/qby+rLw/LLx/K/w/Kvw/qbw/Kbw/p7w/n7q/nLq+ojp+mDk+HLk+nzm+nbm+lTi - +krg+pzs/ILq/Hjo/obs/Hrq/H7o/IDo+nro/Ibq/o/t/Ijq/pzu/Gbl/ETh/Dbe/Cre+LLu9sLu9Mju - 9LLq+Kzs+Kbs9Lzs+Jbq9qDo/l7m/lDk/Jzs+p7s+qDs/Fvk+lzk+qTu+qbs/Fbk+qbu+qju/FLj+q7u - /k7k/kzk/krk+Lju/rrz/Cze+Lru/vz8/EHf/vr+/vr8/sX1/D7g9sTu/t/5/DPe9NDu+mTi+JDo/Nz3 - /Eri/Jbs/iTe/Ezg/iLc+K3u/h7c/I/s+J7q+Hbk/Of4/hze/hzc/vj8/hre/hrc/Izs/vb8+pTs/tf4 - +t/2+Or2+nzo+Kjs+n7o/kri/pru/PD6/jTg/Mf0+sby/kji/kbi/q/y/pju/tL29q7s/Pv8/Pj8/NX2 - +vb69/P39fP1+vH4+OH09Oz09ur0+tf09uLy+Nbz/MDy+r7w+Mry+MTw/Lny+rry+rjwAAAACP4AAwgc - SLCgwYMIEwqcwACeC3gM1imcSLGixYsYBboDQorUoncSM4ocSVIkkBsob/QIWbKly5frSKW80YDly5s4 - LWKYiXJCzp9AEZLgecNn0KMKJ0ywWbEEUaMY1zFFWnFCHEeO4kxV6JQn1Irr+kyZYoEB1Yt8GqhtcAdj - 15lfJ67rQaAuAR1xzx4UMGhtgyktLr5NmTehvFl2Cdwwq1ehgCl+GyDYenBwT4sMqCQmIItx44ToIjeo - ZxHeU4tzNhNgRPmzQG2iGRU2aNprRXiXNs/S5lrhOlei8d0+LXeZaiCteweI19fvoHgUa8OlSM/L5hvQ - lSvMJzpCdOIJJ/5cUJ1H+0QSjCIDniid8EQxXzZPmW1+4D3RlJK3v5yQQRXVYdQ30QQIiDaCQvsVpVAH - qk2SnIABMAGZX4JgkFCC9JVAymZ2BAahbxaIxs+F4BW0DiuqofIhRSUIEdkg4SCEIUJMlLIZKSSsSNE+ - ou0gY4kDMVCJanK4to5SDx7EQBGi8UYbkAK9EV9iEtCXkFRJErQOP1Q8soCHGN0XmTVTWaZgQSRIsNkX - pGE0QQwS0EHAD1kGMI4QeArxCB8xXjSBD6KNY5CZedWiGpkXrUMPIXS44agb3lG0zgF55skIOXUGsM2E - awnhTkGEFiRDKpuVAmZ0oBDw6KOkWDkQpf6V5klJMVmuk4dofIBa4jqnqBYpRQz8ksqqq17imUK9xBrr - Dqcm9I4g6p0a6kD2yLJZA58OmEYVxBK7jKsDxSGIsnkKYku2Cukjmg8sDcUTSxMwoho5cs1zQaPdOkrH - KeAS1MIO5ObpyAjJMWCNaMUMtNO7A+mjWiPJvaMOLfk+KkmzFq1TDyUB43mANq3FIJojRgkgU0o1LTTF - ZrTE0B8IhVTsKCn6ZHoQCeQw0rEQOfRp0Do7GDhQIDMtEBI+qh2z1To1cCOzG19YYOFN8fDxSMeCxPHB - Qds0t1ZbAn3wQ0c+oLvAddkVdAIS+OZLBxRp47SOPD7sXATBBsUR2f6BAq3DAAMlMAAV0ontYRAJtQTx - tAQx2OxmGxx3DAQ0JlKyVn4UCSCEXY98xYAKlzzdSh2Oj0QCPuN23IfPAazTyznj1PlBPz/EAdU6TBDy - 9F05GrmNHztTEbtLNn2wijlPT4LxZ+tog8DO4JSO0C4NPH1JPdLnNEEYjnTM90t8yFyKHP1+RgIeqccK - AU6UuL1I7zoOtM42gCj7vUvhEwvJ8vG3HkPkQrBE9gzygSk8qhBhGGBv1tEOW6RDAD9ZRxx+gI/y9e+C - GMwgWLDEwQ568IMcbIzfXBCCEprwhChMYQldIDiCYOAOlMCKDGdIwxrakBL8YAdSpkEFcTjgh/5ADKIQ - hzhEM1DhU+u4gw2XyEQb2gIpVCCiFKdIRCpIJYZNzCITKXGUdfiQimCcojgigkUtmnGGXAzKBL4YxjYG - cYwBsMUZ54iVJwZlHYxwox5/aASz7MIWZaTjEilhCwgexR1GYOMepSgOI5SAJUf6myQnSclKUlKBGbOk - JjdZSUxq8JOgFJAAijGOYhgSJ7s4RxHyMLVQCgQafjiALPngybDBogC4xAQnjpXBcNhClsA8QDZwkgNc - GrMAFEiBBV3DjnGAI5jA7AVOIHFMYzIjCy+oJUyKsQBoBhMYxKzmMc3gBHisCBrn8GYw14cTd7RCnMcM - Qid46ZoPxEGdwP4MxAN/ggEkOACeuMSBEgawTOKNIBD4lCU+0NW6YowAGKeciDt4IIQ/8EJ+26gCNQBa - AGRo4QTavBIw9JDQA/ChBTYRgC30wFI7TgQD5jCATGnRyta1gQwcLYAbPFECqkCDDyXVA60Mkg2WGhWc - 8sMSQVgh06ZegSkT2IQbcnoEFdDTJR/oBToSGogR1HQg1ziHUVk6zL410BbZMOQ6jNBUmeIABQd5xwWU - wdFoPIMJtVxHOhCa0DjErSDjGCtLKSeQbEDgsBAoawBi0VaZauCq62gBGHDAUQd4wAUuGWlJ+wCN1oRD - sHpwaRwRCwGXkiATjWWDAsKjD2Pk1BehuP4qRcIBgaAWw1UrFeypSHtYgnSgsQYogznD0w0z5LQQYsjU - OpzJ1XEwFCEjFaw0CcJbCMBLFcBdwYPiQQhmcJQZiKrICEpqi78ihBd8EKwf/lpdm8SACI09gw0kFQMK - 5PQHYImlOv2AUou0A7TtMEh7tcTWxgKgXxOogy4AaockrSOd0FxAOyx4DdDy4asBGDBBZICGxrLgCRfB - QBQ0IU5j9CsdwQSHczPSC9AmTMC8nQoogLsB2SJkG4eIxjGjcJERLCAQtmCdRaABWltsRcMEYYAuGvuA - JmRkHfcoBDOGcIGCkkSloBXyQJBMEH08oLEVwGxGGNLCzxQDtIJCCP6X5UcB4I5CeiGdyAfEOtZzPJe6 - MUaIPArQWDTQwJUjAK1iD7Jm+SUBuBmw8Yo+K1gIWKnQA3mHJhpLBBiAssWCJWxCID2QTQCXAz3NIJEF - i48HcVogDFAEcKWQQQFAALTmhTFpH9SGNTQ2E2Lu35kFe79N59k3WwCuCOLckjkL1s4VOfVAWoCDxiaA - Cf0LtGBfTBFlD0QUwDWElYPC6LFa1yLWFggJgtHYNcBBR5geq6ar/WuK4AK4rSB2RgQA2l5kKtwLOQKl - 5R0VOhtVywrBt0DuoYa2MoPfGPmvUQed7HZLqsAyJQTCE1UMW9gCqRgROKq1MIYxiELRrtyywyor8rdH - hrzhsz45VaqrcqrYgrSibflP2kHaAMv8jmdtx8RVLpWl7NwiAQEAIfkEAAUAAAAsAAAAAGQAZACH9oDk - /v7+/vz+7u7u/kDi/iDe/gDY/pDu/Jjs/Hjo/CTc9Kzq/Jju9vb2/mDm/jLe/gza/qbx/JTs/GLk+vr6 - +mrk+kTg+qDu+obo+Pj4+Hjm+Gjk+Gbi+Kzu+Izo/Pj8/NH2+Pb49qTo9pro9PL09Mbu8PDw9Lzs+en3 - 9t7y9O3y8ury8uDw8tzw8szu/hDa/lDk/ize/JLs/Ejg/mfn/jDg/g7a/HDo+nro+lrk+orq+ITo+HDk - +JTq9qzq9L7s/hXb/I7s/Izs/iLc/Izq/Ibq/Hzq+obq+oro9p7q/H7o/Hzo/Gjm+I7o9OXy/Gbm/GTm - +mzm+dHz+Hzm/k7k/kLi+lzi9Njw/Djg/DLe+k7g/iLe/Cre/Crc+Mnw9Mru/L3y+rrx/jng98Du/j7g - /Kfw+LTu+qru+LLu+LDu+qju+qbu/KDu+qTu/pXu/J7u/Jzu/nDq+o7q/Grm/Ijq/ITq/ILo/Gzo/G7m - /G7o/nbp/oDs+oPo+mbk+Ibo+nTm+l7i/IDq/IDo+nzo/ojs/pDs+KLs+Jbo9rbs+J7q+Jjq+JTo+nLm - +pDs+pbq+prs+mTk+p7s/FPj/EDg/Dze/DDe/lbl/kzk+qDs+qLs/rTy+Kjs+qTs+Krs/FHj+LLs/E7i - /kri/Pz8/kji/ub6/kbi/kTk/kTi/D7g/Drg/DTg/r70/ire/PH5/ije/ibe/sD0/iTe/sL0/sT2+mjk - /ETg/sb0/sb2/sj2/Ebg/sz2/Nr49PT0+N70/tT29ur0/Hbo/iDc+Jrq+sHy/LLx/vr8/Mn0/rDz/Pr7 - +vb5/Nb2+fL59ub08/Dz9Ojy+df09Nzw+Mvy9NLu/ML0+r3y+MLw/Kzw+Lbu+q3u/KLu/qDw/rn0/vz8 - /PX8/N749vL2+eL2/tb49u31+sfy/Ljy/Mz1+Lru+qzw/KTu/nDo/HLo/hzc9tHw/N7399Ty/OX4/t74 - 9OLy+MTw/K7w+rLw/LDw+rTw+rbw/q7y+PD3+Nry/jzg/pzu/Fvk/FbkAAAACP4AAwgcSLCgwYMIEwpE - lqEBrwYZRCmcSLGixYsYBSZjQ4PGhRASM4ocSVKkNgcoHaBDVrKly5cCRdFI6eAOS5g4c1akQBPlTZ1A - gw4M0dPBT6FIDVJAFvJig6IURIo6mrSiKFhBDgxrWvFpz6gXRRFTp4dehqoWycVZG4ccRq80wVptA6Mu - jDNy0SIUYIRtHD0onEK9CM6SXRgO8uo1KMDvWjZcFcJNqTghhSKHYViqvJjgG8dxdlmcjJLzwWiZYdCJ - 3JngO9CEqCIknbjrncyWwLVOKMoa6GldB08UhSY15N0J8/X1a2QZRdqmCf5ykNlBK+QKh4Ge91y4ZUep - w/5gV5iMEOh3E6FP1JdanezxBJ+BRsCaoPqEGYykBgFfIYXPjvGX0H0IyZOaEPX1NxAKejhGSHQEGvQN - DbgFpiBvxIAGxoDeFSTKGamtceFE+ezhmB7XHRQhQcwYdhgNyYw40TiglTFbhwNRIENqw3QmylIjZXAA - aLoZtKJA7qSWwHvDiZIgQqKAQcgeZViIUS+gucHakRkAk9ozGSGjTwJVUHHBkwUZs8eaa5IT40XIZANa - OUbiGIA5qUmApoe/yFEFAYASYI1F/LDJJiHGMHnQLw36tccHBa2YD3WHWWLlcx1QEWigNERHUKGGsulG - OxaJcg9obtnXITKGpIaNRf4ZeOHAppvO4elAaoZqaBkpThSCiX4BpmpPR7WYGYwUIZMCDrTSio2iBcFS - h65s1gHGmwpJAVo2TRFFbI46pDbOcOI4UkqzgZaSCbQGoVAGtWweAAKaFEgAGqkC8dRTU1KkpgS0DZgB - A7qBBlJkmL24Ae+a/Bx8EDigBRGSADOldMdAyKSDWy+WscMEwYBCIQW7E2VgzJQLz9NrQcicAZqAAZyU - EjoD2ZLaI/UhEw8fIBMAg1k4LUPOwnsQMg2kBinnWKoBfMARDdlgG0F1Kw9EQiKjgGyKBPkAJQoK2RB9 - gDKswRLgQD82lIFcsmRmj0EZmGNJzwn0smdJFDwjA/7RbKBHEDJusOWGABTxZVcgR1HADh49OzAOyS8l - Mw3K8BKzsgC6aKIL5AEUAwYbsPwkCjM6/EnwJWdgu1g+xBCNKOe8/a3GJSBXQcSlrSEDzht8wz7RB3n0 - fMMzd1dFgRQHLAyzS5qAbMkwvlcVgpTUbgiTG+iOcoHqMgaAgjW6Lt8SOc3WgXv3C4HDAJsREA7TBzcE - ysTI6PO2CyzhAIXM51vV7///AByJkwZIwAIa8IAD1AsyHMKLBjrwgRCMoAMbkJdkgMENB8igBjfIwQ52 - 0A2rKAZSPlCEfdTghChMoQpXuEIxFCFGUfKgDGfowVUgpQgszKEOWVgEpmCQhv5AnKEbhCIKE+7wiDrc - BwVE8cMgOnGDQwwKBYyIxCqmUIkBWMUTt5hBWBARh1YMYw0wEJVirKKJXJShG2DhvqAko4RiPOI+MPAN - 0SGDAnjMox73yEc9Rm8kd+yjIAe5xz8G8JCIHI8AvKELb7QRJsXQRBDIcavuveMY2sjkNh7ZkmRYogCg - vIQ8zhLAVsAik6jUBjxwcgZQurIAFYBGJZHzgXJEIJWo1AVO6vBKV7rCAyoonl5EsQt84DKVq4RJK3vp - SjH4oAEXIoUmjpnKbeQkGf1g5isl8QVSIqcbsqAmKiOgDE66JBmRqIE2XfkHFhiSJMgAwS3FqQ1jqG6R - IP5wpEWSgQ4jlAFpAfjaErawzgLEoAfNEGZJROENY9JzG63gigBkcYyKzqIiH7jECzYKA4AG1B3ZLCgB - EAFNpLRiG/TUBj7aIZtdVPSlpIhJA0hgAhJQcCBn2KhOFREZClyDDAUtgBWkMUuMdMMWKY0ACDjzAU28 - tKKiCWg++gABCFTAOQHlg043WgAnHCQEPWBFQWMxBWYoVCGiUMY8xSkLrB4EBE+taEwDgAwmGOCuBpjD - QNCw1Y3ywJsEEQU4/hDUGiSBBC65ZEo1gYIntSKux/DiQiCAVwO84CYUQEVfgeCChCBDCpIIai5+ANiL - tGIVKV0puygaVytRoLJ39f5mNfr6Ai2UFCEUwIYYgvoEfShUALZMaTm4d5BLxlWXOYKtAW5LgQnQdgF7 - yocOXFHQVwTBnAgBQUphUTWEIGMbcdXEyjKgXMQOpBdA6OsDVEARwVYgqGywyjSpqYl3CNOlcY3qQBpQ - 3sBigLYemCUy5DGDdcLgbqKYbyrJCbtuOPWp26AKf2Fr3oHkIwZ9XUcLLkKBNjyAmZKAnDJwac+M6AKy - frNPfwuyCdpuoLQTEYcdYvHKTFxEnhFYRXcpQgrIzmJLKyZIBmZA2xJkRBTPeIIrVNGDor4EFpDd8YQr - a4LT0NYCvBAJQ266GHhAVnz7VW6VDYKMCtBWBGdFW/5nPgDep2qCuAKZMl7HbBBwrKOvXFgBIn0BWf0a - ScxQagJtAeDkb0J2FYqS813pbJBlPGCzVwggLlAsGUAnxAy0BcRt0dfjuN4CTYo2AKOV4gnansB/AlhF - lNNj6YRIIb1bpUSFZeSNLz+n1d79A21H8M6gsDmu2/DobHCNEBQMoa8KcEb34BpXb3SF2Ah5BG01UGiT - Hrp4oR41QpKRis26Y0S2gOz5hg1bbSPEHLTtR5qBIgDI4sIpQZ4IBfqR4V7DRBRtrqgmugFvCl9EH7De - qCvsDRP8QvUt8R7Of3UqsQsxFBaycDbC/X2RDByiFrV4BIwTGamEU4QCDVm3/zbIC9ssc1woJK/spk+e - EwpQFq82qDbLd0KLykZB5DP3jwo2YAMbVKBrOdcJBXhhggHUdOO7CQgAIfkEAAUAAAAsAAAAAGQAZACH - +Gzk/v7+/vz+8PDw/krk/hrc/gra/prw/Kbu/Izs/Cze7u7u/MD0/KTw9vb2/mro/ire/hba/qry/KTu - /HLo/Pr8+Pj4+nDm+lTi+kzg+pDq/Pr6+Hbk+G7k+Lbw+JTq/Pj8/Pj6+Pb4+PT49sbw9p7q/N34+sfy - 9NTw9L7s9LDq9vD19PT09Nrw9PL09PD0/lrm/hzc/KDu/J7u/Jru/Jbu/JTu/Fjk/m/o/jDf/hbc/Irq - +oLo+mjm+Iro+pbs+H7m+Jzs9qjq9Mju/Jjs/JLs/I7s+pzq9+Hz/IDq/Hrp+pLq+Jrq9qLq/Hbo/HTo - +njm/hja+nLm/lrk/kzk/ELi+lri+lji/D7g/Djg/DLe/NP299by9tby/jri/Mz09tDy+Mby9s7w9srw - /Mb0+Mbw/ML0+7fx/j/g+Lrw/kbi+6/w/Krw/Kjw/qjw/qHw/Kbw/nrq+orq+m7k+JDp+Ibm+nro+mTk - +qbu/ITq/H7o+oXp/oDr/oru+nrm/Ibq/pHt/Gzm/Ezi/ETg/Drg/DTg/p7u+mzm+pvs9rru9rDq9M7u - +Kzs/mHm/lbk/GPl+LDu/F3k+qjs/lTk+qju+q7u/rHy/lLk/lDk/rr0/k7k+rLu+LTu/Efh+Lbu+L7u - /ELg9r7u/r/0/Pz89sDu/uL5+qXt+vD4/Izq/ibe/E7i+tz2/iLe/iLc/sb2/FDi/iDc/FLk/h7e/h7c - /FTk/O759N7w/vr8/sr2+qDs9N7y9OLy+tDy/sz2+KLs9Oby/s72/Ob5/jrg/jjg/kTi/pzu/tD2+vj6 - /OL4+sry9/D3+OH2/Nj3+Nj0/M/2+Mry/Mj0/MT0/Lzy+MDw+rLw+qzw+qrw/qbw/rj0/sP1/vz8/ur6 - +vL6+uT2/sj2/PT6+tf09Oj0/Or6/tD4/LLw/LTw+rbw/LDy/njq/jbg+J7q9ur0+rzx/ors/pru+uH2 - +On2+r7y+ub39Ory/tj4+sz0+M7y/LTy+sLy9O7y+8Py8vLy/MTy9O30/nTqAAAACP4AAwgcSLCgwYMI - EwqsYMGBQwujFEqcSLGixYsCQ8Dx5w+BiIgYQ4ocGfLag5MP2FQgybKly4U4UD7wt/KlzZsUj8k8WROn - z58DRex80BOoUYMbKoC06GDohpCjih6lWCFajRpkpEpsuvOpxQr34sQ5c2xqRWlixUq7yFWmV4qj2MCY - C2PNW7MIBeRJG4ePOKZOLXZrRBfGAwt4FQrgwzdOg6VbA1O0kKAwjEZ3Exts0DiOiYptUWZOaM8yDCOQ - NReU19mG1oOhT44+KMKJ5UbdVCccRa0zNIqxH8wuOMqD6QmpdRM8tZdvHm4Tgw8nuO6B5QfQlSc80fle - dMkJN/4gMh1Pu0ILRRrzCRa5q0QkppW8Nj+wWWcZyQlKP5/H9Bb6Cm3AWWP/JbRfQmGYVkR+AA4ED2N8 - GTFfAAfChsNt8jSo0ChndGaGgeARt4ZpbGgo0Qh9qJedQRUWBA9hheHwjYkSJdPZGgi1ONAGP5iGj2aj - JCXSMTV0hgxsIdZnWhIT7lZBkwZVoI8NfazxF0ardEaDVjoGYIEepq2CUQWrJEGFIwhAOdAXfbTZpjQz - fsVGZwXql2QA05hGA4MHjbLOD1QQICgBOFL0hptu2uCMmg5CmFYfIBSkozLWFdZILUxB4sigg1IwHUGH - IurmG0fCxU5na9np3kAVUGIaNf4VWTDGA5xySgFiE/UiqqjnYDqRCCnyxYevAgm1U1FIwEgXBSFMVAES - PNRa6yaMBkCGEbu6aYQZkUrES2dsLGXBUD1toIFpyUg0ygpHYCLtoJikedEp52TrZg1b8BnAMTR09tlC - Qy3Fi2l/NOmAJzC8O+gfGYZEpiH2ttlAqQgt01kNNQkQE0r+sBqHae8kZAEYOCgs6AO8VIuQBV9QGXE5 - KxZUwRp0DuSGTBIMBI1p+B1UwS47mEwADGTZxI00EfcBSFYHKeOoWgOBgIA/FLBRlkASXHfKQSv4conJ - mtCwNU6jwCNB0gcwk1w0BA4UZEMWvOWKZWcYZMEnjQidxP47+rK0ATgHJN0GewRVUExaMwgwkV50FUyQ - BVw4IXQPyahMkgXQAJI0nAQJME4mi1ZUgRkI6NPTKOFoILQja1yt2SlnJA3IF5b3WfgamypMRRFjK1eB - PNck7UbtCVWAjtBOrNK3WRtsEbi9dbYkjcmN4EO8USLoo/muDNhEw7uX4CECjQWdQs6u0bOUibQJNEy+ - zO+E2ocEir9UQRyD4gDO9b6b4Ao9PhkdAk7Av/cZ8IAIdNsoFsjABjrwgRBcnksq4BAWWPCCGMygBi3o - kLuAwAxvOIAIR0jCEprQhG/IRgElAoIEqMELMIyhDGdIQxoSIwGRGoUZTsjDHp4wG/5GSUANh0jEGiZA - KSH0oRJ7+AagjOKFRYwiEdWwgVEkcYlYJGETf7IBKErxizJUA2KikcUyitAVThQiGNfoBTk8RQCuuKIZ - efgGV9TvJ8dwIRujqAY5KKMoFdiABQZJyEIa8pBxE5JZAonIRjqykIpMoCQnScnOlWILpbij/e5RBGm4 - jpLbyIQERikKTbIkBI2AgConQQJcJfAbZBilLCVQCpusQZW4hAAFdPEp81RgC7Oc5ThssoNc4jIHGuiH - BBNTCksEc5a1fMktjYnLKijCARrahiieOUsg2uQYj6BmLq0gBlfqBgS44KYsLfGvmxwjF14QJy7tsIsV - YkQAzP5wpjol8IVuCUQApaBHNHPChiSw4RZugwcPciBPCKSDCS9YJktKgY19SoABxPonLjLB0V5QBAST - KIBIb+DPAIyCC+FsKAESgU2j1IIBFsUGMpJTCo7adBsCGYUDWLAPFjjgLZUQqVCDkJpjpEENDYXAHVBg - zpeAoBcWtQQzXgMCUdiUo/8ahTLmEIEIUCA7o5CDUEUKgV8cZASIKERDc8CDcEhUIRWghz7ViYuYFWQL - V+UoTgNQAQoY4K8GoMBAPDBWkXKgqTmVBxSS6oUmuKAlwajoPkUhDj5xI6+ZwAWrIgBYA0ShJsfoRGFj - IIbiDSypmCAFYinCjWzEFBlQ2v5oXom1gc7+1ZVhKGwBMNBShBwDEmhIaiCQIFEBANOiWygpQoKB2ehZ - wLYG6G0FeqBbFfTtFBpgqDxzYANTJoQZFiWDXfOSjbyKIk4Cea5tWUCQZbCisFl4wURGsQwKJHUCcBEl - NzMRjGWaALPtFIgDoMtet/lAt3RgVAVO8Ap5wkCC+p0lO1VW1byqUFIELl8hCpsKW1jkGJKIpzFhwCh6 - BNMYyp3I5/JKOP1kuCCM0G0HVpuQU+xAu6rEg0XyaQlXZLQitcAsLpIz4PUa5Biq0O0QMDKKZgQiB1hg - wien4g3M/ljA0N3HQeyh2wwU+CIM+almaprX9A2kyJ3Vcv6ULqBbIbzVbZqpQHmvKopmwSbLCJFHKgqr - hXlQkh4ANhCe+/QB3dahlwD6BmZdMSE0A1bNZyVEYVnRAkmu+Kp7zdGgEULYwt6ht+8LZV6BoS9H/xXS - B9nADXSbggPCEbPjxbBtUX0QcMiisIP4Mo3IfFUAbmXTCKmAHXRbAnvepAJWpXOKWQRshMADAoVVwDrI - B+i8UkwhpjYArRGSC90CwdguuWxeGQ2cZiNEBFUorCy4YCJgYPZK0TE3Qj6h20e82ScCwKwxmPJiZz1i - 0uAmySiSbVP0xtvIFVkFLMaag4CT5L82DfDBO6trdR1YqEu4t09GUQpc4GKgoOl3TkeYIAhBqGPKlWQ2 - wi0iSAdo3IDqpXjKjRJzwIJ65jexgA46GwFE4zwkFphDZynw8p+Hpx8A6OoFRmB0n2yABQOIOgtorJqA - AAAh+QQABQAAACwAAAAAZABkAIf2guT+/v7+/P7u7u7+ROL+JN7+BNr+lO78kuz8RuL8GNryyOz8lu74 - +Pj+aOb+NOD+Btr+pPD8iOr6dub6+vr6TOD6Qt76ou74lur6+Pr4fOb4ZuL4sO74lOj89vr2jOby8vL2 - luj+FNz47/f27vX08PT07vT01vD00PD0sOr0puj08vTy0O78xvTw8PD06PLy5PDy2u7+VOb+MuD8cuj8 - QOD+dOr+OuD+Etr8kOz6kOr6XuT4gub4qOz4cOT4lOr0tOz+Gtz8juz4puz4nur+ZOj8jur8jOr6gOj5 - 1vT20vL2our+Itz8XOT6eOb+SuL8VOL8TuL8SuL8SOL6VOL6UuL6TuL+Jt78Nt703PDy4PD8Mt78Ktz8 - JNz+Dtr+DNr+Ctr+CNr02PD6uvD2xu/+QuL8rvD2v+74tO76svD6rO78qvD6qu78p+/6pu78nO7+ovD+ - oPD+mO/8mu78mO7+e+r+a+j+cur6auT4i+j6VuL8ger6luz6huj8ZOX6gOb8VuT8UOL+hOz8eOj+iuz6 - iOr+ku78dOj6dOb8ON78Lt76jOr6jur2rOz0uur4ouz6ZuT6mOr+Xeb+WOT6mOz6muz6nOz8YOX6nuz8 - Xub6oOz6ouz+qfH+VOT+tPT2tOz+TuT8RuD+TOT+tvP8/Pz++vz0wOz+yPb8Ot78POD6XOL+MN78WOT+ - 0fb+Lt78WuT82vf+LOD+LN7+Kt7+KN7+2vj6aub8aOb6buT6cOb6k+r+5Pr8aub6cuT8bub32/P84vj4 - 5PX6xvL8t/H+5vr80vb+INz24/L++Pz8+vv8+Pz58vn29fb09PT8yvT07PTy6vD53fX31vP04PD6v/L4 - zPD8svD4wvD4uO76tPD6rPD8rPD8qPD8nu7+nvD+sPL+wPT+/Pz+zPb+1fj83/j+3/r42vT86Pr55/b6 - y/P8v/L81/b25/T4uu78oO78ovD+uvP85vj+xPX87vny7vL03vL20PD8sfL6tvD6sPD8pPD4yfL6uPD8 - 9vz88vwAAAAI/gADCBxIsKDBgwgTCkzWoAGzhqQUSpxIsaLFiwIzbKtTx0yDiBhDihwZkpONkzbMgCTJ - sqVLAXVQ2qiz0qXNmxUzyDyZDKfPnwgb7LTRE6hRhcmS1aQodGdRjE+PWiTV4o03Z0slNpUZdSIpeHsE - jaEg1SI4QWgFqbu4FWVXiWaKyC2S5m3Zg0LSCiI0z2JbnhaDOZhb5A7ZuxL1ot3md6jdgxQQEC5i5zDi - hJwUCyJXkZnjikomF2FwWSI6zXIeF/TslCKzOpMdoCstcZhmZ64/Txwjeg1ticvy6hXiYSJrrhNJ3Jl8 - p/hvhek0wzOuO2GyC6LXPlfYYI7mcxKP/ruVGE30HtXbBUbT3CYrQfGAEzY4InpdeonJ1miGpRA+Ueii - zeHefQSdptgBqvmXIGyEOQAegQqRQo1mLSSkIEKkZCNaPhBOtIwhihHiD0IXHsSOHZPZkEGHE0Wn2D0k - VkcQBW+IVuFlpCQlUgNxaBbPQSUWZI5oEgwYoQACXCRAC97IMUpfGAGjGRxZ/fVfQQ1IIBpnFyUTjQQy - FLFGkhS1csCZB8gBjnMVJXOPZsUYZOVbwojWzUWkkFCJDHzyOUxFnKCJpjfFGGnQCIQoZogyWMoYwAg2 - TGYHlK6hUUSffdZhmUKBCoomJ8BYNKFi2g00J0HJqCHan0xVQwOm/phqWqannj7J1AEhUhrAqQMFgyJh - dayI3zFgwoopPugRJI4ctKIpRwtsJpSEZmYQZOVKyfAhWjoSkTLCBZMY2+ckaiRb0DzDNItmHOsYSkEE - moW60FArJSGaEOgxw5u4fQoxW0ikANOGumeu8SBCwWj2BkgwyVTHQMnsIZq8kCkxCL982lAoSxQU4w3B - B8Az4kGk2KYYfwJ9I1O1AjkjWhsYspMDxmGOddMy6jCrrhzOMGrQMonqdWMAypjBkRnCBvANc8scREIP - ktDszgg/kYLOPSDDAUtWLSg2zkCkUNBQA0+dMhk1cl5jB80SBGMoS8nAEgHIZhwsECnwohUB/pkKCSDE - XDlERcEvddBsRzpv25SBMzqrq060AowDzjiJL9TCNi08lScfNEuSRtKX4QyyN61UblEpaUSNMSW60ma1 - GSB/Y/pEpRSO8R7RzG4UBUnAQXAtN6mDsQPCmFtaAy00Lqg8N8UhriRqRMuiQCPAQyvwNoFjLAJ2T09Q - wJ0e8A3fLSmzR5+DtOt93+SIU85PybSwBlbr12///S6Rov/+/Pfv//+XYQgzBkjAAhrwgAUkG6pOwYkI - OPCBEIygBCXIiVOQzyfIQAAoCMDBDnrwgyAEISgQ4JxTTPCEKJzgKY6CgBC68IUhRIBSGpjCGqKQE0Yh - xQZhyMMXgoIs/jS0oRAhiEOgJGOHPUyiB0HRgACYcIhQjIA4cthCJVqRAAggiwDEEcQonpAT4rggTjKg - wSvycIQjiEoyKMDGNrrxjXBso1IQs8ax2fGOeMzj2ChgPPz58Y/1I0YtdvGTUsCDDuroY4fmIQ9PONKC - N1GGAx5AySbso4l+9IA4HMlJTxDSJtagpCgf4IR6bGp6pajFKDrJya/ZRAijFOUNMGCC9e0CHqzs5Cdd - koZYjvIJaGDGIhuZS06u8CYZ4IUvR+kHe2DyOf1oRTE5CQ8uQawlGWhDGZYpSiQcQ5H5U+U0HVmMaC3j - DbnohvQSkgEzSMAMpSDICCTATUrWgAgk/rgMMcAxTk+conUNqIEBBkqAeEokA00ogEIzATpSJOEW9XxA - IM7wTKD44xT9BEc8lkIKRgz0o4wJACka0AwQNKMBlkmDQld6gaVQgBpRiKgtTlBRmyBDmuMcBSzsEgwR - fHSgErjbCBDBBCYMQlikEMJKFfoAdhwkA5jYZj37wA7dJUQA5MDlOFuxzoVA4qcDTcNCBiGCsopgEAMZ - w1IVqoGaDgQdSIgoAXqwgpacg5/jlEfrClINCIA1EYdJBhPMKgImFCUDUVjrFVBgnWJcIqKAIINbKeKP - TY4THMBAT0DBagBTDIQChC3rM/ex1gI0QZgJoQAanhDRQ/xidgIQ/uc0dWquHnBWFc9sQGhFgNoAJMMX - pQXC25bBhxvU8wZzECNCatFPcXT1UAUAqxdiYK3dNoMgwYjFWstQAooEYxARhRlFiJlLvVaOFDzgLAA2 - pdvQguB7OigtBoyXjHSwgpuXqBx5qUmO2UXDC2DtAjSwtNv3EmQZqVjrKqZhkVQRwJeXMB45OjmKcfis - IhTYAWdVsJT2EtbABOFAaScw2YSMwAjGFaUaLFILeIxCHCO7yDU4a4HrEti9BqEAIEpbDYyQwhyHuEEC - MHHKozQAC2CFwAIO4mGzgpggSigtFHrb4IYU+SiY4OwGJtvksj4ZbBMobSOs+pwRBAGsItBC/lAKjBB0 - rGKtqXjGH0nhBM5+4Mq7YjPJIlHaPOCZReb4Ali5QA/56PkgyyDAWmWRBfxRAAqcTQF3Dn0Qta4VDyWG - EDY4WwEqy4nSOd5Bac9gvwYoAqxgYOykcayQJFxhrZ2u3w8464NMC6TLIviyQUixh9IugcxHQYdPf6oA - GEwE17o+1APWigWnsigZuOBsCMyFbIpcoLQ8AOdRlBAGsG6hrscGdVCesFZaSKNDyYgCZx1RkWpT5Bql - 5QWwccKMbv9UD7auLqsnkoxbrDUW87YJKZgx7IF6QQx+EXdCojGLpd4g4PlrQHo/2ofZuZsipIjvSikB - cZsw4weoSAUdS8B5cYpQgAhQgMIj/vybkWo7z/vGMEQAyZTdeprmPsF1vnFOkgYYg7BMYDnPe44Iwg6i - 40OHjAmIyoQJNC3pP6EAM0AwAJPu/C4BAQAh+QQABQAAACwAAAAAZABkAIf2hub+/v7+/P7y4PD+TOT+ - HNz+FNz+DNr+nPD8INzy0O78xvT8pPD29Pb+bOj+Htz+Gtz+Dtr+rPL8eOj8+vz6+Pr6cub6SOD6sPD4 - quz8+vr4+Pj4eOb4bOT4YuL4mOr8+Pz8+Pr49vj49Pj2xvD2muj89vz88fr61/b29vb02PDw8PD0vOz0 - tOz25fT09PT04PDy7PLy5vD08vT08PT08PL+XOb+Ftz8WOT+fOz+LOD8pO78ou78nu78nO78mO78lu78 - jOz6guj6YuT6oO74huj4duT2kOb4ouz07vT2ruz0wu7y2u782/b8gur6muz6luz4muz+cun8e+r4pur4 - mur2qur8fOj8euj6euj6eOb6dub+UuT8ROL6WOT6UuD8NuD41PL8Mt7+NN7+Lt7+Kt7+KN7+JN7+MeD8 - Ktz+Etz+ENz03PL+Ftr8z/X6vPD2z/D+POL8yvT8yPT4vvD+Q+L+SuT7tfD6tPD8sPD6svD8rvD8qvD+ - qvL+pPD6kOr6bOb4juj6fOj6eub6XOL6VOL+hOz+gur6h+j8lO76hOj8hez8fuj+jO78fur8iOz8aeb8 - TuL8PuD8Pt78LNz8iuz+k+7+mu7+Y+f+VuT8luz8YuX6pu74puz2tuz6nOz6mOz8mOz6ru76oOz8XOT6 - qO72xO7+VOT6qu74su7+svL6sO7+vPT8SeL4tu78RuL0yuz4vO7+v/X4wO78/Pz+2Pj8OuD8QN78QuD8 - ROD6cOT8UuT6cOb8VOL69Pj++vz++Pz67Pf+5vr8k+z6w/H6fub+y/b8juz6fuj64vb05PL85Pj6rO73 - 8PX+fur6zPL+6vry8vL6+vr89Pz63/b36vb83fj42fT81fb7vvL4zPL8zPT4xPD8tPL4uPD8svD8rPD+ - qPL+uPT+xfb+/Pz+3vj69vr68Pn+6Pr7xfP+0ff65vf85/n48ff60fT+9vz07PT4xvD8sPL6o+z+eur2 - 2vH+OOD+SuL+jOz8cOf33vT8v/P40PL7t/L6x/QAAAAI/gADCBxIsKDBgwgTCqRQYUOKDRVoKZxIsaLF - ixgFVshjyFA3ERIzihxJUqSqHChzdAtZsqXLlwIMpcxhiOXLmzgtUpiJkkLOn0ARVuCZw2fQowopULBZ - UQRRoxmZIq1IYRsDP26kKnTKE2pFAawaNdpXYerFBWLFLsDIdaZXit0cyHXQ761ZhJbSNrJ04mLblHYT - rpMy1wE9aXcp5tWryu9Ti9J+FHYgBXFihar0il1m8W9Pi2EmO/BxeWIwzY38BDbouWjTRZOlsCs9MRtq - N00fU8wmOg/tib6AaAZigmLr1QSb0ZtMz9fviW5QyzKuOyEFPqLTPZ9YwQ9qaBOP/k+kRrhwJeTbBVJD - LUHrQPEJK1gS3ST9RAp5UNdPCB/hM9E9uGffQMEslhYCyPXHmhOxBTPgRLTsg5ox/FVXEC3eiNbNgxT5 - colmlkyDkIIEVVPeXM4Ux+FE2KDGyogWDiQNA6LJQdtSI0njnWazsRajQE2Idgx6CNEigAAYCeCGHwiw - 0ldGyaDWh1QkBlBBEKJRkxEF1ASBiQN7IFkRNgiUWeYCKurUDWoo+NiVQfGIxgBGtFRDBCY25GlDPxap - YqaZfmBDJEEFanYJCAWR2M4UsZ1zUQMZ6qmnE4MG4OefZkrAmUVoabYWQQrSoodo2VhUAT8TSCqpE5ax - iCmm/k42hQCIT2pkoYmTHVLWfS4co6qqb1QagBuvYmoMohOhgNqGAw3FE0sU9CCaOxA2wwmev+aJCQbC - CnQOK8WaGU4TAgYgTR+obRrATs8OhIJoQJS7AR0OZKtnIuuMREsyEoRbpirgCYYaA0bFNJMhA1HwSGzq - GiRNGIzYm+cUKJRLUQXYMOnvPiIeREtYmu1n6UzMDisaH0W6oInENjhAFk7mLOAvAlgFdo6Bag0Egiod - dbOrpczVSlADomCbLSYMOPoTLcGIM3Mf1ki1jWa1DESLNA1VAJUxk+1jUAXcSMFyEMlYXBKX/frbTcAJ - S5CWBGIqJMB8cgHhlTTXOMHy/gRZJVbBkjOPk2YAAtQyTi3CUiCHKnJAVWcPLNP182XnyOxvoN1SdUe9 - Evfg4Ha0sNPNzOJkrtAvhrC8CDVmm0VBE334K7JLskgshT+mT/W3xpjaeJMfR+dhzooGnSPLq7O3VLuq - P3xOvEG0rHMpAuLE7RIFqefpSMXPyy2MOuUAJcAceWyTe/fop68+9LS07/778Mcf/2W0ONTA/fjnr//+ - 9z/kFQVuUIUEBkjAAhrwgAdUhTqs9xNg/CATBIigBCdIwQpWMBM/QJYbEMjBDiJQHUj5gQVHSEILxosW - AvSgCjvYmKDQAoIljCEJM4GYFK7whgVsIVAoAEMZ+nCC/pkoywZxSEQJgNCFIvyhEgkABcQIQB02LCIH - FcjAnJjjgUuMYSagMAKb0IIC0gijGMdIxjJKQymtc8nVKsDGNrrxjXCMozTSuL462rF70CiHMHbICh/s - 43zbOYExWEHII94EBA6IgyIxoY3Jpe8d6iCkJFmxx5vcQZGYjAMjXNCq5wmgHLKYpCTDd5NhZBKTdXhC - EronjHGIcpLowMklT4lJLnhCBBwS5CsnaciXVEAKtMwkJMLgyNKAABu7lOQ4Kpkwl1SADwQIJiYR4QJA - juSToUymLGqBLIGYgwhb4MHwKrIRfKjCK8EIgjQVaYd5NOMy0HBlMlmhDqEFwByv/jiAPgkwqApgQgcA - xcTkaHGNfKwzDjiYxQamcoJIznMc7GAKLf6gz4r6JgD1e4FGNwCVOwD0o/MwCAWIkYmDWqAenbwJBWqR - zV3KohyBcUEBKqrPSgiEFu3IQhnKcAXnCGQYHwVoHFxwEF/M4xXrrMMfqkFHuS1DnsmsxeAIQgFA0FSf - d1jIFArA1QI4YyBvCCpAhVBMgaxDEQclQAYa4BJoDHKexrBnQZ4RgaveYlcUKENXC1AGo1SgF2IlQxis - gwJIHJQUJCgrRabh0GRCtFwVaMVVD7CEhO2Vqz97hlh1MARcWscVXDgoFvTRVFDOUxbWGFQGJuuBhQpE - Gpct/kAKEjaBzXqCIud4Qh2S2oMqIqQc82SFVCvSjjJc9QZMIEgFYvsCgiRjDGK1Aw0qsg5GHBQcFnnr - K+NqEVogYrIA6OQGmFsQKGz2CZWiwDM2IU1ItE67ylyGbxFCjRtclRIxKMh4L9tcgpyjC2K1BwwuQgEM - RPOUkKjUMia5zcxJYwiTtQJT9rvX/hIkFZvNgmstEoxh7BaTGLhIOcYhC3V0DCPcmGwr2Kpf8hakAjbY - LByiQg0s1CES87AmRiogiatGABYHoXBXLUwQd2yWFCzGCEM2kNKpIGGyHdgwQYTMVSJb7QqbVcIdAxCM - M1y1AANACJULYOWBrMMeYu3C/irrSItiTPYITRbImMs8kE9s9g9xJt41DHBVMUxXzC4+yAgIINYxsGF9 - 0sDBZFugkDkrJKxitYCUn/eGyX5htglxdEKkAYnNkiB9IgDDVdWggIloOiHXQINYT5Fk4oFiskaYtEFO - XSREbJYKTTVLNR5w1QTIgCK0Rkgw4iBWSVSDeBSwwGRLMKhgI4QTm0WEjnESBjVc1RatznSgFVIBLogV - DdfgEAUKMVkWWMTZCCHGZvPBIRFYm6aEkDWg+auTfIgVDLlemgh4XdEb1OMi6Kavqj9ah3znpH7frSgi - 6BhwhJj3o6Rp9wdw0QUfZK7hB6nAPEhBCk4o9jm00JpIPTB+EGlsQN5b/lpss53ynCz3sihvuUukYYa9 - 9lXmQZFGFvZ6BYPjPCk04MBOrzCCn++wAdFYQTRe8PHSBAQAIfkEAAUAAAAsAAAAAGQAZACH9ojm/v7+ - /vz+8PDw/kbk/hbc/gba/pbw/GTm/Bzc8szs/KLw+Pj4/mbo/ibe/gja/rb0/Kju/GLm+vr6+lri+kDe - +q7w+JLq+vj6+vj4+HTk+G7k+GTi+Lzw/Pj8/NL29srw8vLy9pTo+PP3+Or29PT09PDy9Oby9Nry9Lzs - 9Kzq/hTa9PL08uzy8uLw8tju+t/19uXz9O709OTy8ury/lbm/hjc/JLs/Ebi/nbq/i7e/hLc+p7s+njm - +lji+KTs+H7m+HLk9orm9qzq9Mbu8tzu/Hjq+ozq+Jbq9L7s/HDo/m3o+oLo+JTq9p7q/Grm+Nz09pro - /Gjm/Gbm+mjk+Hzm/lbk/kjk+mLi+lzi+krg9OLy/Dbe+kjg/Cre/CLc9tTw/CDc+sXx/hLa/hDa/g7a - /gza/gra+Mzy/jbg/MHz9s7w+Mbw/j7h/kzi+MLw/Lby+rzw+L7w+rTw/qby/LPw+rLw/K7w/Krw/qbw - /p3w/KTw/KPu/Ibq/HTo/Gzm/J3t/Jjt+qft+pns+oXp/JXt/n7q/nTo/JTs+n7m+I3p+Irn+nLm+lDi - /IPq/obs/IDq+nzo/Hzq+ojo/ozt/pru/HLo+mzk+K7u9rbs9Mzu+Jzq9qTo+pzs/l/m/FLk/lTk/Dze - /DLe/Cje+J7s+KDs+qju+qru+qzu/lDk+q7u/E3i/k7k+Lju+rLu/kzk/Eri/krk+rbu/rjz9rru+qXt - +Lru/vr89NLu+L7u+qLs+qDu+lLi9sbu/Crc/Dje/Gzo+pLr/DDe/Hbo/DTe/Hbq/Hjo/uT6/Hro/uL6 - /D7g/PL6/tj4/iTe/ELg/iDc9rLs/Ebg/h7c/Irr/hze/hzc/Ejg/Izs/hre+tf1/Nv3+Krs/rr0/I7s - /r70/JDs+Kbs/sj1+O73/jTg+Nby/Mz0/kji/kbi/q7x+n7o/pju/Fzk/Ob4+oDo/Pr7/Nb2+fT59vb2 - 9vP2+uf39u30+OT09tny+s70+NHy/MT0+Mjy/Lvy+r3y+rfw/LLyAAAACP4AAwgcSLCgwYMIEwp0x6Ah - gwkKI0qcSLGixYEe4FCi1A/DxY8gQ4ac9ajko33uRKpcyXIhJZOPvqVsSbPmxAkwS860ybPnQAw5H+30 - SdSgu6EUGQRFSpFp0YgCPqBD98FpQqU5rSIUoObGATVanxYsd6DsgXIWscIMa3BWjrc5UIqVqMfsgUrL - Kqo1yZbgPENwczyCOFdhJbsHZuldSnHCrsA5DPUVOwvxAXZJGU/MBjnHgsIRxVnGM3mvzokMrnXGDFph - PssfUGuOKKZzndYR4dW1q8eDRNNCJYoDHPhRXtwKP1jO93s2QncWOqNFrnACHsvHrzo/WK/zjcm4Yf5Y - hhMReNgJlTproy7RXWXEMBSaV3iv8x7wyMUdtktH63yESkFmiDjsURQObNpl9Rw/ne1TIEUYLICYHtkV - 9J9Bw0H2iEcPbmaZGgBut1AEnd3T2lEgTYCOZaxZKGIAMHSmDn4ECSCARVGhQ4caFVI0j2X+MHXhQBMU - 0lkyF7kDQyENHFLHjRMxQ8eUU5bjW0Xu7GPZei4qWBAaneFxkTgRNGCmmfxQxA2VVKKjDZQT6YfYAlcO - NGQAIzwiYI/ydXDImWcGJ9GabFI5yzEVkYXYdHY6504/nYF4Ez6QAAroNIRFJGWhbObD50EY5DFhhUOS - QBxclHCokDv1MGkpoP78gPcBp4V+UGdC2ljGDUFAeRmAO3x0FltEI6CyxKtnLgEHjcvkQ2ubXCbkjj8s - DuROUARxBpkeYTHwRg7InhkICSC5w84sz07JDaIJzaMOYujA+ZJJlFh7Q2fzJDQBOX2Ea+Yj2dBolDY6 - phvOp7+qseVAJJm0q0AfdObPcyQA4m+TYNGEQTnp0kGVU7otitEsG+2jKjd7HiSPHceGuwQeCKskjjcd - +4OkQcrZFe2vDu0UcWBiGMSAPkZcXEi+RJkLQcfe9HgLtWVBAGdCAqT3FrcETQDFNRcbUtVcE7xT8LPh - 3BoAM+EwcwtFApQDRzlTk8DHxXGpWhg84XSMDv4zU7OUpRIX7xHzU+6QQOiz3vQt0i2UXHxNfB0q6U+6 - N7MUjr85lCNwURjMSuuwLOGB7BJz2N0hQc1yWvlK+bwKCIGnS8vO4d7UdEs3Z/ahzebUCXAMM+zW1HYd - X8du/PHIJx87Q/E07/zz0Ef/PANDufMBNxBkr/323HffPTd8E+WBHp7UYP756Kevvvqe9Aax9/DH7z0z - ROmx/v34rw9IStjL73/8D+OJO8qXvwLizxMQ6d//Fri9ANpkgAaMIPsgwgwGWjB79OuJOwAhwQ6aDxAQ - EQAzFHhB+IGPc4AgoAcPCAh4VO8oMIyhDGc4w7m4YwI4zKEOd8jDHuKQd/7KC+JzhEgdBpwiHYIw3Uq4 - soB8ZIqIAZiAHLhggCriQIkh8UAOCMDFJ+CDAUR0BxQoUMUyGmAPNNkHF9dIgD7EAIhFEUciyGDGMkqC - JoFg4xrdUAoZHI8BP/hCHc0YgTTqkY2esEU8OjQBfShjkGZ0w9paggEjHJKNlgADGJHDKiw8AJJVtAES - 7AbHhVgAFJfk4hWOcIJSXmQEk1gBKA1ghg288Se1iMQezJYQDMDhBnCYpEDEcYMrpJIAqRCEPObCAEx4 - YZYG0IICNikQDKSiANj8hDCl9YQ0eHMJ1YPCMI5JAAm8gZoCXEMXoOkFFZSgIO5AAjbnCYGFMKAEIf4o - AfUG0g9v+rOQ8BSDJ8hpDHs8sSUkuMQZZlkAALSAKfVwwDyx2Y2FjCAd4xiHI1QVCH96kwD0AFUEUnHM - WFyABK4UyAguYINZPoADRTjoQvwwUWw66FeQcIBOHeCIgfDDo96chEwFMo9rGDOVNcDEMkUygVaIApoV - IAI6C4IPG9TUGjNxxzh26oBxZHUdQE0DGKSVDSWQswEgmOpE3EEOXkDzC5x4p75WUdMC9MJaXNUpNe8R - 1icsUlpxWAc5IVEP/DAgEWWYJRmAQAO2YKKuVKDmBPLqAGq6QxJhpYVE4MEDVhzzFXxQ3EEYsAhoZuEF - ajXICERR02cUgSAMoP6sXInaBqB+YqkRmYcjyHkH1FARkr9IwV8j4o4j1HURT4xtXmcrkEGElQeTccc9 - npBKJfSFAb8YZAKiwIKKwOAZNeVCCywk24KMgBVAbUMMKjKBOdTgkNadyAXMWAYNtJK9T6jrEJCiXK4y - VyD9BCoTUpsQcQTiFWycQ1MmIY0d+ECTF9FHXRsxXDuVF54ICOsakgQDSLihBqbATww/ggEc1NQGmhgt - ZUNwkGyEFQEVbkpDUkoRQdQ1CKnt705ZbBRHhBUaUBymDmrqABcAaMUIIYEzgLqKkIaRCXUVwVADoGOd - 8vgguggrEqYcOyhIo6ahMMFVkIwQeHwivZBT3v4EJFDXTMiHzAj5KVB7QOAOyaGuFIgxefN65YNM4A9h - vWvy4NGGmlIDF+WBM0KgUFuPrmMEyetEXatQZ4FU2QF9Pkhxw7oNGiNUohP1wgl+o2iEiIMAQMWBk0/n - jh7U1QnXLTVCThHWI3haJeSgRk2dgds38xk1YPVoG6DAagrUNQlJkTVCxBDWHJyOAbqeKBYqDdsLt2cY - 6b31R9wRD1Bj8xko0Iu1JQKDRnvzFdpOEgOMO09bi3u5FnGuP3cRu3hsAhZugG5axt0eQSAAAadId0hu - uLlL/1ciE2hIkJOdVz0vvCaXpvbDmaoDrnp14j6ZQDq4ygSBY9wd8khERhCZAGmMazAeIRhAPiUuloAA - ACH5BAAFAAAALAAAAABkAGQAh/aC5v7+/v78/vDw8P5A4v4g3v4A2P6Q7vyc7Px86vwo3PSw6vyU7vb2 - 9v5g5v4w4P4M2v6m8fyY7Pxm5vr6+vpi5PpG4Pqq7vqi7vqG6Pj4+Phy5Phk4viO6Pz4/PzR9fj2+Pa6 - 7vai6vaY6PTI7vS+7Pry+Pfi9PT09PLy8vTy9P4Q2vrX9fTw9PTo8v5Q5P4u4PyS7PyO7PyM7PyK7PyG - 7PxM4v5l5v444P4O2vxy6Pp+6PpY4vig7Ph65vhq5PiW6vaw6vae6v4Y2v4i3PyG6vyA6vx+6vqM6vqG - 6vam6vPf8P4g3Pxq5vqI6PiQ6Pxo5vpo5PbC7v5O5P5C4vh25Pw84PpO4vwy3vpQ4PfM8f4i3vww3vwq - 3vTU8P4c3P4a3P4Y3P4W3P4U3P4S3PrA8fy78vLO7v484Piy7vqx8Pa+7vyn7/qs7vqm7vyi7vqk7v6V - 7vye7vyc7v5w6vyW7vqQ7Pxt5vyI7PyJ6vxu6Pxw5v526f6A7PqD6PiC5viA5vpw5PpW4vqA6P6G6/6O - 7Pio7PiY6va27PqO6vqQ6vqS6vqY7Pxg5Pw+4Pw44Pia6vqc7Ppg5Pqe7P5W5f5M5Pqg7P608/xX5Piu - 7PxP4v5K5P5K4vz8/P76/v7E9P5G4v5E5P5E4v7c+P4s3vw64P4q3vzy+v4o3v4m3vxA4PTm8v4k3vxC - 4PxE4Pil7PxG4v72/PxK4vii7Pzb9vrn9vfD7vx66PbY8vrN8/p45v7O9vbw9fzF9Pyy8P6w8vz6+/r3 - +fzW9/r0+vjn9vrg9vTt8/Lq8PfQ8vTa8PrE8vy+8/TO7vi67vq48Pyr8Pqu7vqo7vym7v6g8Pyg7vya - 7v649P78/P7J9v7k+vz1/P76/Pzj+Prt+PjA8Pfb8/rV9P7W+Pfy9/zL9fy38vqs8Pyi8P6u8v5w6Px2 - 6Pzf+P6x8/zo+fTk8vTc8vq68Pyu8PjG8Pq+8PbK8Pq88vbo9Prb9fx06Pq28P6e7v638/74/Pbs9vrj - 9/699AAAAAj+AAMIHEiwoMGDCBMK7ERBg0MKCiNKnEixosWBHszEibMM4sWPIEOC9Heg5IFlnUSqXMly - YRyTB+KkbEmz5kRgMEvOtMmz58BgOQ/s9EnUYKehFIHmREqRadGIAoRduiTMaUKlMK0iFNCrWrVeHp9K - 3DWt7LQPFrGa1HpwWZ+3fVCKlRjB7LQIpyqq1VmxFty3M4DNjWi3rD+9QdkSBMbmbx9Cggcn9Fd4GjuK - GhJTZOG4TwTJCrtVXqdYYOalEzXE6XwZdMJelcOl1ixRWWczrhUOq2s3gjaJp7NKNEHD8YxhuRUKq4wN - OO2EnXx1HpdcIYVflfMqDL42Yr/O1Ur+5+5X+fD25wcpvOmsrnrETssqczuPOiG4zs/cS+zG2+w5rdzx - hRAIBzhGiHb6KTROZWghFKBQCZXR2TIJShTMOYX55iB6BHVDiGOFeFChRLRU1suG9RUEDDydNTjYUSAB - c0llrRX0oFPFdJaPeAYJIMBF4VizDjYIVsROZfowtReEBVEwR2fzWdRJP3PQkQA5P040yi9c/rLOByJW - 1MknlbVX0JJM5dKZLxeJ8wwdcMJZBkX+dNmlNepkOZEJ/ZV1Tpg/cQhCIQYWGVEwZSQQZ5wHRBbRJ3ba - 6U+NEn3A4JnodUJPZydORAE4NCy6qAyOKrRlpHZi85tEFGDYW5H+aHb44V+NStQJMVWKuqgyPIazDqpd - riMMoAmpU9knBFHwXCeNOcbCcGrwoWucfDjDo0CnYAPsnVEmBIw1NA6EU04E0dLZG2xpoIyi08I5TTch - sVPntr98Am9CohV2iZ4vmRTHQJ2s5lgt3tojQ7twzkDLtQcBQ4s19P6yy6pGwVZYtySZRKFAwnRGDkK3 - voGwlb2UqpIHH/y67SWj6EnQboW56IE/Gy0DqD+O0UAxQeKQIy3C8Bja0im9RGxNNgctZ5eZAgFDwdM7 - heMYdU3mYsTI1RBMVCfyRvyJoQKAW5Y1Lm81DVzTDAXMCQyMXAM4DIfk8CX0rrMLsQGMskv+y019YMYH - Q3XDxsh8LGOyWMPsojKwLJe9kgDL/NzuMya41w2k9H7ieEgCxDEyA/1U2Ak3EG+LdEvYINwH4CMKRIFU - wMrW0i/T8mFGMK0XdMo4qJ7OUuqivnFv7gZ1zWVzNG3jOZwyLEy8QtmM4jtNAnxAzgebP6/99txH1FAD - 4Icv/vjkl69BWFtTUP767DdAgaMUGMMBBAbUb//9+OefPwRNVO6TJ29oggMGSMACGvCAB7zBG0SkAQ7o - 74EQ1F8TDteSNyDwghhEILoaQL8IehCCOUBfTQSYwRJicIIa6OAHV3i/FcTtJiQ0oQwL2ISnNYGFOKyf - Hohijhn6cID+GBDMMJqQgxx6MAd6iAVRPBDAH5awCRgAwU7Ul4IBWPGKWMyiFgeQAhQ0gII26YTTnkbG - MprxjGgExgu7x0aAtRE0FICGHy6At8d9IgLjAOPzKOANK6zgjzaoY0g8kIAXGFIHyBAh8TrxjUb88ZEr - YANNzGDISr5gBifQo3vE8YcwQPKRRqCJHCxZSUrAgRe504AhFPBJSOanJfQgpSVvsAYNJIgCWnBFKyH5 - Ak/QhAJGkKUlb8ECRc5lSlHY5SOJcAhirXExvnCAMCsZg3o8EyQmQMIXlLmCMWxgFTsJBhuMwAbcTcQD - 5KgD2TokgWkakhJtEMdcNJCGB3BzBVn+OIMtBwICTBTgn5TwZUSAQQcCGJQPpepEMQrpzibEY589AQYy - NHFPLCygAQXpBCT+yVF9DER9XtSAo8xg0JKWwyDAUMYE3PmCHXzDmCqpxQbGwM0vdMAYTCEGDDj6TwYM - xAR+QAMaaoAcgSCgpAadQj0OEoxnUMKdlGAEP65JEBAAoQD3/MESjNkJXfD0n7gJQCcI8YCyPgAPA1EG - Ug2aCJh2IwYsdUAaMCoSCjQDB/e0AAkgahBkbOGrmohMJ9Bg1gegYSYUuMFaqYAL6LCADyzVgxZgqhBg - sIAH9+yCElBgHX9+lQTiKmxZw5KLtRJAB3xFqTxuwNIanOBawej+JDeHAIBjKCYNXy1AIMJCAdE+gK4B - AIYRTLuG4cDhqdOkBBuy16Qn3LMCyaDsT63wVVMsIVm+BW4A+gGKtVJCnhKpBQ1YyibgOEKZjiiBdqGj - iNw+oVS9FS1nCSIH085CkwD7wB6myYfSaEAVrUyFEOY7kROY4qtWMEaTfEtggZiAEmvdRDsqAgxnSJOU - /Z0IECApBh+4AL+L2UNug4CU+Ba2wQJ5h2kzIF2DmAAByDXkx26ChFSAoRG4aLFBtJBbTKw3ACY2K4qD - ewfTIuMiCq0BJRzQBhADTI0vpIANvroFZqSHwQdhgWmb8GNbPc3JLblAbqtgzCCXdchizYP+aRHxxm7g - 4KswmPCV5YuQWmzCu6jsXieckNsRgNHMD0CzQNxgWkiAOTn2SMVXW6GChABa0AEAgQPWCooTcA8YE8ht - CKyD5YSoda07SG3rvJHbRnT5o51GCDDuYdp5aA8EoPgqK7zgvVQjxB5UWOsNTu0eS+T2Dy1+9HtiYNpM - UNUm3XjAV7HgAlbZGiHdmMJaX8CP1nViB7kVQWmELRFomHYRhy4KOFjxVVnwGrt0ZtWkkRoKe4iuArmV - AkW4LZHSrjUBFQIBuXkaBVEjhN4DTQClj62STjRA2RxFhTsqAvCIFKO7JaUEwUXCkPZydBHXanhEJoFU - N4yoAT3QxAtLMMAwjVf2Ak1oAjTCXRSGRPnZEnGav99oEECfm+YqAbSOcQ4SCuCgsGhgOc895YfConXo - PAEGL4KKhiIUFek1AUYDUDAAL+78KQEBACH5BAAFAAAALAAAAABkAGQAh/aI5v7+/v78/vLq8v5K5P4a - 3P4K2v6a8Pyo7vyO7Pwu3vTC7vy+9Pyk8Pb29v5q6P4q3v4W2v6q8vym7vx26Pz6/Pr4+fpu5vpO4Pqs - 8PqU6vz6+vj1+Ph45vhs5Pia6vz4/Pz4+vaS6Pai6vac6vzl+Prw+PTk8vTW8PTK7vfk9PT09PTa8PTy - 9P5a5v4c3Pyi7vyg7vye7vyc7vya7vyY7vyW7vyS7vxa5P5w6P4v4P4Y3PyG7PqI6Ppm5Pqg7viG6Phw - 5Piq7Paq6vTQ7vTu8vyW7PyU7PyS7PyQ7PqY7PqW7Pic6vx+6vqW6vam6vvB8vx66Px46Pp+5vTo8v5W - 5v4Y2vpw5vh+5vTm9P5M5PxK4vpY4vxE4PpW4vw04PzS9vwy3vbT8v4W3P464vzK9PnA8PzE9PzC9P4/ - 4fzA9Py28f5G4vqy8Pyq8Pqw8P6q8P6h8Pyo8Pym8PqM6vpo5PiQ6vqE6Pp05vpg5P566vqI6vqo7vyC - 6vyA6P6A6/6K7vp+6PyE6vyG6vyI6vxu5/xW4vxG4Pw44P6Q7f6c7v5i5vxi5fi47vbA7va07Pqe7Pig - 7P5Y5Pxc5Pik7P5W5P5U5PxT4vqq7v6x8v5S5Pqs7v5Q5P669Pqw7v5O5PxM4vqy7vi87vxE4v699Pz8 - /P7X+Pw64PbE7vqk7vxI4vpu5Pa87vrY9f4m3viU6P4k3v76/v7p+v4i3P4g3Pi07vp45v4e3v4e3Piy - 7vxY5PTe8PyN6/7F9fTg8Pz2+vfv9frK8vTk8Pzs+vri9v76/P464Pbe8v7g+f72/P7K9vLy8vr6+vj4 - +Pzn+vr2+vfp9vrE8vza9/jU9PzO9vjI8PzG9Pu88vq28Pys8P6o8P629P7B9P78/P7b+Prd9v7s+v7H - 9vz2/Pfx9/rS9Pzx+vrm9/jb9P7k+v74/P7Q9vjM8Pq68Pyu8PjM8vyw8Pyy8v424PzW9vjE8P5E4v6K - 7P6a7vze9/bK8PrG8vq+8vy+8vrA8vy89Pr2+AAAAAj+AAMIHEiwoMGDCBMKLMXMQjMLFRRKnEixosWL - AyugiRPnjAWMIEOKFInmgMkDvUaqXMmSYJyTB+K0nEnTYgWYJkvV3Mmz4AacB3T2HIqwlNCLFoAevbiU - KEUB0jqRkoYxKc6mEgUo41iGmdOKYCSIlSAPqdKLaACpBWQN61eDmcaKTWbRKky3CIetVWsj4luFcsWG - q3uWYoVsewEl8vsXYa/AEpxVtHsSr8FviQFlaqywHOROAihSzilaRuZhnBVSg+xNdGGJZTIzSK3wV1y5 - mUBMHB10ookbiW38oq1QGmRqu18XvZYZDHGFFTpBLieRt2WB5jLHYfz8YAnI3Kr+KzfITE7mEt0Vlnoc - GH1C6wpbZYaXXqLnwNu4F4SPMGniRNTVp1BYgZny3ngEWZPZGQJKFMJtY2VC10H8GWRCIokdoFuDCt0D - mTL9IRhABWtkVlZj10HXD2SoGVQhQcRkNkeKCAkQ2kXekEKKOhNeNAxkpFCIoAUNnIdRKebEoQcPpNw4 - ETKdRBmlKfpJVEo4kLlH0IsCkZPZNhiN844eZJJpTUXhSCklKcg4OVE5EIqV337jPWPDfwGKdgYPZZZ5 - QJUHKaOmmuGAY5E8kDm3pXKlQJFZGRUx00oiffZZA6AGoTPooDyKtg1kww3001UEXZghpgSVAk0DlVba - VkX+yJCy6ZreoDrQd4ENJipQqb6TGVUSjbPGH62W+cc+thr0izqzSskNOhJVwACLGfE6EGaJSXCdBcHw - WSyZcrQI0jC9NBulMnke9GNgoA300kkyCVRBHJnJklAF39jwLZk33EMjdLGa2wkYGwYKGbQC9QJTSgKZ - klk/RUGDwL5LlpGsRSCYIjAp3rg5kG2BnThiLxydwVgvid0QakEcXEPst3+ssTJN5VAjcC/2GmScXAjL - 2xAzRzm8F3IFMeMlxXFoyVMpspRrLroFCcDNWOFNJIAEa0nAXQXE0EBxIvL8u1IFAZtrSsECIQNGmxVV - AIYa8nAHTDsU/2Fyar9obC7+mx6vJAAUL3/bTrqplSPo032LJMABFM+g9HOllMCNuT2vpMy+gIBxcWMV - 5Dhray1tU+wfDKDNYQC/gLFp5SpdXikCJpyeV5rn0lSBImXa4K/sCsmCTM40CQAGA/IkzvvxyCcvETPN - OOD889BHL/30zXjlVCkWTK/99g5ANBAzwHgQgQHkl2/++eijP8YFsfcUixw5PCD//PTXb7/9OcihWzMe - pO///+krxOZAIof7GfCA90NAKRwwPgA68H8RsN5O4ofACh4wBxVoRgMfyEHz7UBsF6kABS1IQvrlgBnM - uEIHV0g+CgxFAiWMofwQEJFfUGAHLHRgBCjQo52AAH7+MqxgDhDAgaNkbwXLSKISl8jEJi5jBStwwABH - UooKoPCKWMyiFrfIjAqAUHlgNMgXw7gSC7RhDxkwnd+wZDEyjigaXSiAHC2hRpFUoA8uyGMUpiHB45Xi - Gz6QoyAL4IaZqCGPiHTBDVQwxcaYoAezGKQgeTCTBiQSkYvAxDhOxwwhhEGSg2zHTKBwyUQ+YB7NqE8F - 3AEKUA7SBcYDSQV4UMpE+uEcfUQRMS7gSkFCgAncGaNBSPSAWiJSCdAQ5kg4YAdX9LIAt+hAFo7yiwwM - IgMhqAgIOqGIJpVKBsbM4yLasMmvMKMWiHhmAbhAhI8M5BmTgIA8F3GxClCAAPj+1EMwv0HLcOagGu7k - SQXE4AV1nuIRDihIKX4gz4Z2YiBHdEAzGAMFfFq0DcMMRg7C6QIeHCOXLIGGLV7wTFeIoAhYgUY8GirP - GgyEA3RgAxsSsDIYWBSfVYDGQULwhkVwNAbAUKZBOPABCKgzCL4AVCkCwVJ5ziYApUgAGaZKhgQM5Aw3 - xacGQCqQYRiBow9oBAdUUgFRpEGdGEhBKhEyDR001RB+KQUbqEoGNgiFGYXIqhbOkZBStKIJHKWAO7ga - rXPkQZ1fGMIKFMKMeDYVHxmh61QlSI6sEiAKa0VIBaBQzHAmQAUgtEAPaPHMWQBgACmqRVMhgIeAMkOy - ZEj+qLwIYVlHTOQZCPCpMReRjVgShBkaUGcdWEDYUo2iqV/YxW9hK1vscCKriyinREqABI6ugSLNOEQv - D7GA5qpnCat9BXcswNyC2DSrfNhcKcAgBWP+gUYWUAUoFTCCxVaEGG5lKRuKsJ/yEuQZi8iqJU5gk2t0 - NpFN+NcHBkkLLFBhivZc7SOaQl7Jelcg+rAsLwJKERPA4JLXaBsSdACLRYihuAhxx2oZceEAVJiuLban - ZadxJGIkYBEPaMMUq2gUkFjAEE3VAREoBFv7FqQVlqVAiyfCEO/9ZROrnQKHIVrkg0TVso0gownS0NR4 - EJjIkjVyQUxgiay6ABhgLAX+HVZLAky9mKpiLkgGLBuJRqbmG/lt6BZa8J4qIwTAWeWECpJXgUKsVhQK - efNU41wQa1j2DlPmUDRW64MlUznM0ImCZddxvGdwIsgoqI6fE/INLWT1AZbuTipW24NI9xfT6qmBZUMh - VJ6YgAxNJQMVdjPqhJigCmZGc4NKcYfVPgG+vU5IGyyrBDv3pBV5luclUr2lZPfnAVn9BF/rU4oHrBYV - k7E2QoJh2T4IyALRhsAVMitqC7etD1nVRK1ZUopm4LqhOjhGXfxLEWI816IumPdKsAfehiohtPymSCpu - WkgBNYMSOHABDZGS8IlU4A05yIGOOcQQYSo6thipgAUzXO3GolW85DN5rWRJjnKVMIMedGWDs1u+PDrQ - lRc030kFxhFTNvBirDm3nQOQGEUU/yUgACH5BAAFAAAALAAAAABkAGQAh/Z+5P7+/v78/vLY7v5E4v4i - 3P4E2v6U7vyU7vww3Pwe3PLO7PyY7vj4+P5m5v404P4G2v6k8Px26PqM6vr6+vo+3vqk7viW6vr4+vr4 - +Ph+5vhu4vhk4viu7vaU6Pz4/PzR9vaK5vbA7vLy8v4U3Pjv9/b29vT09PTm8vTM7vS46vSk6PbY8vLq - 8PLk8PLe8PTy9PTu9PTW8PLu8v5U5v4y4Pxc5Pp65v506v464f4S2vyO7PqU6/pW4vig7PiE5vh25va2 - 7P4X3PS+7PSu6vyB6vbO8P5k6Px66vqQ6vna9Pii6via6viW6Px46P4g3Ppu5v5o5v5I4vxI4vpw5Pw2 - 4PpS4v4k3vpE4P4i3vw43vwy3vwk3Pwi3P4Q2v4O2v4M2v4K2v4I2vq28PfO8fTS7vy+8vbG7v5C4vjC - 8PbE7vi87vi27vyu8Pqw7/qr7vyp8Pye7vqo7vqm7v6i8P6g8P6a7vyc7vya7v576v5r6P5y6vpe4viK - 6PpU4vpK4PqH6fpy5Pwo3PyY7PyI6vx86vx66P6E7PyA6Pp+6Pp86Pp85v6L7P6S7vxu5vxO4vxC4vw6 - 3vw23vyK7PyM6vqa7PqS6vyM7Pik7PTG7Pau6vxk5f5b5v5a5Pqc7Pxf5fqe7Pqg7Pqi7Ppa4v6p8f5Y - 5Pim7P609Pio7Piq7P5O5P5M5P5M4vxM4v629Pz8/P76/v7G9vw74P7Q9v4r3vpo5PxE4P7c+Pzu+fiQ - 6vxQ4vxS4vxU5PrK8vxW4vyU7PTs8v7m+vxW5Pxa5Pbu9fyS7PTq8vzZ9/Tc8vp05vp25vjj9P76/PTg - 8Pp45vbm9P4e3PzF9Pz6+/zX9vn0+fbe8vTw9PLw8vre9vq/8vjU8vy/9PbM8PjG8Pi+8Pi48Pyw8Pq0 - 8Pqu7vys8Pyk7v6e8P6w8v7A9P78/P7K9v7Y+P7k+vz2+/nQ9PTq9Pbz9vze+Pnl9v74/vTg8vbp9PzK - 9Pyo7vyi8Pq88P669Pzc9vrG8v7E9Pzk+Pyz8QAAAAj+AAMIHEiwoMGDCBMOlEahAQVpCiNKnEixosWB - zGKRIlUP4sWPIEOCjBWhZIR0IlOqXEmQlMkIpFjKnFnx1cuSNHPqNCjtZoSdQBW+AknB59CPR4NahMcv - FryLRW8mnShg1kYQHpVKPHaq66lbFqO+nCox1oGzB9KR1Xown9dTrthVFGtybUJcaM+Wy8oWoau3p1BS - pFvS7kFpp/IeYGC4r8B0gE/hGmyUIjbFB1w5Vogr8jkBEwlHaEwQQwTMkzcnBBH5qUTRpAe2w8xPtUJ2 - bt/m+/C6ckRq5RSX4207IbzI6npLjfhqG+ZpxYWeiyxXIeyI8TCTAh39bmTBCa/+hzeHuV93oZABB7Pu - G6E+zPnO//779lxj8Qcx0FHMILX8hNNEBhZC+BlUD2b1/BcRBrl55QpxBhVIUAl2KFYHhFrFllA/kYFA - YHsEvWIGZsc41oAJJlDwkTT8ROYfQRIKlJ1ibWjIUgMaCBGGFWTwNVFngMVyUIwUkILZeha9Eg8phzBy - TkVJGCClAWFQQc9Fs0SGJIwgCjQNZttcVMIYh5RZZoKvaTHllEJc0EBF1NDn1WcFSYhBHYrZUd1EDfTC - iJlm1qGhNGquOeUWa6g4EVeAlcjlcgO9sg+CFEmjBAOAAhqHjwj9YqihPSgx6HRvxfXoSwXhpVgEzEj0 - Sgn+cGSaaT02vvIDGJ9OCcYNJUjEIWCzENTTTSG6gplrClFjhqyAMhKNjQK9IkMPuU6pgA9vJvRKLC5G - 6hNB/WBmDmkUtNMIs2a28WJFDaiQQLVSytKNogcB+VZtA7lkUkwCCWCkYusKi00c6JZpBzYqWeOBEPAa - wMcyhrGm3kDpvATeLZg9iVAJbRR8SCO0siSNCxuEAa8XP/RqEG6ADRgAM+lslE5WZuVVzp4EUZPNnwXn - Q01ODSzwR8NcpJItQce9tWUArzAkTVIY5+VhnbN5DEfAM5lAhCANY9EjQQJw25WQEglA3lnjChsPHR4f - 4KhSr8wQgg7wQlDLM1Oto87+OtyVPU0sx/QdQAn+eMxIR5tR8AIHEMBLQhI/z/RKNDyj60/ktjWQSQUN - 24K5SgKwXXAE5sl3wgoFwCuKTLMUfMA00GbYAgBf5OqETPkw6ywGCtY5wCifrs5S65mCg3XvATQggiRT - SoFhSgJEYGY5pSOfUAPgENIGLDQJME00x8Ru/fjklz9kA+inr/767LePPr1AvdKQ+/S3T0FSFMQQSAEk - 9O///wAMYACfIIHP0QQW5sgDDhbIwAY68IEPzIM5eNOAQAjwghgUoAQ4xRJzQPCDIIRgjRrAvwyaEIMF - gN9MFBjCFoIwD9Ig4QlnGMAsiI8ir2ChC3fYQBhSQAL+NAxi/5AAlDbw8IgLbANE2OGEEgoRhUiQB1A+ - 0AYdIvGDeWgDBpJyohF48YtgDKMYv3iCBnCQJk2ThhrXyMY2uvGNTzOfHFVywzmqBANjmAA4eDcTAaTD - HFixo0Ck0Y1HXOGQNuDjSpjBiCM4sghKUKH1XoENRxzykldog0z44chOHoEB8TjjeUowAVpg8pKMkAkc - PNnJKLjhHcijQAdkcUpM+kMm0WClJ3HQjaNFRxrt4EUtMfkJwaVEGjvQpScJEcniKEkCw7zkA3yAoToW - RBpm2IMyOxkHelgzJNTggSmjeQUNeHMg7HCDHp+XEAxsgw50GgguyOGAbR5BD2P+MOBOKDAGNJDzCnwo - gy8x4IAHGDQKrYoIM4pAg4YWwUfYoIQ9j4CEdvgSjdr4xD8JEAQTGMQCBg1pfARyIhSZcSDRaKhKx2CQ - V9QjDxPdwTJEGZJ4JOKfNbiANdaCCzSE1KBxGAg1kqAKVRRjT3NQaUOPQIz8+EMP9nSABVS2EmqE4gH/ - BEIzOPgKQPzUoNGIViMIQFYCHGAg9VBqQyshSYHgIg4T3QM+LnoRaaRBCv/0RQroOhAlfPUBn/DIK1RR - VgKo4ijSkIBaaaAEbWHjEBMtgjbayhwlbOKfOdCER8Ozib+SYSGFJSu9tLFYRPA1UvvAwUQREA+LNKCU - 5KT+RS6AEZtv/FURR5NGaAlwtFfsYLHdkAg72gDVbUYBHINhwj+hgAzK5kwVX83BPGC0280KpB+dUKse - YOkrBkzUDHwy5DAfcYbTGqQSf2UCXxpQ3YLIYbHiqNU0irDNQ/BJF7Wsgim4O5F45OCrj4hBQdgbWusK - hBoOUCsnnlERbGqTlYewUSgwSYsfGCN20lDEX4NgEAIX1sACycZif+Hcg1DDHvXsZDZwyIMc0EIPLCjx - Qdrx102AOHntvWYhFquNj2QnCjgYQ+xeQeQ6SsMGfy3DQTxc1hsHQAmLRYJ5tUWBhzjGDX/9AV+ZTFYn - v+IXi/WGIEsgha+iAQUI4TL+AZwcAFxwQq0OoKr5ePDXJZxRzWwOgBsWawGaygcb//3pLmBwvRznRw9q - 7cQyzJfYv4pAIXhWSC8WO4Epd6cbf4XClCOdEGkwVK2fHV8DShFdFkSE0wnBxmJxkOfoyOGvlT61oRHy - ijssVsjIwwUBvkoAd0gE1Xc5ApybqqBXTOCvqdAQsBMyhsWC4ps0UUKgQzqMVg9k2QjBwB4WizD5vMIR - fz0DRbCNkHYsdhL/acC0DSoBS1971kKZhIKhfaNdhzQH1WAXvBUSjzer9Aj0XkkD0BvSoOq7wBZ5r0o1 - mW45fGITbxAfuTsdDiQgYQx+TlwdJ97phggyNLt198ctQ0KBkI98J9IgbFlVkfGTrygJhf2Fy3UijXcQ - VRWW0OfMVRLDE4zgBCn6T0AAACH5BAAFAAAALAAAAABkAGQAh/aO5v7+/v78/vLe8P5M5P4c3P4a3P4M - 2v6c8Pwm3PLY7vzE9Pyi8Pb29v5s6P4e3P4O2v6x8vxy5vz6/Pr4+vpu5vpG4Pqs8PqY7Pz6+vj4+PiE - 5vh45vhq4via6vz4/Pz4+vj2+PbC8PaY6Pz2/Pzy+vrh9vTU8PLq8vTA7vSw6vfq9fTw9PTW8PLk8P5c - 5vxW5P587P4s4Pyo7vyk7vyi7vyg7vye7vya7vyI7PqC6Ppc5Pqk7vqe7PiE6Phy5Pik7PTs8vao7PTI - 7vS67Pza9/qa7P5y6fx86vx76fie6vao6vx26Pxy6Pp66Pp85vp05vjV8/Tm8v5Q5PxC4Ppa4vpQ4Pw6 - 4PbO8Pww3v403v4u3v4q3v4o3v4y4Pwo3Pu98f4g3P4U3P4S3P4Y2v4W2v4Q2vzO9fi/8P484vzL9PbK - 8PzG9P5B4v5K4vq68Pq08Pyy8Pqy8Pyv8P6o8fyq8Pym8P6g8Pyk8PqS6/pm5PiL6Pp86Ppk4vpY4v6G - 7P6C6vqK6fyW7fx+6vyC6Px66Px06PyA6vyC6v6M7vyG6vyI6vxr5vxK4vxA4Pw43vws3P6S7f6a7v5i - 5v5W5PyY7Pxi5fqq7vqg7Pim7Pay7PyY7vq07vpg5Pxb5Pqk7Pi67viu7P5U5Pqs7vqw7v689PbG7vi+ - 7vxK4Pa67vxE4vTQ7v7A9Pw+4Pz8/P7V+Pw83vps5viS6PxM4v76/v7l+vxO4vyU7fvE8vxQ4vyR7PxU - 4vTa8vyO7PxU5Pqy7vTe8vr0+PqA6PrM9P7K9v74/PTi8vrr+Pzn+P6A6vjc9P5+6vbS8PjI8PLy8vqo - 7vrQ9P649Pr6+vz0/Prl9/jx+PT09PXq9Pzg+Pja9Pbk9PzA8/zU9vjC8PzM9vzI9Pu28vq48Pyw8v6s - 8vys8Pyo8P6k8P7D9v78/P7f+f7p+vrJ8/r2+vrO9P7R9v76/Prw+Pzr+vji9Pbg9PjM8vrX9fi68Pbw - 9fqm7v566v444P5I4v7b+Pj0+Pf09gAAAAj+AAMIHEiwoMGDCBMOnCCt4QSFECNKnEix4sIzESKceWix - o8ePHs+MGznOHciTKFMSjEByXASVMGNSnNBypMybOA3SrJmzJ86dLV35HEqwFjFi2CwCJSm04quM3DgS - hZiulNVSSWfWHNd0ojcEYBGc6ToV4bmrpViR0FqTLER4d8IioOO2bEFWaEuZnLh0ZF2ErkrJRXDnr12B - r/KWijeRwlbDBrENRlDqcMISiokJkOi4Ledxg++UsJywiOJanz1H5DaZGOmEH86iPSc1YeegEYOZG0zn - w+uEtRTzi3ibKURXCyYX+Z1wAjHFoxUW9wvx2OQIm5kjjKd4r+3HCif+gJuMTLtCd4rVSQefUPLgyuYT - TsOLVvN31Qcp0AkdPT5Cfoqlcx9uCJ0xmTf+hSfbVef4lh97BsHDAG+1DQUZRMHl9QpC03F1kCusKGcX - BQ00IE1HrjyXV38EdfgXMtddGBMFPjwghh/MVBgRZnm5phOEA0kTwWSMVeTKMREkIggbFOVxwJMHjAHF - ChYllpd6BfXlYUFFTLaARdWUksiYY54hkTSOQAllGB6EQBE79DGY3UJABqDfYAxMQxEFwwhCJpl0RTRB - mmpCecUpJ0qETYBZ1qnGZN5BNIEJd/z5px06HlRJoYXuoIyMAUywoFVqEaRlQXANNk6mBR0pjqX+lo4l - 0QSBiMEplGIIU01EyCi2IZ08DRTYZFkpFMw2kcBKZiTfgCpsCzvcCmUCQFCgkCtnQAdsSwRRM1k0EFEA - jSTKkhkBixQ1QMQV0j5JRTOJHsRjfSu19JJAAgwp1x1FHjQpHuWOyYAJKLEwQhjtQtCHPIaZduVAIpHk - XTqtJQQPOAEnIok7rCrlwg9jtEvGHrsa9EGcVgmIrzsZbTQQMYOZs5ZB7OCSbMCssHOTBqtY0e4BkIRi - bUEZXoWlQK4wNEFXFMvFjUHS1INAxhEc41MDKmTxcyPQVJitVZEqFE1Y0cwZKjV0ZHzHckS5wgIABrRr - RgUrkFULP6hNJED+EcTwYzY8YgYciTcd4yTNAB1A0G4Beegc0wRq3FxuKeja1cAQFmzteEoCpB3wOOWZ - 18ASXLSLD0zcBIxAEc5O5QoKG5RxKx8wsaJsJGwU/ps0CnTC6ekqvQIrOJUnKFADKbQC5RQOcj4OmeaE - brxtcOQQge4W7c0GP61P7/334CM0AQUalG/++einrz4F2KPkijTqxy+/BtJ0NcE9HHBRwP789+/////r - ghOC0RNaROAPMUigAhfIwAY28A/XsxMHAEjBCgIwCe3rSAQcyMEOOjACrtCA/ixIwgpyIYMWQaAHV9jB - P4xvhCWMYf+40D2KuEKFLMzhAl04ASTI8If++xtETzaowyLGIA4PYQcSYAhECnJhEMXoyQfigEMjcvAP - cWBHV6TRAGd48YtgDKMYv2iNBqDwI0mbgBrXyMY2uvGNSwufHOdIR4NQIBx5gMPQYCIAYkSDY3UM1Tpg - IINCTqJ5KJlAJBzAyBzUI17gM4EECklJGcQBJmxgpCYdcIO6fa8aedBCJSkZCZjMYZOaPAIcSuYfCsiB - CqOsJDhg8g1UbnIZ69jjbyYAjRfEspKMMNtJJnALW26yF8qA5GGo4YRfUjINPKhNDf0FhnwYU5M08KRd - goEDfThTBl7wAZUG8gE46AIciAzPAuxwDrOVYAZHuKYDjvAGNxGFAm/+cMM3ZaCHE+iSAoxIg0AdgL0J - /OEFCM1BhUywSHkCAhq6lIkr6mGJfRIAFA0wyAwEylFWDIREJaJAV9iA0JLOMkvQOIQ8HSAIeZxRIsfQ - wRa+qQ8PsOAgx9gHRwXKgIEEQxCUoMQmmleHkiLUAeMsCAXAEc9rHqEOrERJCHiQhn0+wRiZckUgdirQ - LwXAFZsggFgJIImBqMGoCO0BqyS00nygwZ4fmUA3prBPT2BBAwmpRxu4qgeOuIISYyUAJZrSQ7S+QBkJ - cQU2ErHSP0RBmRJxhTIqsE9VaCKjzXEAV9OABWEFVqzxqodhcxDRLK0DCSvFATUqQoE8eOGbWpD+xU0h - 8obN6iBeE/gsAfCKtFsYthkRYUccmmrMI5w0ItLowT6ZAAzIGiQYlOCqKoxBEGnoFrMCOcYk0HqEfsD0 - Biv1aEQ0QMhfwsAUvI1IDzar1hZdtyAXMKwcnOWKIuTgmongTHkr6Qgh+IMi1FAFV2FwD6W+lyDscABa - J5FUQeHCmqhMhLN4UEkvBOIa3ZsAITYLCjsemCC4MCwGnHsZchDXAV4VlBHaoI8mJNMi0NgsI9L70Q8v - BBCGjUJHvHWEGLzhjNNcyCS42oYT5MfGA1GGYQFB44m8r352gcNmA+FcCiAZaTgwbDfqCI8pcNUNUuDQ - lbOrYKM6IKrgq8T+ZjPBKit/FrsGgYNhL/HSw5hgrzv1RIHF/GbbHGHB2gjfBJKwWRFIZ8wDGYZh81Ba - /6xjs0yAs4f73Jwc5Ph7FHgBkXkRLkQPxATbNSoSmhyfC2w2DySuMaUTywDDviHIPYEHAbhKgGsQx9MD - gUeZS8oINDPHFb3YbChA5ebAShohbzAsDWB9E2XgmaOT+O+tVx2efCyYYOZxBRM2u4bG4JogvURrKc1D - gWcLlA+NPjK1rxWJBTMbJhqYNUdVIY89fbtboT7qu1WS3J3WgLX3Jkh8S3rJ+GhgFIxgxBzOWOyxHjs8 - 4QAEIH5sPChbpOFifXh4pJHuQFY34B7viHUrP9vxkINkAoAd62BNfpMJCCKwlWD5TVzhD6BSohIElHlM - XFEiZ5Qo1XYJCAAh+QQABQAAACwAAAAAZABkAIf2hOT+/v7+/P7y4PD+RuT+Ftz+Btr+lvD8hOr8INzy - 1O78ovD4+Pj+Zuj+Jt7+CNr+uPL8qu78bub6+vr6aOT6PN76svD4lur6+Pr4hOb4cOT4auT4vPD2nuj8 - 9vr2yvDy8vL2lOj59fj47vb09PT08PT05vL01vD0uOz0qOj+Ftr65fb08vTy7PL8zPT27vT07vT02vDy - 8PL+Vub+GNz8pu78pO78mu78kOz8TOL+dur+Lt7+Etr6nu76guj6WOL6lez4iuj4eOT4kOr0wuz0vOzy - 2u78iOz8huz8fOr6lur+buj6kOr2qur06PL8duj8buj6euj4iOj42PT4kuj23vL2nOj8dOb6cub6bOb+ - WOT+SuT6auT8Ot76UuL6ROD6zPP8NN78Mt78Jtz8JNz+ENr+Dtr+DNr+Ctr02PD20PD+NuD4zvL2zPD6 - wPL4xvD8uPL+PeH4wPD+SOL6uPD4vvD+pvL8tfH6tvD8r/D8pvD+pvD8ou78luz8juz8iOr+nPD8pPD8 - n+78nO7+fur+duj8lO76re76ien6XuT4jOj4eub8gur8euj8cuj6gOj6dOb6VuL6TOD8iuz+huz8fOj8 - gOj6fub6muz+je3+mu78ZuX6mOz2tOz0yOz4ouz4mOr2tOr8QuD8ON78LN7+X+b+VOT4qOz4oOr6nOz6 - nuz8V+T8U+P4quz8UOL+UuT4rOz6sO74sO7+TuT+TOT4su74tO72vO74vu7+uPT+/Pz+x/X8QOD2xO76 - qe76pe7++vz0yu7+2vj00u76YOL6YuT6ZuT8ROD83/f4juj8RuL8SOL+JN78SuL+Itz+4vr+INz+Htz+ - HN7+HNz+Gtz6eub04/H87Pn++Pz62vX58fj8gOr81vb+NOD45fX8wfP+RuL+rvH8lu7+mO7+1Pj8nez+ - tvT8+vv8+Pz69vr39fb29Pb66vj8zvb28Pb06vT43PT24vP60fT21vL40/P6yPL4yvD4w/D6u/H8tvL8 - svD8q/D+pPD+vfT+0fcAAAAI/gADCBxIsKDBgwgTDtR1bsI5XQojSpxIsaLFgQLI9evH7dzFjyBDhiSX - q2QuciJTqlxJ0GTJfixjyqwowGXJmThzGjxnM5fOnwnPqWPA4CJPm0CTEmQwpEsXKkUrHnX5UVhJYRCV - RtSFwIBXAxmyTpxq8qI/O2jtoNSq8ByNrwbKwJPa0+K1tGjDiWW70wxcAz8mUCR7k6KuXXjR7uVLUBer - vwY4DK5LcUViO7sYJ1Rz5m8YEWMpS5xw57IHzQgnaIDMKTTSidwu+0Od0AS1v9RGSCTsU6KHcInDoaON - 8FwIyFg8thWt0MVlYcQTlgjz9wy9iLwlsrsMQUD0hCgg/ueIWpz5wXP9Ll/7nlBdJMi1lr9OiOxyZvYJ - FfiFSwp0+fnnmWMafgkxsAhkiiw2UHYJxZbYbAQm5EQCfxXgzX9UIfRbcMOxpeBEunQAGQXKFcSgQYdd - hgxfEwwl2EUkVPDXA/acZ95A2yUGE1sYIOKANInMUyJFREAmCnkL3hjAORCo99E15hwAiAsVcVLAlQVI - E4VuFTFADGSn7KRkfYndV5EH3xygpprcTDTBHFhi6YAq/k1kBA9/kcFlkgAKhAFweIVzGkUTyAPImmvq - tRuccWIpihwvRjQBAJD5sNeJA7VzWZtj1YcooopKNEijjW4Cz4cFteDAXzzMxWeG/gNpc5k53mkHwaef - crobE9GQimU0COyJkC4pQJZIpJgGgFhiK0Ykwi6H4qqmJi6gepAuMRTjK5Y7nBLpQSR8Adk9GDF3l47Y - cbOAtGtCsN5HDBQhyrZXNmPPtwV5gsZfXZBn044B1OTksCuEw66a4aygUglWOEAvDVl48yEDG0AWy0Ak - mbRWAM9cRiVC2sBx8AELdMTSOSYIIQ29ziSjzUHWvAWXpQJltBE3tQZATnDYHCSCC9Gyu8ugMjEwzA/0 - FhBGLfieM8RfhzTG0F4d4wWdidnwM7I57+qkTiddJO2FPEOmM8dXzWAwUXpo9ZNzALqwk8fIdjSblC4l - UMEM/r3UPCHxQMDokYQe6VAkADL+IPO2NmkeDIg/1uY0wQAa0ECvA5wULpMA7QSN6zjfEK0ZA8HkkDQr - mq8kgMEHh9N1dOo0IQa9vsQkzMH8IBM5Y7q0EAQ0vvoQ0y7STjlkhBPEQAGptbN0+6f9iB7hUr0cg+Uq - wMQkQJQIvz79QRjA4ccd2W8ujAt2f6/++uyHdA5R8Mcv//z0w3+8ThPUr3/9E4h1jjuX6IYDBkjAAhrw - gAfcgSWkJxNgQCATlIigBCdIwQpWMBMQGA4DLoHADnoQgYzYXUggYMESmtCCEAgAAwT4wRZ6sBv3YwkE - T0hDE2ZCFyt0oQ4P2A0RfkQX/jOsoRAnmIlznIMRO0ziABHwExIO8YmUgANEPMAIFirxhQjomU7Q8UAo - 0jATcFDbQPJHAhCY8YxoTKMaQUACEjDAhyphiBHnSMc62vGOcGyfHvf4vXPAoQ9wiKFIBOCPkwhSfecA - QynWwMgGdGglwNCEDiZpiGwckkAraAQjN7mGO8TEBZMMpQ70wI488kUbfYgDJzdpiJjcQZShTAIc6oSf - c+AhB6vkJBw+CUtRIgEM+ELNOeSxiVxycglvS8k5btBLUfYBGZcEygp8YMxNEsAXQzLleb5BiGaGMgIj - 0GZKRNADVVYzDkF4B0HC1wcIlG83uwjHLt7mgTx4c5KE/nADLX9yDje8opqMlMAJvoUBRxDgoDpI5nky - 0YCG4uB4K2DmPTMhj2DGRBdTkABA12CKWyBJIIc4qEi/MUYGDOWNA3FBQ1fqhp1w4wj31MEgVhDNj4wA - ERsVBSrccRB2vEKkB9XDQEQwiFKUYhBEy8NKG6oDYQ0EA9yMaR5exhIR+IIAG/VBPGKoCxwA9aD30QUg - ZkDWGQAiU0tt6C8EeY19xDSfHzVKPbSw0U2oIa4DmcIcvioB5eiiFGWdQSmycg4EpLUBrroWMgwRUz9Y - 8ofIuMJGZ9EJdbRFB18lwHUEoovAkjVS2TisH/C6IBdQIqYLYIdFMJBKgMbhAi+Q/ogbMvsHZHl2BuTR - xQ0OywbfwCEJ90wCwCT1iY1GIR4WLYgISvHVWcSDIBO4LZLYsYS0JmGfCLmGDWJqJoUwIBHVTMQHSGsQ - G2T2E0OKrmctSxB9HBYPPtRFNnDgzQO4aZGrnAMs2DuRFcziq6XgKXRvy1+BpEMHaV2CU9viAkb00hA+ - 9AUn48CEd+TxHEfIbB0Mot7AFlgg9TisIJKLEBG8UpTdbYsgthAHHcCDxAiRR2avENcOl/XDS5rEYbPx - EXYsIAmUcENNGxOSCSzhq3OYx0FsTFYcBwAZhz0CeRPCkP7xhQ6ZZYJFmTwDJweAD4d9Ax8DoI0ZfNUU - TkgN/oGzW92l6oCqeixHZlshSC57OQBwOGwshkycFdDiq5tYR0LsnBAMJCHBF2LfETMr5kGvOSHtOCwn - YBwdMGQ2CVMmdFBwcNjNfg8DDfjqFqogqUcnZAWHRcCUaROLzCqB0ppWSA0OK4fvjcDMQF1FbEu9Xolo - wxFpbWqEdAGEzFpAhLFWyDcO6wtx5iQbW/hqA+484F7vhhGHVRh7dJGEzLaBUKaOCDcOKw78MCDaQFU1 - uK0tEV2II8HmxvVBnVuRZEeEum7GzwTMK9IaWMTeEbHAUndp7lhAYQl34LNAAN4WfBzhCEKe3kM+wvC2 - TIDSY164dDP+Ey5jnOMgOQdgIss6WJDn5ByDCKwgTJ4TXYjgBkYtBwNZHkcGtNGNH09KQAAAIfkEAAUA - AAAsAAAAAGQAZACH+GTi/v7+/vz+7u7u/kDi/iDe/gDY/pDu/JTs/Grm/Cjc9KLo/Jbu9vb2/mDm/jDg - /gLY/qjx/JLs/GTk+vr6+mjk+lzi+kzg+qLu+JDo+Pj4/hDa+HTk+Gji+Kzu+Ijm/Pj6+Pb49pjo/Mj0 - 9PL09Mru8O7w9MDs9Lzs+fH49tjx8/Dy8uzy8ujw8uDw8tzu8PDw+tf1/lDk/i7g/JDs/Ibq/Ezi/mfn - /jjg/g7a+pTq+mzm+mTk+lTi+Yrq/hLa+H7m+Izo9qzq9OXy9MTs/iLc/Hbo+ojq9qDq/iDc/HDo/Gzm - +oTo+Jbo+Ijo+Ibo/GTm/GDm/k7k/kLi+nDk+mrk+l7k/EDg+l7i9Nbu/Drg+lLg/iLe/C7e/Cze/h7c - /hrc/hjc/hbc/hTc/hLc/gza/gra/gja+rzy9sjv9NLu9Mzu/jzi/LXx+Lfu+rDw+LDu/KLu+qzu+K7u - +qju/pbu+qTu/KDu/Jzu/nDq+prs+pLq/Gbm/Gjm/I7r/H7q/HTo/G7o/njp/Irr/oDs/Ijs+nvn+IDm - +mLi/ofs/Hrq/Hro/o7s+JTq9q7s+obo+ojo/HLo+m7m+Jzq+pzs+KLs+qPs/Fnj/ELg/Dzg/Dre/lbl - /kzk+qjs+KTs+Krs/rjz/FDj/E7i9rbs/kri/kjk/kji/kbi/kTi/Pz8/vr+/vr8/uL6+pTs/jDe/N33 - +o7q/ize+orq/ire/ije/ibe/r70/iTe/HTm99/z/sH0/sj2/ETg/Ov6+un2/Ejg+sLy/vj+9uTy/sr2 - /Eji/Eri/tT4+uP2/Lzy/qDw/IDq+sny/rDy/Pr7+vb5/Pj8/ND2+vT6+Nj08/Hz8u7w+t329Ozy9Nrw - +sDy987x/Lny9sDu+rnw+LLu/KLw+q7u+qru/pzu/KDw/J7u/rz0/vz8/uT6/OT4+N/1/sX2/PP6+u34 - +Ob2/tr4+uX4/MHz/qLw+tDz+L/w+LTu/q7y/M31/nDo/KXu+OT0/IPq/rPz/Nb2/K3w9u319N/wAAAA - CP4AAwgcSLCgwYMIEwrUMA3GABgkKCicSLGixYsYBabgUaZMBWsSM4ocSTJjqgkGUhrYEbKky5cwKZhR - aeBHS5g4c1psQNMABA06gwpFuKLnz6FIFTZroOFmRWpGGySdWpCCjiuYmgC9CJUmBKkY29nS9SoV1Yqp - jmxYu8GHWYtdVX7FuI+ZXWbtzlJsVoTthjDSuEa9qE7fXWag3upF2EyM3w1WnCaMm3Iu2l2HmelbrDDV - pccb5Fk0Mbiiu8zMdnFWmG3M40zOKpL2CnZiM1uZ9albnZACB9CUZJee+Aq1Md4Kh3B5zMUXxdlyayd0 - BiozqFXIEzYTAdpQs4nQK/5LRwgNNavsCkloeSwmBvjhCNehtoV+IgrQPSQTDJ9yfMFU6aDWS30KNWAB - aG4oxJ8B/hF0DmrDEDhRFmE89kAICS3YoEDNkJPbbhL2dghoGShWkIYJtWNciBO1oMBjX7CDEIoHRWPY - YddxZuJFqSwAmiTfGUSjQfWYxxkFTAWJUQO8PEZGNgcNSVAvqOlyZBAP1DKBNDtSRARoxWxFUFE9+deM - LgKK1As5yUQAzUWUFCBnAbcw4dxFGgAAmgcGkUmTfw9m9iZG0YyQzKGH7lNRM1LMOecDlcRm0QtgPOZF - CgX5qdJ4IFR3mD7PXETBPhEgiqg+XRqUSiiOOkoKMP5KKkTBB6A5YaKm/RVUV2Z5oXUMM6aaimpFd7Ta - agLopFoQC108BgY6BE3TkwFiBlBYZuQIUNE6tgQbrKIVCSABLcbOSYssmHYmBGgTtMRTTzcNg5o5FDlT - DzzeIgoPNMoelMo1FZQ7Jw4e6DdQAxeABsxAGkzbEpWZpWNbDKXme6guIGakwQm/CCxnKMvEWlAJrvl1 - RUjN5EBTDkrillnGqrqjj8WH6nPOSyQg8YDHBVCBT6oaUAFaNwMlQNMOQZqD2qAHpaALzW22oy1MqQwB - xC0ez6JDugUNUcBjR7wVTQI55LBDCm8ZY12oBjkDDb4WwzMMCEJRoIYVPLMxj/5Tzejw2BsDIdnQNA28 - pfRh5xXUzCv0QE3OgEk1MMoVPF8Sj4kgSMFWKHRTFKBd6UwtUCq9gAI1M4lTlcoKTcTiMReG+KLYKhEo - E0HnFbFiTOoCRZMO1BEY0+9QzbhgBBceP0CJpDkJYEzFFqcD82oarNFD5cy/JIDpNIMCOYENOKKFx/zk - 1A7N9JTFYgCpWBPELOXWkNMw+e6L3foDNXPNDsaWj9P5wcIY/g6igTTYYE4OYBtMtneq7w3wIBTQBgJA - ITqcCIAV0ODdAzfIwQ5epBkUCKEIR0jCEpowhCJDCghPyEITNkMxzegHE9jwgBra8IY4zGEOcVCDaCRF - AP62qMMBhkjEIhrxiEesgy1UEQAKMEGHUIyiDmswvJLYAolYzCIS6UMBGkrxi1FkQwpxIkQtmjGLdUhF - F8HIxhyyASmpKOMZ51jENDajBm3MYw0LkZQr0vGPB7CFWUBQCC/qMYyFYCJSnhFEQJpRibhrYgNIQMlK - WvKSmKwkU6qIk1R48pOgDKUoR+lJD5rylKgM3DvwgIYxlsR5ttgHJ1nUjHhAgQC4zEMkXSKAZBDil3Wo - hivXdwxl4PKYBABFTqDxy2YSIgKy22AK9HAKZB4zHDkBhTObmQg0YGh9zeDGJqyJTGQsc5vOZEQ8DMaZ - ZsQgAeREphEq6JJmwAOdzv7EwzGGSRVf1CCex5SCB2I1y86MIBH4bOYb1sEbZ9iBFAAlwBRg0Q+CgEAb - eECGAm0zAmYMo4LqaENCf5kIYHyTKs0AxiUiSgBAqOAmIFCEDGb6B3oeRAB1yINO60BPd8RhpIQ4QAzY - +ZJUSCMSLHXANqolkDfM9KkSEwgFNMAUCiimHjrN6jtUtY8DADUO7CjoRdbhhylElBSeaNA6NvHUmdJj - IM6Iww1u4A0FtiGrOlUE1wjSjHcgdKRt2KtLnCEHKbD0CEMYYyoQ0NaZjmAgcXCAZB0Aj4FAA686BYcr - 1cEPoCZiBEzNSDOW4QCWLiEb7KxGY2VgBMXcYLIOuP7BQFIxCMzmAVoJOQcegFqHGPATIalAxyJYugk3 - bIhDMm1sYEYHW8kqqRq2RQBRUwENRgAVmhjRADUjWopJVHQiwFitH1rSjOY6oCWpSIZtoTQRECDjrwnd - 6qLowFJl5OK3AYjGDRq7CWHw1bzV6oUgMJuIkypkHREA6mMpQoEbABQK2QgtQuiwWjqYiALmHc9dMcuN - gr6CAQnFJoP5QE4ZwOG4BvEFW9t6AxJUJcMFcQYhMCuIO6FlBINAJx4sIgdkokIH/RBrKvywWtG8uLn+ - WYZt74FfgkRDm86sh0VSgQEZlOIP6GgyQWKwWkWEFsNIVtUBbFsNkfgiAolgxP47xMo+kjQDEKtVAQRh - bJBX2JYGEt7LCzmDhtVKd85hPsg9bLsMVKbAAY11wHcNAmbYbmgdA8YrIQS7wTisFg7KavRkj4sG27aB - zbw5xoqfmoDjalqyxwVBIjALCBlxMBU1WG2he0Nn8tj2DkStTzxWm488S7XW/mKAbd3zQAoEgr+5mMip - HYDiALjDtoPwNXrasFpK5HrZzQ4AP2y7MPytA9FtVTSDgY0QdSgCs3+gNHpSoYfVuoGT2K4IMGzLD1Aj - pRqjnqkSst1EcjNm1Zg9RohSkY/VsnfcgaZIDGy7YwlpIN8yGESuA+dv4OKBxiHSALhnugl8iKriCPEF - ullDRAEKP9V/Fon3RbSBV3NmvA1GEIQ2bCorkAMXG0MEhr2TsueMqJxHIEzlXgAsdBWad+JFF0kzXjvZ - G+w86UqJ7GTjAHWhpCIEd5hrHLJXdapRlQRJClFAAAAh+QQABQAAACwAAAAAZABkAIf4buT+/v7+/P7y - 7PL+SuT+Gtz+Ctr+mvD8qO78iur8MN7u7u78wPT8pPD29vb+auj+Kt7+DNr+qvL8pu78buj8+vz68vj6 - cub6ZOT6SuD6lOr8+vr4hOb4eub4wvD4uvD4kur8+Pz8+Pr49vj2nOj87Pn0zvDw8PD0xu70vuz49Pj4 - 8Pb09PTz8fL27PXy7vD+GNr+Wub+HNz8pO78ou78oO78nu78lu78WOT6wvL+cOj+L9/+FNz8hOr6fuj6 - bub6YOT6muz4hOj4qOz2sOr06vL0zO78juz8jOz8iuz6luz43fT4nOr8jOr8eOr6lur4mur2pur8dej8 - cuj6dub+Vub+TOT81Pb6dOb22vL8SuL6buT6bOT03vD8QuL6UuL8POD8NOD+Ftr40vL21PL01PD8zfX+ - OuL2zvL4xvD8xvT2yPD8xPT4xPD8wvT+QuH7tvD+RuT7rPD8qPD+pvD8pvD+n/D8nO78kOz+eur6jOn6 - cOb6YuT4juj6euj6ou38fOr8euj6huj+f+v8gOj+iu76gOj8fur8gOr8gur+kO3+mu78bOb8VOT8SOL8 - QuD4ru72wu72suz02O74oOz+Yub+VuT8YuT8XOT6p+74pOr6qu7+VOT+sfL+Uub+UuT8UeL6rO7+UOT+ - uvT6sO7+TuT4su72uu74tO74tu74uO74vO7+vPT8/Pz+0Pf8iOr4kuj64vb8ROD++Pz+KN7+Jtz+JN7+ - It7+IN7+INz+Ht7+Htz6zvL8VuT+3fj8hur6fOb6oOz8WuL8lOz83Pb+OuD+OOD45PX+RuL+iuz+wvT8 - luz59fn89vz48vj29Pb08fT28fby7vL8xPL06/T44PX81/f23PL05PD41/T80fb4zPL8yfT8uvL7sPD+ - pPD+uPT+v/T+/Pz+2Pj66fj++v761/X+4/n84fj46/b+yPb04vL6svD8rvL89Pr+NuD+iOz65vb++P76 - 0vT67fj62/b6xvL25vL8vPL8sPL6yvL24vT6vvL6yfT8vvMAAAAI/gADCBxIsKDBgwgTChzB4sSCEyw2 - KJxIsaLFixgFWuAiBgYAaBIzihxJMmMrRgZSGrjArKTLlzAFbuCh0oCMljFz6qz4rKaBCCN2Ch1aEJpP - oESTIqzgYETIiy2OOlBKdaCIIFq0QHlaMWrNCFMxnlOn7lyrqhRb6SnAtoCesxa9qgSL0deou6N8oZ1Y - AULbAreWQJV60R0rvKPC7VVYAdffAhgqxCVs0RXiUawWJ2x16XEBDxZfUKZY4vIoV5oTktH1WBbOiaK/ - huWr5jKrZqmXdvAcrGLsubMVojM9LndCan7/QkhH8XdKuhNDhLscrpzxpSQ8+5Cs0PnP4Ait/pk+dz0h - tEePdWWDPRqhBdPqyitM4RkTV4PeoSNsZcZ0CfkJOYCBZx90155BpV2GGoAJTeLYX2CokFB+4BFUgTK2 - zcJgQhsI4dkTcOF3IEF2XabXhgkVocBjtMSDEIUIGXaZMgIsFiJGrUThGRbcFQTjQVeMt9gGI4zQ40Us - ZPCYDGMc9GNBCSIW314igHDGDoxkc2NFKHj2yX0ByPVcha2oY5o7IpWgjASdFGfRHxDECcEOgjB30Qhc - eAaJQWJ+Z9A5pl2RUTNmSGCooW7yZYmccp6RiQgXdWHLY2FYUFCf+gl0IXUhXFQBMZ0cemhmaeHAKKOg - pHFkQhX04dlb/gRhCh4xpp2YVjyjiCoqK1siNMOpp/5QTa8GDWDMY7ZUQ5BRXwU1kIyIsbGqe2zoqisx - FgmgxA7AyrnDEZYq1AoRnjHSYzRHvRaAZZf9N5EI2lirqzU4XvNDt3K+AQmYBDnwhWdpDKTCUU9FideC - rIIq76HqoCnSCJGAgm+cOPAy7UBGyPCYFpAGUAFNKhXQo5mXOXxQK+TkurAEo7hbEjSanDExBFTEQywz - VHiWykAU1HQBd4BeRq976qzMpi81wtRKERxwi28YSoRbEDbJtXUEXO780NEFK8BVIl7hXCzCFUZL4Eqn - OzFTBgYzI6PKfRUE8Rg7A23gAAstsOAA/lxB40VeQRWgE+rKypg8lAOnaDEzEFoSJEIjbeFwsUHsnlZQ - KyWEYzQ4f1PVCjRMvDPxDoSQE2I57fwiR8cVnTNO5wK5U+jKbU5OVAXrADOzMX+wHpMA1gy+sBm4GTeC - CZgs7rtLAmi+cjgul+eAJF5MTEpOvqwMDjooBtAKNSA4feoRObkibztX2F5eBV1gAez1MWWva8PdHzTC - Go3IWYn6GDU/avT1M4gI8HGDUSRNJ+e4AuwCyMAGOtBTG2CGBCdIwQpa8IIb4F9MKhDBC3oQg0eqQDQS - EIczmPCEKEyhClX4hgQUbygCYIMdDkDDGtrwhjjEoR2kFYANJGCF/kAM4gqRQCyYsCGHSExiDtkQAGaU - UIhQDGIcNDiSGSrxikm0Qys28MQoehGFcUiKFbFIRhtqsQJH+KIaTaiIpByxjHA8ABvOEoIjdHGNQIyD - IqxzOxnG8Yo79J3d7saCQhrykIhMpAOaUsSdtOKRkIykJCdJyUc+8JKYzGTdckADflDxIgIYBxvG8UkA - VYAXDyCAKp1QyokIgA6FiKUdYtHK3MTjF6rMJQFIBRNtxPKXhcgHPRpZHgvQQBS6zKUdchIOYP5SETlQ - lynxgYlk6pIBObmCM4F5gCtIMzcVMMcUrKlLQBzwJRWQwDaB2QBaXoccRyBnLqvAjiMRsyIV/jCDItb5 - SzisIDXMyAQn5EkAK2jABQQJAT9o4I9P5hMcZjinO7rBz1gqQg3fHEoF1FAJghLAD1ngSgUQEYOS9uCc - CBHAAfLAUjuglBxzqGghDmAOfsWkFUvIg0cr4QFnEQQOJQ3qlHo4gqZsIETaYKlS1WCQVljjADKVgOmE - Qo9hWIGgnBhCNA5SgkoEtaTtsAoCdKADCaAtAN1QKkt78E+DbHSfFe2G1F7CDG9UwaNHuMfFWhGEr5bU - DAOZwwMG+wAJDOQKamWpNybnDnDIVBFmyKin9JFKgkqBDJINQD38GgNA9EgHhH2ADgZSgRskNg+xUMg5 - GiBTG9Sjlt6L/gUhdrqKClkoEZxdj0BaEdrB9sgXp72DTXd7hRvItB0AnMgGjklQUVACoROxB2c18JQK - 9PYBr2nFHE47D4qEwA1w5ScT8bkJj75iHxpkBgX8Wol7WOi6Pg1ACQaRWCRkliAl6IRMAUsR9cqTAmi4 - L0HkwNlQ3GgD1wVPWhPLj3sOBB124Oc3KrIBClgzBqiwLULI4dWvUmCrBEFwb8ETgkIkdhB2wqcZjOvM - BljEG7osRRBc4OCBtOIGnA1YQUQc2gqZ4bRyaGUz/OFMbVikAgiIgSd6UI1aWoOzPfgmjwlboQqsNLHK - ygg52qGIG6ihxjYmSQUAwdksHGTKg7Vt/ixOe4PhMqYCYIYJAzgbBH6h+QEabsdpt5FJCzyAvdA1yJ01 - bAH6qrUQAmZQkv1qiiIOOiEMOG034mzLDgd1CvHdcYITEgJFnJgcDmzFETjLZw5tOiGITWwD3FyeeXA2 - Afd99GZscNp6MLACUuBslk094onE47SKSHRqgOpXGrBa1gphx2ntUT8/+/UBbVUIshPijh4kFh5zlU8r - asDZDzh42glRw2nhQOmkoIOzTsg0QsC9FE+rdRAuAlArkMDZJlH41BSpx2ldDKANcBYPrK4bvifSigac - mEEI/moljnERdidkvmqFB8IJHFRvYMThCcGHWrGJcDgcYhDdQKlyQwdOkY3ewMuwTQqcRYLxzXBQkyW/ - rrBhLhLr9jbgNK85aAmrg3LnvOQICO0cfi6UVqhgAmSdw1mJflNmLLIpKd9JQAAAIfkEAAUAAAAsAAAA - AGQAZACH9nrk/v7+/vz+7u7u/kTi/iTe/gTa/pTu/JTu/FDi/B7c8srs/Jru+Pj4/mbm/jTg/gba/qTw - /JLs+obq+vr6+mDi+kTg+jre+qDu+Iro+vj6+Gri+Fbg+LLu+ITm/Pj8/Mz19rbu8PDw9oTm/hTc+PH3 - 9u709PT09N7w9Nbw9MDu9LTq9Krq8u7w8uLw8tzw9PL09PD09O/y/lTm/jLg/Hbo/Eji/nTq/jrg/hLa - /Jrs+prs+mzm+lLi+HTk+Jjq9rLs9qDo/hvc9Nrw9NTw9MLs8ujy/Jbs+pLq+tf1/mTo+pDq+o7q+ozq - +JDq9qrq9qDq9OTy/Gbm/iLc/Fzk+mrm9o7m/kji/Fjk+m7k99by/FLi/DTe+mLi/ibe+lDg+kjg/Cjc - /CTc/CDc/hDa/g7a/gza/gra/gja9s3w+rrx9M7u/Lvy9sfu/kLi9r7u+rLw+Lju/K3w+qru/Kjv/Kbu - +qbu/qLw/p7w/J7u/pju/Jzu/nvq/mvo/nLq/Izr/HTm/GHl/Frk/ITq/oTs+n3n/Drg/Czc+nbm+lTi - +H/m+nLk/Hvo+njo+KTq9rrs+JLo/ovs+p7s+pTs/pLu+nHm/G/n+JTq/Gjm+pjs/lvm/lrk/F7l+qDs - +qTs/qvx/ljk+Kbs/DLe+Kjs/rT0+LDs/E3i/k7k/kzk/kzi/D7e/rfz/Pz8/EDg/vr8/sv2/Ebi/Dbe - /jDe/GTm/OL4/tr4/izg/ize+lrk/ire/ije/uL6+J/q/HTo+svz+Oj2/PH6+pzs/vj8/NX2/h7e+OL2 - /MT0/Pr8/NH2+vP69vb28vDy9O708uzy+t729Ory9+D098/y+sHy/MDy+MDw+Lrw+rTw+Ljw/LLw+qzu - /Krw/KTw/qDw/KDu/pzw/rTy/sH0/vz8/tH2/Or6/t/4/ub6+tD0+en3/Pb6/Nv3+eT3/Mn0+q7u+rDu - +rLu+r7x/rrz+sby/sb1+Mbw+rbw/LHy+MTy+rjw9vT2/j7i+pTq99vy/oTq/mTm/On4AAAACP4AAwgc - SLCgwYMIEwpscELEABEnKCicSLGixYsYBZaoNGWKDxMSM4ocSTIjq14kUpJo1KCky5cwBVIgppKEl5Yx - c+qsWKJmSpw7gwodCMMnCaBDkxZk1aBByIsyjCK1SKEBK6UYNUhKsIXX04pRfU6dSEHCg1hIlGGtyEpC - gbcFkFy1GLbm2IQUChnYa8CD1bUKWT2AW8CWM6hSLxIxw9eAEGVzAR9klYtwAR5fFdZVefegsi+NDZTp - LDkAK0yWC8Sz2CJxxRWhDSTKXJqgFi+WU5Em2Fos2EOhz2ipjVdRak8Ve9ulSMFKbES0iQ80MZjwg18U - lXOm6IJEaCHYpf4jZAUl9YTICLX/nNhgQ+xg4hXCSGVZV5KJ6o9OXAAhNJfd8amQWiDRDZTfbidYEBs1 - 8bFXRWpqKHRgQqywEJsgBTY40BCVEUYAaRMi1IwYoZVxmIYKUZBBajugx5trBlHgQWyKuIiiQc/gYBkN - 56QHY0EvkBHaFCXcOBErT6TGiI0BhFhQAxXE5khpVTklkjI9WOZFNAc5SVARsakCYE4UZEIADoDsw6RC - baSGBW2brVfQCRfENo9IwLxCCjy1XGTHA4A+gMMfPV7UwCKpdWBQnPoRxEoQsXWR4UEfDEPKpZeSUxEF - nAQaKAFzjDkQCrZYlk+RBDE6lREKhJZDMf4XsUIOPJhiKg9bnXoaKBa+TDoQBZCkJleqPzYAQGwZrLmU - P+DUWqsxFtGhq6410FIRM61YZgusA8XwYwqMNRYGqhPl6ayzmlYkgA44TBsoDpOQOx4QqVXyVFG+LcRB - bKVQVOm5ta7SJ0bQ1OBuoFfAMakyVKTmy0ANGPXUI7HZsBsrtNAK8KWvoDNSA/NgcTCggZiT4Rq4EZaA - BjLRpFIBITXARWhocJnQOM1uTAo447x0wigEjPxAIeEZ1EAhqVUz0A01NRLSHLFlUSA6IOi85y4CxMSK - CRm0e3A+wSRzUBTVwSXBXMnU0FENJczFR2gkFE0QBbWsYvUwHwTVQP4KPAh9SjWZsSKJZfT8ytAyJ/wV - gDahTWIQxjlv/AowSjXwRgJCY5IEehpoAhcneU/0ASx8WVwQMPJYzbNkMPCSj9ATFCqQK/VEUg/LFWmA - QSOe4C4QOshYDQ85WVMZxQRCu2GH7yRlRo7dOosTunQNRDNL5sy/lLrO8lCOojIhoDKyNTntojM45Rg5 - EDM/vD6tBDlZeq7AxasvEwqMTEt+TOY7K739B2lAGnL1gD5M7yUC2B4p5NEzAOJlGnsAR/1yUo5aNNCB - GMygBjNCgSo15YMgDKEIRdhBwHTwhChMoQpXOLcSLOEUBIihDGdIwxrW8BQS8NhQBPCKT0Tgh/5ADKIQ - hzjET7wiaxRYgg2XyEQbnm0oryCiFKdIxHUEoAEwbKIWmXgKX5HEh1QM4xQ/EQAKZHGLaJzhKZICRjG6 - MYifYEVZ0kjHGB4gKVF8ox4j8AqBfOAAZ6zjEk9xAFck5Rg93GMYjfiVqpzgkZCMpCQnCUllKG4trMik - JjfJyU56coOgDKUo52aMOhjDkDoRQC3WQbxRsmIYN5iBLAlxQJcIoB4HyOUnaKEsI53jD7IM5gzAEb9c - GvMAq2gbBpNRh00IM5gRyIkxjmlMPawjexqigDQc8ExhQismw6DmMbmRBC9ihRVJ4EM3hUmICbqEFbgU - pzE/oY5eKuUcEv5YZzCVQI9j7IQVyPCGPI3JBu+VRgNy0IQ+ZbkDeX3AGHQ4pUWOIQ54iGOC6ADHQHPp - DRBgUygUWEcfFjqDQeyjkZFQgkoj4c7JRIAQMI2Ai8YRz4FGwBnmHAkrnDEIkvYhHmNRg0qH2keZfJAC - kRkGTJcKgsel4w4bPUA9zmFPkZRAByTVBDvwcRBg9GGoKiXFQBDKBz7IYXrTWCpMIyGvgbgCBHqI6jTE - FhMNWEMJJJ3EL9bUDbCqFBkD+cQNBnuDegxEqWolBD3WBAw2RNUbJnunOfxAUj5oIUPO8KsSBhEZPhD2 - BnwYCCu8kVhCqEMh/vhEVG9a1cepA5gLdf4ANS6WUr/eRyCs+Oxgn0KL0kZgUqyoBR6iugrZbaoOCtXn - JuxgAoqsQ7MMeEpudfsVOZT2tgr5wDriOlBrUqUdJGUCNLyIjhv4tQ9yo4Bub4AUYEQisQcQFTBWEVXA - MqcG+qxBNEQVADhoFg7oUa9up5LWxH6zIrRQrTzJeN9uKiEOarGIP74KVj60VcCfnYoGKJFYtl5EAMMY - LjUZTBFrCBMUGDBBa3HLAM2upiAYJuxYEKvWeuT0d9M85jAsIgA5KEETfyjGjQWSDs3+YSwxHuxYWMGN - 0lorI+NYhR7wAIIV47Z5hNDsPg6SZPYepLeJxQN/l4LU0khDsxiITv6XO/ON0ppDlMkwL1jRi5A1I8S9 - iaUEXTfoY7/eY012Rog8SvsOK0vnHBQeKh8izOX1kuaPHTYuAFlxAM3arM6OVgiNlyqHIZdmGJqVwG4C - PZ6XJvZEAKQAH/zqAG7hJdOoLa03PL0WNmjWDr4idULYUNqH2Q8YfvCrH9ra6AFTBB3vVWsk9nyjOmj2 - HZuC9URAUFo2qI8WDvDrIESla7wwoLT+MJIENDucaBu7IukoLYkbRIFsg/UIOe22Qj7R4RtRINhDpTNV - pE2RceTZ3v4d6v72fW6LgEOtB84mrwkxjZamiN8UYcU68EBlQ2OF1mWEeMRLOEqyaLzjMekyxiRBfiTP - EpYPFid5xOXwWcOq/J8NkENZ5fDRl5eEKQ2wpJVQFBAAIfkEAAUAAAAsAAAAAGQAZACH9ojm/v7+/vz+ - 8PDw/kzk/iDe/gza/pzw/KDu/Ebg/Cbc9Kzq/Lz0/Kbw+Pb4/mzo/jzi/g7a/qzy/I7s+pbq/Pr8+uf3 - +lzi+kLg+I7o+H7k+HDk+Gbi+Mby+Lzw/Pj8/Pj68vLy9qTq9pLm/Pb8/PL6+PT49PT09ODw9NTw9MTu - +PL29PD09PDy8ury8uLw8tzw9t/z+OL09O708u7y/lzm/izg/G7m+oDo/nzs/kPi/hzc/hrc/Jzu/Jju - /JXs+qHt+nLm+lrk+KTs+Hrm9rbs9qLo9O7y9Mzu/h7c/Nj2/JDs+pzs+pbs+Jzq9qzs9Ozy/nLp+I7q - 9Oby/D7g/GDk+nDm/lDk/Fjk/E7i+mjk9OTy/Eji+rnw+k7g/Ezg/DTe/i7e/ize/ire/ije/ibe/iLe - /DDe/Cze9tDw/hTc/hLc/hDc+Nbz/hja/hba/hTa/hDa9Njw/Mz0+Mry/MT0+MLw/MTy/MDy/kzi/L70 - +L7w+7Pw/Kzw+qzw/qry/qTw/Krw/Kjw/p7w+o7q+nzo/Dze/oXs/oDq/Hvp/GTm/Fbk/Ezi+nbm+Ijo - +Ibo+lbi+oPo/ozu/Hbo/pLt/G7o/Jru/Jbu+LLu9rju9NDu/JLs+J7s+Jbo/pru/mPn/lbk+qbu+qDs - +pjs/Jjs/GLl+KLs/Dzg+qju/lTk+qru/FLi+q7u/rPy+rLu/rz0+MDu9r7u/ELg/r/0/Pz8/jPg9sTu - /uL59sru+s30/Gbm/Gjm/Grm+Krs/sn2/vj8+Pj4+n7o/vb8+tT0/Ob49vL0+vP4+Ob2/n7q/H/p+njm - /s72+77x+nrm+u74/PT89vX2+PL49PL09un0+OP2/N349Or0+rzw9tzw+Nv0/NH2+NDy/Mf09sjw/ML0 - +rbw+rDw/qrw/rj0/sP2/vz8/ur6+tL0/sz2+vn6+tz1/Ov69vD2+vT5+Oz2/tP3+sXz+rry9tjy/Lbw - /LDw/LTy/LDy/krk/kri+qTu/nrq9tjw/jzg/jrg/Ibr+nroAAAACP4AAwgcSLCgwYMIEwpEdyLEgBDQ - KiicSLGixYsYBUZrNGYMERYSM4ocSTIjrUk7Uu4Ihq6ky5cwBVYgo3JHmJYxc+qsaKLmjgI4dwodOrCY - T6BEkyKkBQxYUIssjgITWQEdLaUY0QHBgmXIU4pRaxaYehHdplNUKDjAarGJjbc2KGAMq3LsxQqRDOg1 - 4AjYVbYJK0CAa6MWtYt0U9q1mELNXgNmoP0FfLBCLcI2goQEK9UiNEiPDbxZSznhDcw2Olhs0blikdAG - hGwubTDeZcKpSE9kLZbsRBZgQqtpQzvwI9SoKvKu6zvwCNjNZhcvOG0wYQjtKC5X3BzhiyShzf5kn75U - BGpHkxFu/9ndILANsDmRV3giFeZa2Xa3ToiETWhDus13kC2oafFVQesthhA0X8Bmh4AKAWMFaswolGB7 - A9GyAGxVHAghQdjcBhcBASK4n0EzhBHaG+l8qBA6UqAmSkIXIoQOALBFkp6LBkEhC2b8WKDeiQTB4EZo - YzjD40RPoIbDjgLVaJADHMDWS2noOACMdBVBIwRqwxwkZUEqRBBaAhgOhQ4TBOiQSDZQToQLah0alBh7 - Bp2AQWgR0CFSCe7MMs4tF6ECwaEQ6LCEkhcBowxq39hJJC0iwKYFlwp9oMQsr3T6CqEUVaAIoogSwEqJ - CqEg4ls6GFPQnf4KCuSCAqHxcJhFFdwyjqeenlMRLbqQSuondGBqUAWdoNbEqyeiowFsGcR5kDq+8Mqr - rxX1Iaywidz6Gxf3eRsArE/J4dhjZ7hK0TPaWGstqBQJgIAO2yKqgw/RUFQEapNstsJRQQFzAWyYhFoN - p+52Ogu8FsVQSL2IXvGNsQI5UApquQzkwFGbxQJbFh4OJAAxuybcqTvCjIRON1VAfOguw1CcRhiYYYFT - BWXUZENIDuwT2hppKEStyZ36os5L0DxBgMsQRCLkQejggNo1A+VTUzIhsQKbZgiR4A7RrwyaEy3WEEIv - xDoAwc5BU1gH17ICGeNPR4Ws8NchoRVwTP5lBxM9SzUUk4ROPEEwvcge0tECBGZdDFSBAw2d4JdAfYQ2 - ikG0kAz2Ms8o5YAdWDB9QzrpgaAIXLqETFAFBOyVRYklLAO20ZQVMwQXTBPCqEz0UEIPCBaBEEohqDyl - KcIJDyoAbRVM4QjT9hT/knS6+q3EB/Oh0wYvoqsukuxEL1OCiw5kkorLkcZEDNHjlLOkQCwwcbawPuRU - TcILL/++TDHgsG36MFmftdyBvf0VBB3bGNWhohC4jIDvFecYnwFtVAcEzEJ/OilHNdw3wQ568IMWoQU6 - RkjCEprwhCgcobR2QouqpPCFJqxAemixgh+AggA4zKEOd8hDHoLiEv4FHIoAltEKCRjxiEhMohKV2Ipl - LA8dP+ihFKfYQx+s0CXLWKIWt7jEZQQAHTekohinCIorlqSIXEzjFlvxxTCO8Y06BEVS0KjGOiKxFbSg - hQ/gyEcceiIpWbSjICXgxQB8wAdu7KMUQeGJXyRliHQcpBabOJsKAAMamMykJjfJyUw6wCqUyaMoR0nK - UprSjCBMpSqXVAFu9KEODRTJLZZxCwyCkBbDSEQNdnmIWFpEAOI4gDDrQQxUQsgCm9ilMmtQB/sJ85kH - 0IMEDciOPnximcr8Q058Ac1nDmIO3itOBe7wAGwukxvO7OYz/5COcLKFFulAhDmXKQlbuqQCwf5U5zNb - YQFjDkUdPpinMh8AD3u+RADaAIQ+n+kNdZUGBHy4pkA/AYTdBaCVEuCGLwMggEC5w5YkqMMgFnoAQGjD - nTCpwByiINBd9iMGs0HHEh5AU0oY9Fh/kIROJSAddciDpAeQAOCSQgtqHKKlNYgCHQ7EDJo6tZAXRYdT - QCkQJej0qlDNUDX+AFRxOMOfFykBApD6CVeY4CAlmIRTaSqOgXyAD4c4BD02U4er6vQSDl1dQkk6CG6s - LSYg6EI5W2qJaUirAWulqTsG0oocODYHba2qXXUKD2mVYBxABcQwUJoQWmgjH0hFRDZUd4vEPmACGDzE - Y3NwCMcBYrKSeP4aQtTRCqBKoJgioYUFJoDUStgBVaubaWLzIxBarNaxm7kFbCXgPVpUowFAZYBFKYIO - a7b0E6pYAUVyYVoEbMa4x30KPWCrBIp84BwjXeggsqqQCvABqT84RixBgIjERmEaqztuDp5SAkpM9gAo - LcEsgLpY6uZAoMhoA2flYdpvpKcC+u1OXSeLTosQQwILZWOokGHOB3gAuLONQmIRcdb8Hrc7H/DEZCkx - XYUIQAkK7aaGKdKFZX4iFOsAKy0QYFo/FQTCJzaIVScrj40K5AO+SK8wy1sRAczjAZ+gBDWMLJB0mJYS - BwLyattDiwbAVrYXUccrBtEAbYA1AGdenf4kTBuDykT4IMSAbQM4W5A80oYbpg0FprT82DSJA7ZhSiU7 - cpDYSYznWG9Gq3/t6om/fvDJib2GtPjs2DQFwBewrUOaaWMBEa/1ECC+aKIrc4AVt3hJtDiAac3R3lEf - pBqw5QOVS6ME0/rAe5TOgaXRLAHYtsiA6DiEfcXl5iALDbaAoDNl8GDaPjQw17sWCANgm7H3lSAfic2H - dicCbYqQ4BKTvYSjXdQH0z4oVK5OyDJgi4cldTqxh4i2TNKNkAq8drJHc5EPTEucinS7IrCebD1chA5P - O7UHnP13ReqxYoJj26lRADO36Z0QdSxap/X7UAUY7NTI4oriCZmwTkx9wSN04GECE6jDTQMD8qXMoQFl - 3jRRR6LwEFZg1h7MtbJXiZFc45znv1LtYw8hc6BPhBZ8WC09jD4UWrADrnINItPHliVofPLnOwkIACH5 - BAAFAAAALAAAAABkAGQAh/ho5P7+/v78/vDw8P5G5P4W3P4G2v6W8Pye7vwe3PLU7vyi8Pj4+P5o5v4m - 3v4I2v629Pym7vx+6Pr6+vps5Po83vqy8PqO6vr4+viE5vh45Ph25vhs5Pi48PiQ6Pz4/PzR9vbG8PLw - 8vaS6Pn0+Pb09vTw9PTo8vTi8vTa8PSm6PSc6P4W2vLy8vLg8PLe8Prl9vTu9PTk8vTc8P5W5v4Y3Pyk - 7vyg7vxW5P526v4t3v4S2vyU7vqC6Ppa4vqW7PiM6PiA5via7PTI7PS27PLY7vyO7PyE6vii7PqS6vjc - 9Pba8v5m6Px+6vqQ6viW6viU6vaW6PTq8vyA6PqA6Pp45vpu5viG5v5c5P5I5PxC4vpu5PpQ4vw23vpC - 4Pwu3vrN8/wk3P4Q2v4O2v4M2v4K2vjO8vbU8f424PbO8Py+8vjJ8PbK8Pq/8f494fjE8P5I4vi88Pq6 - 8Py48vq28P6m8vy08Pyw8Pys8Pyo8P6m8Pym8P6d8P596v5u6P526PqH6Ppg4viO6PiC5vp86Pp05vpS - 4vpK4P6G7Pqm7fyW7PyE7PyC6vxu5/xN4vw83vww3vwm3Pp66PyI7P6P7fyK6v6a7viz7va67PTI7vTA - 7Piq7PqU6viY6vam6vxk5fig7Pqc7Pic6v5e5vxg5f5a5Pqe7Ppd4vqg7Pxa5Pqq7v5U5P5S5Pis7Pqs - 7v5Q5Pqw7v5O5P5M5Pwy3v5K5Pi27v648/xF4f78/Pa67v76/v76/PbA7vw84PpU4vw63vTO7vxU5Ppi - 4vpm5Pzu+v7a+PxW4vpq5P4k3vuf7f4i3Pqa7Paw7P4g3P4e3P4c3PyZ7v4a3v4a3Pin7P669Pzg9/6+ - 9PyS7Piw7P7K9fLq8vrb9fzK9Pbs9Pp+5vjv9/404Pjn9fbq9P5G4v6t8fx36P6Y7vz2+/z7/PzW9vr2 - +vb29vXy9PTw8vro+PTm8vjf9Pbg9PrU9PjX8/bV8vbS8PzA9PjE8vrF8vi+8Pq78fy68vq48Pyy8v6k - 8AAAAAj+AAMIHEiwoMGDCBMKZFCixYAW69ApnEixosWLGAWSIAQOXBB2EjOKHEkyIzoJDlI66DGhpMuX - MAVOgKTSAZqWMXPqrEiipgMdDHYKHVqQnU+gRJMiRMeAAc6LJo4GNTkhpFKLExKRIpXoacWoNZFeRKfo - 1jgh665aDIWmLZpQGMGqFFsRHaACeAtcYGBV7UF0BNyicQMDqtSLZ5zlLQC0r9+C6NwIRlPOcUK5KelO - ZHBqcYFmUx8jzDEZDRiLIg5XxOS5wCfLogcqkSwYS2iFqcPevtzL8zMlsROiu1DaVcXcc3f/jdJ6Cuzg - ArsFFkzgG0XkmZUblOHAsw7r0Jf+bip94flA7D+1E2SwoTWS8ArZYZnsZttE9JoPAovm+RYG+AqFUJoV - XhmEn3oClWBIa/gAqBAD5ZTWYEIHCsdMa8MU6GBBM9DmFg3qUKjaQSZ04Vkz8Gyo0ARQlJaIiLohNIEg - rQFinooBdOPIZFq4g1CFB72gjGeQgIdjQsyUdgRsQBbEAAWttSIaU1WJtM4npclzUJMEZVKDZ45oSBE6 - 6FSJFSo0yDIFPDceZEZpDWiIWXoGlXCIZzWchhEDaXBBRg0sWeQKAYQSIMsPRlbEgDeldWDQnPmh40lr - VrRJEDoycECGAZwaAEVdfhRaKA0W/GcRClpM9goJBUG6mxT+kHiGTGGojVBDp50+guBA6IQqaqENgGFp - AOiIUhpcBLlK0AQZtJbEsOsQMQuuuFaw60B3/PrrEbROZAIr9HUbgLIDpaDYYmiwupkCvlBL7RPXCiRA - BLFoW2gsyairUC6lSWBVCUc9xYAwrdUyETonaDCGu52KcUW8BMXTg72FliKHmAOt00BpegagzlFW8dIa - DhgLxM4KCTDcqQ9KDOskGw1QTGgj8phXT2mk4ISODjWhERIGWngWzRkJMaDJLypz2kU+JVdUAjY0yJxF - JT4eNAEgpbUxUBM19RBSP61VAdsERZyStAHPCAHxmN38IIvMr0QQokEnjDMZsh5P0VH+D9+ENIlnDlR9 - qRSD7JA0GYWEI9QES0giMwGj4FMgOolMpg+vDLVQAl8C3eEZ3gOVoIIDZ3NxhssiMfDGJ4+Xs01fGPjh - ViOW6rJKXjiYutAQXpz9RS1N51TCJqxInQQxBO1iCw+26D7RB3n0oIru6LgAwANJF+CBvn6h884FWci8 - iivOjwT7BQUkXcYx4aCuEwP0NPJ4DuWX9IEWZ99ihvtDMRDHKDK7XExukDQHbGJtfjEBEuqlLQTkJAcM - 20EGEnUkdKDgCNoSIEwW4K5AsOlIB2GAGeRHqD7sIifqgEOuJAfCFXFDD9ng30QwoIoeXCJ4LVSLDHPI - w4NN4If+QAyiEIdIxB/u0CRkSqISl8hEJl6KBKEYBQ2mSMUqWvGKVxwFAs6RFAEUgxoQCKMYx0jGMpaR - GsUQQAAmEAosuvGNWOTDESdSDDPa8Y5mLMYapQjHPr5xFHNUCBjxSMg7UmOPfkxkFpMyyEI6coyHRAcC - FEnJKTqQKHV8pCYhkA6BfAABfKzkHxGgi6Sg44ubJCQ10tEXpqzjlbCMpSxnCcumBLKHuMylLnE5AW7c - gRu3NEg1QFANNe6SWOlABBOWSYkTxkQA1qiDNG3hjmAqxR2WWKY2mZCNnBRDmuCsQzaQx0N13MEP29Qm - OXICgnCGEwT1AxA68JGDdG6zmzH+qYY7w9mPalizJOioxiTsuU1KGBMm0NxnOKlBjH9mhBgIaABBl5kD - NTg0AF4kh0LBmQ3u+QUDdEDnRBsQgUR9IBv9yIYzx1SMbOiRIOfIxkalSY504BAm6ABDHya6TCN8kFfm - yIFQLXHQhAigHwdIKgSKGgBiRHOmEPCnUmBACZ4yoQ9gUI49hMpVEGDOlgQpRlLH6lVhQmCmdbAGOXdC - jAhIdKJ+oINHBUKMPnBVqNYYCAbmQAlK2OIDA8nGWJPKh7lBJh0anWk2DPsSDKihniNNhjieg4e7CrWT - ArEFIjaLiEMKpBqDTao9nhNTtJKjGDcVjjyUydNKKKFkMLD+bA54cFBKcBYRlBiIAMgRWnMI7iDEoAZa - IQCDHbqDB1bNwRp2hY6gWhY4A7ntZq0Cg9AeoB9tqsYd0KpWjEzgnDz1AyxKQBEQyDYCVkGHdBHhFWpY - 1z7PaydayzomOVgVGu2jyDkQYdk+dONS670NMfgQ2jrE0yDnsAdaXzqRCRxhooiYR2ofa1l9tDLABRFs - aDtGEXfYYqOePdiD05mDNiCwrpZFhEfVK93dfMAfoeUDBRWS0X2GeCJq2KYfVDFjhaAjD7LlsEBYfFvl - pMO6FsXIOeQLTgZPRABzyIEfzFHcjFRDttDQEJE5qxx08Da0v7WIU+tQ0ynxQLYpMsj+ljerHWJYlxyp - hcxFJ8IN2eIBNmtGhHqs8d5jqoO/d+1Dj4mF4YOcg8CDXQBjexhlyyb5L4U+CAisyw1dusOud6UEgvK8 - 6TqE1hJrzSE6FiBbLQkn0gcBbWhtMeeYbEO2CGgapyeC1NCKq4JG6O+t1Yxq4L45zo+hp2Ut0KZZT8Qe - 1jX1kfZrWUYMGsAt1i+ix1pYEPZDthM6WK8RMunQ2uNI7pCtpuuy7b94OrShBhACZAvfMZU71da1hYom - IFsbuMzYFbFFjOcNaKH2Icw+fjdwLZFoFaGDwkJVA0bwXRFuDJa+DpoAPpKaDaZqO9pjAQE5yAGCVpNk - hwy3CJktjklu6QKb5Atfr8dRjg7bcja3KCcKOuZw2xvHfCd77escDnzzl0ygKWDdUEAAADs= - - \ No newline at end of file diff --git a/Rdmp.UI/SimpleDialogs/ViewSourceCodeToolTip.cs b/Rdmp.UI/SimpleDialogs/ViewSourceCodeToolTip.cs index e5061152be..ec517c278e 100644 --- a/Rdmp.UI/SimpleDialogs/ViewSourceCodeToolTip.cs +++ b/Rdmp.UI/SimpleDialogs/ViewSourceCodeToolTip.cs @@ -109,29 +109,26 @@ private void OnDraw(object sender, DrawToolTipEventArgs e) private static string[] ReadAllLinesCached(string filename) { - if (!SourceFileCache.ContainsKey(filename)) - { - string[] fileContents; - - //if you have the original file - if (File.Exists(filename)) - { - fileContents = File.ReadLines(filename).ToArray(); - } - //otherwise get it from SourceCodeForSelfAwareness.zip / Plugin zip source codes - else - { - var contentsInOneLine = ViewSourceCodeDialog.GetSourceForFile(Path.GetFileName(filename)); + if (SourceFileCache.TryGetValue(filename, out var fileContents)) return fileContents; - if (contentsInOneLine == null) - return null; + //if you have the original file + if (File.Exists(filename)) + { + fileContents = File.ReadLines(filename).ToArray(); + } + //otherwise get it from SourceCodeForSelfAwareness.zip / Plugin zip source codes + else + { + var contentsInOneLine = ViewSourceCodeDialog.GetSourceForFile(Path.GetFileName(filename)); - fileContents = contentsInOneLine.Split('\n'); - } + if (contentsInOneLine == null) + return null; - SourceFileCache.Add(filename, fileContents); + fileContents = contentsInOneLine.Split('\n'); } - return SourceFileCache[filename]; + SourceFileCache.Add(filename, fileContents); + + return fileContents; } } \ No newline at end of file diff --git a/Rdmp.UI/SimpleDialogs/WideMessageBox.Designer.cs b/Rdmp.UI/SimpleDialogs/WideMessageBox.Designer.cs index 04f242f660..5072618afa 100644 --- a/Rdmp.UI/SimpleDialogs/WideMessageBox.Designer.cs +++ b/Rdmp.UI/SimpleDialogs/WideMessageBox.Designer.cs @@ -112,6 +112,7 @@ private void InitializeComponent() // this.btnViewSourceCode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnViewSourceCode.Enabled = false; + this.btnViewSourceCode.Visible = false; this.btnViewSourceCode.Image = ((System.Drawing.Image)(resources.GetObject("btnViewSourceCode.Image"))); this.btnViewSourceCode.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; this.btnViewSourceCode.Location = new System.Drawing.Point(692, 0); diff --git a/Rdmp.UI/SimpleDialogs/WideMessageBox.cs b/Rdmp.UI/SimpleDialogs/WideMessageBox.cs index 18805eaf59..d02aab349b 100644 --- a/Rdmp.UI/SimpleDialogs/WideMessageBox.cs +++ b/Rdmp.UI/SimpleDialogs/WideMessageBox.cs @@ -68,6 +68,7 @@ public WideMessageBox(WideMessageBoxArgs args) //can only write to clipboard in STA threads btnCopyToClipboard.Visible = Thread.CurrentThread.GetApartmentState() == ApartmentState.STA; + btnViewStackTrace.Visible = true; //try to resize form to fit bounds Size = GetPreferredSizeOfTextControl(richTextBox1); @@ -148,11 +149,13 @@ private void SetViewSourceCodeButton(string title) ViewSourceCodeDialog.SourceCodeIsAvailableFor($"{title}.cs")) { btnViewSourceCode.Enabled = true; + btnViewSourceCode.Visible = true; btnViewSourceCode.Tag = $"{title}.cs"; } else { btnViewSourceCode.Enabled = false; + btnViewSourceCode.Visible = false; } } diff --git a/Rdmp.UI/SubComponents/DatasetConfigurationUI.Designer.cs b/Rdmp.UI/SubComponents/DatasetConfigurationUI.Designer.cs new file mode 100644 index 0000000000..df11a5de7d --- /dev/null +++ b/Rdmp.UI/SubComponents/DatasetConfigurationUI.Designer.cs @@ -0,0 +1,147 @@ +namespace Rdmp.UI.SubComponents; + +partial class DatasetConfigurationUI +{ + /// + /// 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 Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + label1 = new System.Windows.Forms.Label(); + tbName = new System.Windows.Forms.TextBox(); + tbDOI = new System.Windows.Forms.TextBox(); + tbSource = new System.Windows.Forms.TextBox(); + label2 = new System.Windows.Forms.Label(); + label3 = new System.Windows.Forms.Label(); + label4 = new System.Windows.Forms.Label(); + tbFolder = new System.Windows.Forms.TextBox(); + lblDatasetUsage = new System.Windows.Forms.Label(); + SuspendLayout(); + // + // label1 + // + label1.AutoSize = true; + label1.Location = new System.Drawing.Point(24, 40); + label1.Name = "label1"; + label1.Size = new System.Drawing.Size(86, 15); + label1.TabIndex = 0; + label1.Text = "Dataset Name*"; + label1.Click += label1_Click; + // + // tbName + // + tbName.Location = new System.Drawing.Point(27, 65); + tbName.Name = "tbName"; + tbName.Size = new System.Drawing.Size(270, 23); + tbName.TabIndex = 1; + // + // tbDOI + // + tbDOI.Location = new System.Drawing.Point(24, 155); + tbDOI.Name = "tbDOI"; + tbDOI.Size = new System.Drawing.Size(273, 23); + tbDOI.TabIndex = 2; + // + // tbSource + // + tbSource.Location = new System.Drawing.Point(24, 235); + tbSource.Name = "tbSource"; + tbSource.Size = new System.Drawing.Size(273, 23); + tbSource.TabIndex = 3; + // + // label2 + // + label2.AutoSize = true; + label2.Location = new System.Drawing.Point(24, 123); + label2.Name = "label2"; + label2.Size = new System.Drawing.Size(69, 15); + label2.TabIndex = 4; + label2.Text = "Dataset DOI"; + // + // label3 + // + label3.AutoSize = true; + label3.Location = new System.Drawing.Point(28, 202); + label3.Name = "label3"; + label3.Size = new System.Drawing.Size(85, 15); + label3.TabIndex = 5; + label3.Text = "Dataset Source"; + // + // label4 + // + label4.AutoSize = true; + label4.Location = new System.Drawing.Point(28, 282); + label4.Name = "label4"; + label4.Size = new System.Drawing.Size(82, 15); + label4.TabIndex = 6; + label4.Text = "Dataset Folder"; + label4.Click += label4_Click; + // + // tbFolder + // + tbFolder.Location = new System.Drawing.Point(24, 314); + tbFolder.Name = "tbFolder"; + tbFolder.Size = new System.Drawing.Size(273, 23); + tbFolder.TabIndex = 7; + // + // lblDatasetUsage + // + lblDatasetUsage.AutoSize = true; + lblDatasetUsage.Location = new System.Drawing.Point(369, 65); + lblDatasetUsage.Name = "lblDatasetUsage"; + lblDatasetUsage.Size = new System.Drawing.Size(38, 15); + lblDatasetUsage.TabIndex = 8; + lblDatasetUsage.Text = "label5"; + // + // DatsetConfigurationUI + // + AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + Controls.Add(lblDatasetUsage); + Controls.Add(tbFolder); + Controls.Add(label4); + Controls.Add(label3); + Controls.Add(label2); + Controls.Add(tbSource); + Controls.Add(tbDOI); + Controls.Add(tbName); + Controls.Add(label1); + Name = "DatsetConfigurationUI"; + Size = new System.Drawing.Size(800, 450); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox tbName; + private System.Windows.Forms.TextBox tbDOI; + private System.Windows.Forms.TextBox tbSource; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox tbFolder; + private System.Windows.Forms.Label lblDatasetUsage; +} diff --git a/Rdmp.UI/SubComponents/DatasetConfigurationUI.cs b/Rdmp.UI/SubComponents/DatasetConfigurationUI.cs new file mode 100644 index 0000000000..1e90f872f6 --- /dev/null +++ b/Rdmp.UI/SubComponents/DatasetConfigurationUI.cs @@ -0,0 +1,70 @@ +using Rdmp.UI.TestsAndSetup.ServicePropogation; +using System; +using System.ComponentModel; +using System.Linq; +using System.Windows.Forms; +using Rdmp.UI.Refreshing; +using Rdmp.Core.Dataset; +using Rdmp.Core.Curation.Data; +using Rdmp.UI.ItemActivation; + +namespace Rdmp.UI.SubComponents; +public partial class DatasetConfigurationUI : DatsetConfigurationUI_Design, IRefreshBusSubscriber +{ + private readonly DatasetConfigurationUICommon _common; + + public DatasetConfigurationUI() + { + InitializeComponent(); + _common = new DatasetConfigurationUICommon(); + } + + public override void SetDatabaseObject(IActivateItems activator, Dataset databaseObject) + { + base.SetDatabaseObject(activator, databaseObject); + _common.Dataset = databaseObject; + + var catalogues = databaseObject.CatalogueRepository + .GetAllObjectsWhere("Dataset_ID", databaseObject.ID).SelectMany(static ci => ci.CatalogueItems) + .Select(static ci => ci.CatalogueName).Distinct().ToList(); + if(catalogues.Count < 1) + { + lblDatasetUsage.Text = "This dataset is not linked to data yet."; + } + else + { + var catalogueString = string.Join(Environment.NewLine, catalogues); + lblDatasetUsage.Text = $"This dataset is used in the following catalogues:{Environment.NewLine}{catalogueString}"; + } + + Bind(tbName, "Text", "Name", static c => c.Name); + Bind(tbDOI, "Text", "DigitalObjectIdentifier", static c => c.DigitalObjectIdentifier); + Bind(tbSource, "Text", "Source", static c => c.Source); + Bind(tbFolder, "Text", "Folder", static c => c.Folder); + var s = GetObjectSaverButton(); + s.SetupFor(this, databaseObject, activator); + GetObjectSaverButton()?.Enable(false); + + } + + + public void RefreshBus_RefreshObject(object sender, RefreshObjectEventArgs e) + { + } + + private void label1_Click(object sender, EventArgs e) + { + + } + + private void label4_Click(object sender, EventArgs e) + { + + } +} +[TypeDescriptionProvider( + typeof(AbstractControlDescriptionProvider))] +public abstract class + DatsetConfigurationUI_Design : RDMPSingleDatabaseObjectControl +{ +} \ No newline at end of file diff --git a/Rdmp.UI/SubComponents/DatasetConfigurationUI.resx b/Rdmp.UI/SubComponents/DatasetConfigurationUI.resx new file mode 100644 index 0000000000..af32865ec1 --- /dev/null +++ b/Rdmp.UI/SubComponents/DatasetConfigurationUI.resx @@ -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 diff --git a/Rdmp.UI/TestsAndSetup/ServicePropogation/RDMPControlCommonFunctionality.cs b/Rdmp.UI/TestsAndSetup/ServicePropogation/RDMPControlCommonFunctionality.cs index a7d33ad48e..cdc6e1a213 100644 --- a/Rdmp.UI/TestsAndSetup/ServicePropogation/RDMPControlCommonFunctionality.cs +++ b/Rdmp.UI/TestsAndSetup/ServicePropogation/RDMPControlCommonFunctionality.cs @@ -396,9 +396,10 @@ public void AddToMenu(ToolStripItem menuItem, string underMenu = null) if (!string.IsNullOrWhiteSpace(underMenu)) { - if (!_addToMenuSubmenus.ContainsKey(underMenu)) + if (!_addToMenuSubmenus.TryGetValue(underMenu, out var stripMenuItem)) { - _addToMenuSubmenus.Add(underMenu, new ToolStripMenuItem(underMenu)); + stripMenuItem = new ToolStripMenuItem(underMenu); + _addToMenuSubmenus.Add(underMenu, stripMenuItem); // If it's the GoTo menu then when the user expands the menu we have to fetch the objects // and update the IsImpossible status etc. @@ -406,8 +407,8 @@ public void AddToMenu(ToolStripItem menuItem, string underMenu = null) RDMPContextMenuStrip.RegisterFetchGoToObjecstCallback(_addToMenuSubmenus[underMenu]); } - _addToMenuSubmenus[underMenu].DropDownItems.Add(menuItem); - _menuDropDown.DropDownItems.Add(_addToMenuSubmenus[underMenu]); + stripMenuItem.DropDownItems.Add(menuItem); + _menuDropDown.DropDownItems.Add(stripMenuItem); } else { diff --git a/Rdmp.UI/TestsAndSetup/StartupUI.cs b/Rdmp.UI/TestsAndSetup/StartupUI.cs index 15361fcb5c..0732b27690 100644 --- a/Rdmp.UI/TestsAndSetup/StartupUI.cs +++ b/Rdmp.UI/TestsAndSetup/StartupUI.cs @@ -279,16 +279,15 @@ private void HandleDatabaseFoundOnSimpleUI(PlatformDatabaseFoundEventArgs eventA ragSmiley1.OnCheckPerformed(new CheckEventArgs(eventArgs.SummariseAsString(), CheckResult.Success)); return; case RDMPPlatformDatabaseStatus.SoftwareOutOfDate: - if (!_haveWarnedAboutOutOfDate) - { - MessageBox.Show( - "The RDMP database you are connecting to is running a newer schema to your software, please consider updating the software to the latest version"); - _haveWarnedAboutOutOfDate = true; - } + if (_haveWarnedAboutOutOfDate) return; + + MessageBox.Show( + "The RDMP database you are connecting to is running a newer schema to your software, please consider updating the software to the latest version"); + _haveWarnedAboutOutOfDate = true; return; default: - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(eventArgs),$"Invalid status {eventArgs.Status}"); } } diff --git a/Rdmp.UI/Theme/BackColorProvider.cs b/Rdmp.UI/Theme/BackColorProvider.cs index 9ee383ff89..8e61ecd7d5 100644 --- a/Rdmp.UI/Theme/BackColorProvider.cs +++ b/Rdmp.UI/Theme/BackColorProvider.cs @@ -29,6 +29,7 @@ public static Color GetColor(RDMPCollection collection) RDMPCollection.Favourites => SystemColors.Control, RDMPCollection.Cohort => Color.FromArgb(210, 240, 255), RDMPCollection.DataLoad => Color.DarkGray, + RDMPCollection.Datasets => Color.PaleVioletRed, _ => throw new ArgumentOutOfRangeException(nameof(collection)) }; } diff --git a/Rdmp.UI/Wizard/CreateNewDataExtractionProjectUI.cs b/Rdmp.UI/Wizard/CreateNewDataExtractionProjectUI.cs index 582cbacb6e..6bc385d83c 100644 --- a/Rdmp.UI/Wizard/CreateNewDataExtractionProjectUI.cs +++ b/Rdmp.UI/Wizard/CreateNewDataExtractionProjectUI.cs @@ -301,60 +301,60 @@ private void btnExecute_Click(object sender, EventArgs e) ProjectCreatedIfAny.SaveToDatabase(); - if (_configuration == null && cbDefineCohort.Checked) + if (cbDefineCohort.Checked) { - _configuration = new ExtractionConfiguration(Activator.RepositoryLocator.DataExportRepository, - ProjectCreatedIfAny) + if (_configuration == null) { - Name = "Cases" - }; - _configuration.SaveToDatabase(); - } - - foreach (ExtractableDataSet ds in _selectedDatasets) - _configuration.AddDatasetToConfiguration(ds); - - ICommandExecution cmdAssociateCicWithProject = null; + _configuration = new ExtractionConfiguration(Activator.RepositoryLocator.DataExportRepository, + ProjectCreatedIfAny) + { + Name = "Cases" + }; + _configuration.SaveToDatabase(); + } + foreach (var ds in _selectedDatasets) + _configuration.AddDatasetToConfiguration(ds); - if (_cohortCreated == null && cbDefineCohort.Checked) - { - var cohortDefinition = new CohortDefinition(null, tbCohortName.Text, 1, - ProjectCreatedIfAny.ProjectNumber.Value, - (ExternalCohortTable)ddCohortSources.SelectedItem); - //execute the cohort creation bit - var cohortRequest = new CohortCreationRequest(ProjectCreatedIfAny, cohortDefinition, - Activator.RepositoryLocator.DataExportRepository, tbCohortName.Text); + ICommandExecution cmdAssociateCicWithProject = null; - ComboBox dd; - if (_cohortFile != null) + if (_cohortCreated == null) { - //execute cohort creation from file. - cohortRequest.FileToLoad = new FlatFileToLoad(_cohortFile); - dd = ddFilePipeline; - } - else - { - //execute cohort creation from cic - cohortRequest.CohortIdentificationConfiguration = - (CohortIdentificationConfiguration)cbxCohort.SelectedItem; - dd = ddCicPipeline; - - - //since we are about to execute a cic and store the results we should associate it with the Project (if successful) - cmdAssociateCicWithProject = - new ExecuteCommandAssociateCohortIdentificationConfigurationWithProject(Activator).SetTarget( - ProjectCreatedIfAny).SetTarget(cohortRequest.CohortIdentificationConfiguration); + var cohortDefinition = new CohortDefinition(null, tbCohortName.Text, 1, + ProjectCreatedIfAny.ProjectNumber.Value, + (ExternalCohortTable)ddCohortSources.SelectedItem); + + //execute the cohort creation bit + var cohortRequest = new CohortCreationRequest(ProjectCreatedIfAny, cohortDefinition, + Activator.RepositoryLocator.DataExportRepository, tbCohortName.Text); + + ComboBox dd; + if (_cohortFile != null) + { + //execute cohort creation from file. + cohortRequest.FileToLoad = new FlatFileToLoad(_cohortFile); + dd = ddFilePipeline; + } + else + { + //execute cohort creation from cic + cohortRequest.CohortIdentificationConfiguration = + (CohortIdentificationConfiguration)cbxCohort.SelectedItem; + dd = ddCicPipeline; + + + //since we are about to execute a cic and store the results we should associate it with the Project (if successful) + cmdAssociateCicWithProject = + new ExecuteCommandAssociateCohortIdentificationConfigurationWithProject(Activator).SetTarget( + ProjectCreatedIfAny).SetTarget(cohortRequest.CohortIdentificationConfiguration); + } + + var engine = cohortRequest.GetEngine((Pipeline)dd.SelectedItem, + ThrowImmediatelyDataLoadEventListener.Quiet); + engine.ExecutePipeline(new GracefulCancellationToken()); + _cohortCreated = cohortRequest.CohortCreatedIfAny; } - var engine = cohortRequest.GetEngine((Pipeline)dd.SelectedItem, - ThrowImmediatelyDataLoadEventListener.Quiet); - engine.ExecutePipeline(new GracefulCancellationToken()); - _cohortCreated = cohortRequest.CohortCreatedIfAny; - } - - if (cbDefineCohort.Checked) - { //associate the configuration with the cohort _configuration.Cohort_ID = _cohortCreated.ID; diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index 0f6c6a8c98..d38a506be7 100644 --- a/SharedAssemblyInfo.cs +++ b/SharedAssemblyInfo.cs @@ -10,6 +10,6 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("8.1.0")] -[assembly: AssemblyFileVersion("8.1.0")] -[assembly: AssemblyInformationalVersion("8.1.0")] \ No newline at end of file +[assembly: AssemblyVersion("8.1.1")] +[assembly: AssemblyFileVersion("8.1.1")] +[assembly: AssemblyInformationalVersion("8.1.1")] \ No newline at end of file diff --git a/Tests.Common/DatabaseTests.cs b/Tests.Common/DatabaseTests.cs index ba5bcfd6a1..9a6d024e23 100644 --- a/Tests.Common/DatabaseTests.cs +++ b/Tests.Common/DatabaseTests.cs @@ -175,8 +175,8 @@ public DatabaseTests() { Console.WriteLine( $"Expecting Unit Test Data Export To Be At Server={tblRepo.DiscoveredServer.Name} Database= {tblRepo.DiscoveredServer.GetCurrentDatabase()}"); - Assert.IsTrue(tblRepo.DiscoveredServer.Exists(), - "Data Export database does not exist, run 'rdmp.exe install ...' to create it (Ensure that servername and prefix in TestDatabases.txt match those you provide to CreateDatabases.exe e.g. 'rdmp.exe install localhost\\sqlexpress TEST_')"); + Assert.That(tblRepo.DiscoveredServer.Exists(), + "Data Export database does not exist, run 'rdmp.exe install ...' to create it (Ensure that server name and prefix in TestDatabases.txt match those you provide to CreateDatabases.exe e.g. 'rdmp.exe install localhost\\sqlexpress TEST_')"); } @@ -390,9 +390,6 @@ private void BlitzMainDataTables(YamlRepository y) DeleteAll(y); DeleteAll(y); - DeleteAll(y); - DeleteAll(y); - DeleteAll(y); DeleteAll(y); DeleteAll(y); @@ -492,11 +489,10 @@ private void StartupOnDatabaseFound(object sender, PlatformDatabaseFoundEventArg } } - private void StartupOnPluginPatcherFound(object sender, PluginPatcherFoundEventArgs args) + private static void StartupOnPluginPatcherFound(object sender, PluginPatcherFoundEventArgs args) { - Assert.IsTrue(args.Status == PluginPatcherStatus.Healthy, "PluginPatcherStatus is {0} for plugin {1}{2}{3}", - args.Status, args.Type.Name, Environment.NewLine, - args.Exception == null ? "No exception" : ExceptionHelper.ExceptionToListOfInnerMessages(args.Exception)); + Assert.That(args.Status == PluginPatcherStatus.Healthy, + $"PluginPatcherStatus is {args.Status} for plugin {args.Type.Name}{Environment.NewLine}{(args.Exception == null ? "No exception" : ExceptionHelper.ExceptionToListOfInnerMessages(args.Exception))}"); } @@ -735,9 +731,9 @@ protected DiscoveredDatabase GetCleanedServer(DatabaseType type, string dbnName server.ChangeDatabase(dbnName); - Assert.IsTrue(database.Exists()); + Assert.That(database.Exists()); - //if it had non standard naming mark it for deletion on clean-up + //if it had non-standard naming mark it for deletion on clean-up if (!isStandardDb) forCleanup.Add(database); @@ -946,7 +942,7 @@ CREATE USER [{0}] FOR LOGIN [{0}] case DatabaseType.Oracle: break; default: - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(type)); } throw new NotImplementedException(); diff --git a/Tests.Common/Scenarios/TestsRequiringACohort.cs b/Tests.Common/Scenarios/TestsRequiringACohort.cs index e5c12a4fd4..01e8001251 100644 --- a/Tests.Common/Scenarios/TestsRequiringACohort.cs +++ b/Tests.Common/Scenarios/TestsRequiringACohort.cs @@ -177,7 +177,7 @@ var configToCleanup in DataExportRepository.GetAllObjects - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + \ No newline at end of file diff --git a/Tests.Common/UnitTests.cs b/Tests.Common/UnitTests.cs index 903ef5cd18..3910233e99 100644 --- a/Tests.Common/UnitTests.cs +++ b/Tests.Common/UnitTests.cs @@ -59,7 +59,8 @@ public class UnitTests "ExtractableCohort", "DQEGraphAnnotation", "Evaluation", - "WindowLayout" + "WindowLayout", + "Dataset" }); @@ -270,18 +271,6 @@ public static T WhenIHaveA(MemoryDataExportRepository repository) where T : D return (T)(object)joinable.AddUser(config); } - if (typeof(T) == typeof(Plugin)) - return (T)(object)new Plugin(repository, new FileInfo("bob.nupkg"), new Version(1, 1, 1), - new Version(1, 1, 1)); - - if (typeof(T) == typeof(LoadModuleAssembly)) - { - var dll = Path.Combine(TestContext.CurrentContext.TestDirectory, "a.nupkg"); - File.WriteAllBytes(dll, new byte[] { 0x11 }); - - return (T)(object)new LoadModuleAssembly(repository, new FileInfo(dll), WhenIHaveA(repository)); - } - if (typeof(T) == typeof(AggregateContinuousDateAxis)) { var config = WhenIHaveA(repository, out var dateEi, out _); @@ -700,8 +689,7 @@ public static void AssertAreEqual(IMapsDirectlyToDatabaseTable memObj, IMapsDire } catch (Exception e) { - Assert.Fail("{0} Property {1} could not be read from Memory:\r\n{2}", memObj.GetType().Name, - property.Name, e); + Assert.Fail($"{memObj.GetType().Name} Property {property.Name} could not be read from Memory:\r\n{e}"); } try @@ -710,8 +698,7 @@ public static void AssertAreEqual(IMapsDirectlyToDatabaseTable memObj, IMapsDire } catch (Exception e) { - Assert.Fail("{0} Property {1} could not be read from Database:\r\n{2}", dbObj.GetType().Name, - property.Name, e); + Assert.Fail($"{dbObj.GetType().Name} Property {property.Name} could not be read from Database:\r\n{e}"); } if (memValue is IMapsDirectlyToDatabaseTable table) @@ -728,8 +715,7 @@ public static void AssertAreEqual(IMapsDirectlyToDatabaseTable memObj, IMapsDire if (memValue is DateTime memTime && dbValue is DateTime dbTime) if (!AreAboutTheSameTime(memTime, dbTime)) - Assert.Fail("Dates differed, {0} Property {1} differed Memory={2} and Db={3}", - memObj.GetType().Name, property.Name, memTime, dbTime); + Assert.Fail($"Dates differed, {memObj.GetType().Name} Property {property.Name} differed Memory={memTime} and Db={dbTime}"); else return; @@ -738,8 +724,7 @@ public static void AssertAreEqual(IMapsDirectlyToDatabaseTable memObj, IMapsDire dbValue = dbValue as string == string.Empty ? null : dbValue; //all other properties should be legit - Assert.AreEqual(memValue, dbValue, "{0} Property {1} differed Memory={2} and Db={3}", memObj.GetType().Name, - property.Name, memValue, dbValue); + Assert.That(memValue,Is.EqualTo(dbValue), $"{memObj.GetType().Name} Property {property.Name} differed Memory='{memValue}' and Db='{dbValue}'"); } } @@ -749,7 +734,7 @@ public static void AssertAreEqual(IEnumerable memO var memObjectsArr = memObjects.OrderBy(o => o.ID).ToArray(); var dbObjectsArr = dbObjects.OrderBy(o => o.ID).ToArray(); - Assert.AreEqual(memObjectsArr.Length, dbObjectsArr.Length); + Assert.That(memObjectsArr.Length==dbObjectsArr.Length); for (var i = 0; i < memObjectsArr.Length; i++) AssertAreEqual(memObjectsArr[i], dbObjectsArr[i], firstIteration); diff --git a/Tools/rdmp/CommandLine/Gui/ConsoleGuiSelectOne.cs b/Tools/rdmp/CommandLine/Gui/ConsoleGuiSelectOne.cs index f1c172fd25..012aab90d6 100644 --- a/Tools/rdmp/CommandLine/Gui/ConsoleGuiSelectOne.cs +++ b/Tools/rdmp/CommandLine/Gui/ConsoleGuiSelectOne.cs @@ -69,7 +69,7 @@ protected override void AddMoreButtonsAfter(Window win, Button btnCancel) Y = Pos.Top(btnCancel) }; win.Add(lbl); - + txtId = new TextField { X = Pos.Right(lbl), diff --git a/Tools/rdmp/rdmp.csproj b/Tools/rdmp/rdmp.csproj index aba8a4e229..586155430c 100644 --- a/Tools/rdmp/rdmp.csproj +++ b/Tools/rdmp/rdmp.csproj @@ -13,7 +13,6 @@ embedded true true - true true net7.0 @@ -40,13 +39,9 @@ - - all - runtime; build; native; contentfiles; analyzers - - + - + diff --git a/rdmp-client.xml b/rdmp-client.xml index e279b08140..ae6840be2c 100644 --- a/rdmp-client.xml +++ b/rdmp-client.xml @@ -1,7 +1,7 @@ - 8.1.0.0 - https://github.com/HicServices/RDMP/releases/download/v8.1.0/rdmp-8.1.0-client.zip + 8.1.1.0 + https://github.com/HicServices/RDMP/releases/download/v8.1.1/rdmp-8.1.1-client.zip https://github.com/HicServices/RDMP/blob/main/CHANGELOG.md#810 true diff --git a/scripts/orphan_extractable_column.yaml b/scripts/orphan_extractable_column.yaml index ad4226e0f5..0e69b9052c 100644 --- a/scripts/orphan_extractable_column.yaml +++ b/scripts/orphan_extractable_column.yaml @@ -10,5 +10,5 @@ Commands: # TODO: we should detect and fail in this situation unless user sets specific error message suppression # check and execute the config - - extract -e "ExtractionConfiguration:New Clone" -p "Pipeline:DATA EXPORT*To CSV" --command check - - extract -e "ExtractionConfiguration:New Clone" -p "Pipeline:DATA EXPORT*To CSV" --command run + # - extract -e "ExtractionConfiguration:New Clone" -p "Pipeline:DATA EXPORT*To CSV" --command check + # - extract -e "ExtractionConfiguration:New Clone" -p "Pipeline:DATA EXPORT*To CSV" --command run diff --git a/wix/build.cmd b/wix/build.cmd index 64f2b97912..aa2e5685fe 100644 --- a/wix/build.cmd +++ b/wix/build.cmd @@ -1,9 +1,9 @@ @echo off set RDMPVERSION=%1 set wix="C:\Program Files (x86)\WiX Toolset v3.11\bin" -cd /d wix +cd /d %~dp0 %wix%\candle.exe rdmp.wxs -dVersion=%RDMPVERSION% -arch x64 -ext WixUtilExtension -nologo if errorlevel 1 exit 1 %wix%\light.exe rdmp.wixobj -ext WixUtilExtension -nologo if errorlevel 1 exit 1 -move rdmp.cli ..\dist\ \ No newline at end of file +move rdmp.msi ..\dist\ diff --git a/wix/rdmp.wxs b/wix/rdmp.wxs index 24ee3e3f00..949b738c1f 100644 --- a/wix/rdmp.wxs +++ b/wix/rdmp.wxs @@ -24,39 +24,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -121,30 +58,9 @@ - - - - - - - - - - - - - - - - - - - - -