@@ -1,5 +1,23 @@ | |||||
# Changelog | # Changelog | ||||
## [2.1.1] - 2019-06-08 | |||||
### Fixed | |||||
- #994: Remainder parameters now ignore character escaping, as there is no reason to escape characters here (2e95c49) | |||||
- #1316: `Emote.Equals` now pays no respect to the Name property, since Discord's API does not care about an emote's name (abf3e90) | |||||
- #1317: `Emote.GetHashCode` now pays no respect to the Name property, see above (1b54883) | |||||
- #1323: Optionals will no longer claim to be specified when a reaction message was not cached (1cc5d73) | |||||
- Log messages sourcing from REST events will no longer be raised twice (c78a679) | |||||
- News embeds will be processed as `EmbedType.Unknown`, rather than throwing an error and dropping the message (d287ed1) | |||||
### Changed | |||||
- #1311: Members may now be disconnected from voice channels by passing `null` as `GuildUserProperties.Channel` (fc48c66) | |||||
- #1313: `IMessage.Tags` now includes the EveryoneRole on @everyone and @here mentions (1f55f01) | |||||
- #1320: The maximum value for setting slow-mode has been updated to 6 hours, per the new API limit (4433ca7) | |||||
### Misc | |||||
- This library's compatibility with Semantic Versioning has been clarified. Please see the README (4d7de17) | |||||
- The depency on System.Interactive.Async has been bumped to `3.2.0` (3e65e03) | |||||
## [2.1.0] - 2019-05-18 | ## [2.1.0] - 2019-05-18 | ||||
### Added | ### Added | ||||
- #1236: Bulk deletes (for messages) may now be accessed via the `MessagesBulkDeleted` event (dec353e) | - #1236: Bulk deletes (for messages) may now be accessed via the `MessagesBulkDeleted` event (dec353e) | ||||
@@ -18,8 +18,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Providers.WS4Ne | |||||
EndProject | EndProject | ||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}" | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}" | ||||
EndProject | EndProject | ||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Tests", "test\Discord.Net.Tests\Discord.Net.Tests.csproj", "{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Webhook", "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj", "{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Webhook", "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj", "{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}" | ||||
EndProject | EndProject | ||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers", "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj", "{BBA8E7FB-C834-40DC-822F-B112CB7F0140}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Analyzers", "src\Discord.Net.Analyzers\Discord.Net.Analyzers.csproj", "{BBA8E7FB-C834-40DC-822F-B112CB7F0140}" | ||||
@@ -32,11 +30,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02_commands_framework", "sa | |||||
EndProject | EndProject | ||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03_sharded_client", "samples\03_sharded_client\03_sharded_client.csproj", "{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03_sharded_client", "samples\03_sharded_client\03_sharded_client.csproj", "{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}" | ||||
EndProject | EndProject | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "04_webhook_client", "samples\04_webhook_client\04_webhook_client.csproj", "{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}" | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Tests.Unit", "test\Discord.Net.Tests.Unit\Discord.Net.Tests.Unit.csproj", "{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Tests.Integration", "test\Discord.Net.Tests.Integration\Discord.Net.Tests.Integration.csproj", "{E169E15A-E82C-45BF-8C24-C2CADB7093AA}" | |||||
EndProject | EndProject | ||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{D1F0271E-0EE2-4B66-AC3D-9871B7E1C4CF}" | |||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C7CF5621-7D36-433B-B337-5A2E3C101A71}" | |||||
EndProject | EndProject | ||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Examples", "src\Discord.Net.Examples\Discord.Net.Examples.csproj", "{7EA96B2B-4D71-458D-9423-839362DC38BE}" | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Analyzers.Tests", "test\Discord.Net.Analyzers.Tests\Discord.Net.Analyzers.Tests.csproj", "{FC67057C-E92F-4E1C-98BE-46F839C8AD71}" | |||||
EndProject | EndProject | ||||
Global | Global | ||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
@@ -108,18 +108,6 @@ Global | |||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x64.Build.0 = Release|Any CPU | {6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x64.Build.0 = Release|Any CPU | ||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x86.ActiveCfg = Release|Any CPU | {6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x86.ActiveCfg = Release|Any CPU | ||||
{6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x86.Build.0 = Release|Any CPU | {6BDEEC08-417B-459F-9CA3-FF8BAB18CAC7}.Release|x86.Build.0 = Release|Any CPU | ||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|x64.Build.0 = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{C38E5BC1-11CB-4101-8A38-5B40A1BC6433}.Release|x86.Build.0 = Release|Any CPU | |||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | {9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|Any CPU.Build.0 = Debug|Any CPU | {9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
{9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|x64.ActiveCfg = Debug|Any CPU | {9AFAB80E-D2D3-4EDB-B58C-BACA78D1EA30}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
@@ -180,30 +168,42 @@ Global | |||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x64.Build.0 = Release|Any CPU | {9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x64.Build.0 = Release|Any CPU | ||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x86.ActiveCfg = Release|Any CPU | {9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x86.ActiveCfg = Release|Any CPU | ||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x86.Build.0 = Release|Any CPU | {9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}.Release|x86.Build.0 = Release|Any CPU | ||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Release|x64.Build.0 = Release|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562}.Release|x86.Build.0 = Release|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Release|x64.Build.0 = Release|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE}.Release|x86.Build.0 = Release|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x64.Build.0 = Release|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4}.Release|x86.Build.0 = Release|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x64.Build.0 = Release|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA}.Release|x86.Build.0 = Release|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x86.ActiveCfg = Debug|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Debug|x86.Build.0 = Debug|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x64.Build.0 = Release|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x86.ActiveCfg = Release|Any CPU | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71}.Release|x86.Build.0 = Release|Any CPU | |||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(SolutionProperties) = preSolution | GlobalSection(SolutionProperties) = preSolution | ||||
HideSolutionNode = FALSE | HideSolutionNode = FALSE | ||||
@@ -218,8 +218,9 @@ Global | |||||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} | {F2FF84FB-F6AD-47E5-9EE5-18206CAE136E} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} | ||||
{4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} | {4E1F1F40-B1DD-40C9-A4B1-A2046A4C9C76} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} | ||||
{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} | {9B4C4AFB-3D15-44C6-9E36-12ED625AAA26} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} | ||||
{88B77A5B-0BC0-4E99-8FD9-D83F6999F562} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B} | |||||
{7EA96B2B-4D71-458D-9423-839362DC38BE} = {D1F0271E-0EE2-4B66-AC3D-9871B7E1C4CF} | |||||
{DBF8B16E-5967-4480-8EDE-15D98A0DF0C4} = {C7CF5621-7D36-433B-B337-5A2E3C101A71} | |||||
{E169E15A-E82C-45BF-8C24-C2CADB7093AA} = {C7CF5621-7D36-433B-B337-5A2E3C101A71} | |||||
{FC67057C-E92F-4E1C-98BE-46F839C8AD71} = {C7CF5621-7D36-433B-B337-5A2E3C101A71} | |||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(ExtensibilityGlobals) = postSolution | GlobalSection(ExtensibilityGlobals) = postSolution | ||||
SolutionGuid = {D2404771-EEC8-45F2-9D71-F3373F6C1495} | SolutionGuid = {D2404771-EEC8-45F2-9D71-F3373F6C1495} | ||||
@@ -1,6 +1,6 @@ | |||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||
<PropertyGroup> | <PropertyGroup> | ||||
<VersionPrefix>2.1.1</VersionPrefix> | |||||
<VersionPrefix>2.2.0</VersionPrefix> | |||||
<VersionSuffix>dev</VersionSuffix> | <VersionSuffix>dev</VersionSuffix> | ||||
<Authors>RogueException</Authors> | <Authors>RogueException</Authors> | ||||
<PackageTags>discord;discordapp</PackageTags> | <PackageTags>discord;discordapp</PackageTags> | ||||
@@ -5,9 +5,14 @@ steps: | |||||
- script: dotnet build "Discord.Net.sln" --no-restore -v minimal -c $(buildConfiguration) /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag) | - script: dotnet build "Discord.Net.sln" --no-restore -v minimal -c $(buildConfiguration) /p:BuildNumber=$(buildNumber) /p:IsTagBuild=$(buildTag) | ||||
displayName: Build projects | displayName: Build projects | ||||
- script: dotnet test "test/Discord.Net.Tests/Discord.Net.Tests.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) --logger trx | |||||
# TODO: update this to support multiple tests | |||||
displayName: Test projects | |||||
- script: dotnet test "test/Discord.Net.Tests.Unit/Discord.Net.Tests.Unit.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) --logger trx | |||||
displayName: Unit Tests | |||||
- script: dotnet test "test/Discord.Net.Analyzers.Tests/Discord.Net.Analyzers.Tests.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) --logger trx | |||||
displayName: Analyzer Tests | |||||
# - script: dotnet test "test/Discord.Net.Tests.Integration/Discord.Net.Tests.Integration.csproj" --no-restore --no-build -v minimal -c $(buildConfiguration) --logger trx | |||||
# condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/dev')) | |||||
- task: PublishTestResults@2 | - task: PublishTestResults@2 | ||||
displayName: Publish test results | displayName: Publish test results | ||||
@@ -53,6 +53,13 @@ namespace Discord.Commands | |||||
else | else | ||||
c = '\0'; | c = '\0'; | ||||
//If we're processing an remainder parameter, ignore all other logic | |||||
if (curParam != null && curParam.IsRemainder && curPos != endPos) | |||||
{ | |||||
argBuilder.Append(c); | |||||
continue; | |||||
} | |||||
//If this character is escaped, skip it | //If this character is escaped, skip it | ||||
if (isEscaping) | if (isEscaping) | ||||
{ | { | ||||
@@ -79,13 +86,6 @@ namespace Discord.Commands | |||||
continue; | continue; | ||||
} | } | ||||
//If we're processing an remainder parameter, ignore all other logic | |||||
if (curParam != null && curParam.IsRemainder && curPos != endPos) | |||||
{ | |||||
argBuilder.Append(c); | |||||
continue; | |||||
} | |||||
//If we're not currently processing one, are we starting the next argument yet? | //If we're not currently processing one, are we starting the next argument yet? | ||||
if (curPart == ParserPart.None) | if (curPart == ParserPart.None) | ||||
{ | { | ||||
@@ -10,7 +10,7 @@ | |||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> | <PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> | ||||
<PackageReference Include="System.Collections.Immutable" Version="1.3.1" /> | <PackageReference Include="System.Collections.Immutable" Version="1.3.1" /> | ||||
<PackageReference Include="System.Interactive.Async" Version="3.1.1" /> | |||||
<PackageReference Include="System.Interactive.Async" Version="3.2.0" /> | |||||
<PackageReference Include="IDisposableAnalyzers" Version="2.1.2"> | <PackageReference Include="IDisposableAnalyzers" Version="2.1.2"> | ||||
<PrivateAssets>all</PrivateAssets> | <PrivateAssets>all</PrivateAssets> | ||||
</PackageReference> | </PackageReference> | ||||
@@ -0,0 +1,38 @@ | |||||
using System; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Flags for the <see cref="IActivity.Flags"/> property, that are ORd together. | |||||
/// These describe what the activity payload includes. | |||||
/// </summary> | |||||
[Flags] | |||||
public enum ActivityProperties | |||||
{ | |||||
/// <summary> | |||||
/// Indicates that no actions on this activity can be taken. | |||||
/// </summary> | |||||
None = 0, | |||||
Instance = 1, | |||||
/// <summary> | |||||
/// Indicates that this activity can be joined. | |||||
/// </summary> | |||||
Join = 0b10, | |||||
/// <summary> | |||||
/// Indicates that this activity can be spectated. | |||||
/// </summary> | |||||
Spectate = 0b100, | |||||
/// <summary> | |||||
/// Indicates that a user may request to join an activity. | |||||
/// </summary> | |||||
JoinRequest = 0b1000, | |||||
/// <summary> | |||||
/// Indicates that a user can listen along in Spotify. | |||||
/// </summary> | |||||
Sync = 0b10000, | |||||
/// <summary> | |||||
/// Indicates that a user can play this song. | |||||
/// </summary> | |||||
Play = 0b100000 | |||||
} | |||||
} |
@@ -12,6 +12,10 @@ namespace Discord | |||||
public string Name { get; internal set; } | public string Name { get; internal set; } | ||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public ActivityType Type { get; internal set; } | public ActivityType Type { get; internal set; } | ||||
/// <inheritdoc/> | |||||
public ActivityProperties Flags { get; internal set; } | |||||
/// <inheritdoc/> | |||||
public string Details { get; internal set; } | |||||
internal Game() { } | internal Game() { } | ||||
/// <summary> | /// <summary> | ||||
@@ -19,10 +23,12 @@ namespace Discord | |||||
/// </summary> | /// </summary> | ||||
/// <param name="name">The name of the game.</param> | /// <param name="name">The name of the game.</param> | ||||
/// <param name="type">The type of activity.</param> | /// <param name="type">The type of activity.</param> | ||||
public Game(string name, ActivityType type = ActivityType.Playing) | |||||
public Game(string name, ActivityType type = ActivityType.Playing, ActivityProperties flags = ActivityProperties.None, string details = null) | |||||
{ | { | ||||
Name = name; | Name = name; | ||||
Type = type; | Type = type; | ||||
Flags = flags; | |||||
Details = details; | |||||
} | } | ||||
/// <summary> Returns the name of the <see cref="Game"/>. </summary> | /// <summary> Returns the name of the <see cref="Game"/>. </summary> | ||||
@@ -19,5 +19,22 @@ namespace Discord | |||||
/// The type of activity. | /// The type of activity. | ||||
/// </returns> | /// </returns> | ||||
ActivityType Type { get; } | ActivityType Type { get; } | ||||
/// <summary> | |||||
/// Gets the flags that are relevant to this activity. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This value is determined by bitwise OR-ing <see cref="ActivityProperties"/> values together. | |||||
/// </remarks> | |||||
/// <returns> | |||||
/// The value of flags for this activity. | |||||
/// </returns> | |||||
ActivityProperties Flags { get; } | |||||
/// <summary> | |||||
/// Gets the details on what the player is currently doing. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// A string describing what the player is doing. | |||||
/// </returns> | |||||
string Details { get; } | |||||
} | } | ||||
} | } |
@@ -10,10 +10,6 @@ namespace Discord | |||||
{ | { | ||||
internal RichGame() { } | internal RichGame() { } | ||||
/// <summary> | |||||
/// Gets what the player is currently doing. | |||||
/// </summary> | |||||
public string Details { get; internal set; } | |||||
/// <summary> | /// <summary> | ||||
/// Gets the user's current party status. | /// Gets the user's current party status. | ||||
/// </summary> | /// </summary> | ||||
@@ -36,7 +36,7 @@ namespace Discord | |||||
/// <see cref="ChannelPermission.ManageChannels"/> will be exempt from slow-mode. | /// <see cref="ChannelPermission.ManageChannels"/> will be exempt from slow-mode. | ||||
/// </note> | /// </note> | ||||
/// </remarks> | /// </remarks> | ||||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the value does not fall within [0, 120].</exception> | |||||
/// <exception cref="ArgumentOutOfRangeException">Thrown if the value does not fall within [0, 21600].</exception> | |||||
public Optional<int> SlowModeInterval { get; set; } | public Optional<int> SlowModeInterval { get; set; } | ||||
} | } | ||||
} | } |
@@ -55,12 +55,7 @@ namespace Discord | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override int GetHashCode() | public override int GetHashCode() | ||||
{ | |||||
unchecked | |||||
{ | |||||
return (Name.GetHashCode() * 397) ^ Id.GetHashCode(); | |||||
} | |||||
} | |||||
=> Id.GetHashCode(); | |||||
/// <summary> Parses an <see cref="Emote"/> from its raw format. </summary> | /// <summary> Parses an <see cref="Emote"/> from its raw format. </summary> | ||||
/// <param name="text">The raw encoding of an emote (e.g. <c><:dab:277855270321782784></c>).</param> | /// <param name="text">The raw encoding of an emote (e.g. <c><:dab:277855270321782784></c>).</param> | ||||
@@ -486,7 +486,7 @@ namespace Discord | |||||
set | set | ||||
{ | { | ||||
var stringValue = value?.ToString(); | var stringValue = value?.ToString(); | ||||
if (string.IsNullOrEmpty(stringValue)) throw new ArgumentException(message: "Field value must not be null or empty.", paramName: nameof(Value)); | |||||
if (string.IsNullOrWhiteSpace(stringValue)) throw new ArgumentException(message: "Field value must not be null or empty.", paramName: nameof(Value)); | |||||
if (stringValue.Length > MaxFieldValueLength) throw new ArgumentException(message: $"Field value length must be less than or equal to {MaxFieldValueLength}.", paramName: nameof(Value)); | if (stringValue.Length > MaxFieldValueLength) throw new ArgumentException(message: $"Field value length must be less than or equal to {MaxFieldValueLength}.", paramName: nameof(Value)); | ||||
_value = stringValue; | _value = stringValue; | ||||
} | } | ||||
@@ -59,18 +59,19 @@ namespace Discord | |||||
/// </remarks> | /// </remarks> | ||||
public Optional<IEnumerable<ulong>> RoleIds { get; set; } | public Optional<IEnumerable<ulong>> RoleIds { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Moves a user to a voice channel. | |||||
/// Moves a user to a voice channel. If <c>null</c>, this user will be disconnected from their current voice channel. | |||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||
/// This user MUST already be in a <see cref="IVoiceChannel"/> for this to work. | /// This user MUST already be in a <see cref="IVoiceChannel"/> for this to work. | ||||
/// When set, this property takes precedence over <see cref="ChannelId"/>. | |||||
/// </remarks> | /// </remarks> | ||||
public Optional<IVoiceChannel> Channel { get; set; } | public Optional<IVoiceChannel> Channel { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// Moves a user to a voice channel. | |||||
/// Moves a user to a voice channel. Set <see cref="Channel"/> to <c>null</c> to disconnect this user from their current voice channel. | |||||
/// </summary> | /// </summary> | ||||
/// <remarks> | /// <remarks> | ||||
/// This user MUST already be in a <see cref="IVoiceChannel"/> for this to work. | /// This user MUST already be in a <see cref="IVoiceChannel"/> for this to work. | ||||
/// </remarks> | /// </remarks> | ||||
public Optional<ulong> ChannelId { get; set; } | |||||
public Optional<ulong> ChannelId { get; set; } // TODO: v3 breaking change, change ChannelId to ulong? to allow for kicking users from voice | |||||
} | } | ||||
} | } |
@@ -26,6 +26,34 @@ namespace Discord | |||||
/// <c>true</c> if this user has enabled multi-factor authentication on their account; <c>false</c> if not. | /// <c>true</c> if this user has enabled multi-factor authentication on their account; <c>false</c> if not. | ||||
/// </returns> | /// </returns> | ||||
bool IsMfaEnabled { get; } | bool IsMfaEnabled { get; } | ||||
/// <summary> | |||||
/// Gets the flags that are applied to a user's account. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This value is determined by bitwise OR-ing <see cref="UserProperties"/> values together. | |||||
/// </remarks> | |||||
/// <returns> | |||||
/// The value of flags for this user. | |||||
/// </returns> | |||||
UserProperties Flags { get; } | |||||
/// <summary> | |||||
/// Gets the type of Nitro subscription that is active on this user's account. | |||||
/// </summary> | |||||
/// <remarks> | |||||
/// This information may only be available with the identify OAuth scope. | |||||
/// </remarks> | |||||
/// <returns> | |||||
/// The type of Nitro subscription the user subscribes to, if any. | |||||
/// </returns> | |||||
PremiumType PremiumType { get; } | |||||
/// <summary> | |||||
/// Gets the user's chosen language option. | |||||
/// </summary> | |||||
/// <returns> | |||||
/// The IETF language tag of the user's chosen region, if provided. | |||||
/// For example, a locale of "English, US" is "en-US", "Chinese (Taiwan)" is "zh-TW", etc. | |||||
/// </returns> | |||||
string Locale { get; } | |||||
/// <summary> | /// <summary> | ||||
/// Modifies the user's properties. | /// Modifies the user's properties. | ||||
@@ -0,0 +1,21 @@ | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Specifies the type of subscription a user is subscribed to. | |||||
/// </summary> | |||||
public enum PremiumType | |||||
{ | |||||
/// <summary> | |||||
/// No subscription. | |||||
/// </summary> | |||||
None = 0, | |||||
/// <summary> | |||||
/// Nitro Classic subscription. Includes app perks like animated emojis and avatars, but not games. | |||||
/// </summary> | |||||
NitroClassic = 1, | |||||
/// <summary> | |||||
/// Nitro subscription. Includes app perks as well as the games subscription service. | |||||
/// </summary> | |||||
Nitro = 2 | |||||
} | |||||
} |
@@ -0,0 +1,41 @@ | |||||
using System; | |||||
namespace Discord | |||||
{ | |||||
[Flags] | |||||
public enum UserProperties | |||||
{ | |||||
/// <summary> | |||||
/// Default value for flags, when none are given to an account. | |||||
/// </summary> | |||||
None = 0, | |||||
/// <summary> | |||||
/// Flag given to Discord staff. | |||||
/// </summary> | |||||
Staff = 0b1, | |||||
/// <summary> | |||||
/// Flag given to Discord partners. | |||||
/// </summary> | |||||
Partner = 0b10, | |||||
/// <summary> | |||||
/// Flag given to users who have participated in the bug report program. | |||||
/// </summary> | |||||
BugHunter = 0b1000, | |||||
/// <summary> | |||||
/// Flag given to users who are in the HypeSquad House of Bravery. | |||||
/// </summary> | |||||
HypeSquadBravery = 0b100_0000, | |||||
/// <summary> | |||||
/// Flag given to users who are in the HypeSquad House of Brilliance. | |||||
/// </summary> | |||||
HypeSquadBrilliance = 0b1000_0000, | |||||
/// <summary> | |||||
/// Flag given to users who are in the HypeSquad House of Balance. | |||||
/// </summary> | |||||
HypeSquadBalance = 0b1_0000_0000, | |||||
/// <summary> | |||||
/// Flag given to users who subscribed to Nitro before games were added. | |||||
/// </summary> | |||||
EarlySupporter = 0b10_0000_0000, | |||||
} | |||||
} |
@@ -1,7 +1,7 @@ | |||||
#pragma warning disable CS1591 | |||||
#pragma warning disable CS1591 | |||||
using System; | using System; | ||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using Newtonsoft.Json.Converters; | |||||
using Discord.Net.Converters; | |||||
namespace Discord.API | namespace Discord.API | ||||
{ | { | ||||
@@ -15,7 +15,7 @@ namespace Discord.API | |||||
public string Url { get; set; } | public string Url { get; set; } | ||||
[JsonProperty("color")] | [JsonProperty("color")] | ||||
public uint? Color { get; set; } | public uint? Color { get; set; } | ||||
[JsonProperty("type"), JsonConverter(typeof(StringEnumConverter))] | |||||
[JsonProperty("type"), JsonConverter(typeof(EmbedTypeConverter))] | |||||
public EmbedType Type { get; set; } | public EmbedType Type { get; set; } | ||||
[JsonProperty("timestamp")] | [JsonProperty("timestamp")] | ||||
public DateTimeOffset? Timestamp { get; set; } | public DateTimeOffset? Timestamp { get; set; } | ||||
@@ -33,6 +33,8 @@ namespace Discord.API | |||||
public Optional<string> SyncId { get; set; } | public Optional<string> SyncId { get; set; } | ||||
[JsonProperty("session_id")] | [JsonProperty("session_id")] | ||||
public Optional<string> SessionId { get; set; } | public Optional<string> SessionId { get; set; } | ||||
[JsonProperty("Flags")] | |||||
public Optional<ActivityProperties> Flags { get; set; } | |||||
[OnError] | [OnError] | ||||
internal void OnError(StreamingContext context, ErrorContext errorContext) | internal void OnError(StreamingContext context, ErrorContext errorContext) | ||||
@@ -1,4 +1,4 @@ | |||||
#pragma warning disable CS1591 | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
namespace Discord.API | namespace Discord.API | ||||
@@ -23,5 +23,11 @@ namespace Discord.API | |||||
public Optional<string> Email { get; set; } | public Optional<string> Email { get; set; } | ||||
[JsonProperty("mfa_enabled")] | [JsonProperty("mfa_enabled")] | ||||
public Optional<bool> MfaEnabled { get; set; } | public Optional<bool> MfaEnabled { get; set; } | ||||
[JsonProperty("flags")] | |||||
public Optional<UserProperties> Flags { get; set; } | |||||
[JsonProperty("premium_type")] | |||||
public Optional<PremiumType> PremiumType { get; set; } | |||||
[JsonProperty("locale")] | |||||
public Optional<string> Locale { get; set; } | |||||
} | } | ||||
} | } |
@@ -1,4 +1,4 @@ | |||||
#pragma warning disable CS1591 | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
@@ -15,6 +15,6 @@ namespace Discord.API.Rest | |||||
[JsonProperty("roles")] | [JsonProperty("roles")] | ||||
public Optional<ulong[]> RoleIds { get; set; } | public Optional<ulong[]> RoleIds { get; set; } | ||||
[JsonProperty("channel_id")] | [JsonProperty("channel_id")] | ||||
public Optional<ulong> ChannelId { get; set; } | |||||
public Optional<ulong?> ChannelId { get; set; } | |||||
} | } | ||||
} | } |
@@ -376,7 +376,7 @@ namespace Discord.API | |||||
Preconditions.AtLeast(args.Position, 0, nameof(args.Position)); | Preconditions.AtLeast(args.Position, 0, nameof(args.Position)); | ||||
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name)); | Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name)); | ||||
Preconditions.AtLeast(args.SlowModeInterval, 0, nameof(args.SlowModeInterval)); | Preconditions.AtLeast(args.SlowModeInterval, 0, nameof(args.SlowModeInterval)); | ||||
Preconditions.AtMost(args.SlowModeInterval, 120, nameof(args.SlowModeInterval)); | |||||
Preconditions.AtMost(args.SlowModeInterval, 21600, nameof(args.SlowModeInterval)); | |||||
options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
var ids = new BucketIds(channelId: channelId); | var ids = new BucketIds(channelId: channelId); | ||||
@@ -17,6 +17,12 @@ namespace Discord.Rest | |||||
public bool IsVerified { get; private set; } | public bool IsVerified { get; private set; } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public bool IsMfaEnabled { get; private set; } | public bool IsMfaEnabled { get; private set; } | ||||
/// <inheritdoc /> | |||||
public UserProperties Flags { get; private set; } | |||||
/// <inheritdoc /> | |||||
public PremiumType PremiumType { get; private set; } | |||||
/// <inheritdoc /> | |||||
public string Locale { get; private set; } | |||||
internal RestSelfUser(BaseDiscordClient discord, ulong id) | internal RestSelfUser(BaseDiscordClient discord, ulong id) | ||||
: base(discord, id) | : base(discord, id) | ||||
@@ -39,6 +45,12 @@ namespace Discord.Rest | |||||
IsVerified = model.Verified.Value; | IsVerified = model.Verified.Value; | ||||
if (model.MfaEnabled.IsSpecified) | if (model.MfaEnabled.IsSpecified) | ||||
IsMfaEnabled = model.MfaEnabled.Value; | IsMfaEnabled = model.MfaEnabled.Value; | ||||
if (model.Flags.IsSpecified) | |||||
Flags = (UserProperties)model.Flags.Value; | |||||
if (model.PremiumType.IsSpecified) | |||||
PremiumType = model.PremiumType.Value; | |||||
if (model.Locale.IsSpecified) | |||||
Locale = model.Locale.Value; | |||||
} | } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
@@ -1,4 +1,4 @@ | |||||
using Discord.API.Rest; | |||||
using Discord.API.Rest; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
@@ -39,7 +39,7 @@ namespace Discord.Rest | |||||
}; | }; | ||||
if (args.Channel.IsSpecified) | if (args.Channel.IsSpecified) | ||||
apiArgs.ChannelId = args.Channel.Value.Id; | |||||
apiArgs.ChannelId = args.Channel.Value?.Id; | |||||
else if (args.ChannelId.IsSpecified) | else if (args.ChannelId.IsSpecified) | ||||
apiArgs.ChannelId = args.ChannelId.Value; | apiArgs.ChannelId = args.ChannelId.Value; | ||||
@@ -77,6 +77,8 @@ namespace Discord.Net.Converters | |||||
return PermissionTargetConverter.Instance; | return PermissionTargetConverter.Instance; | ||||
if (type == typeof(UserStatus)) | if (type == typeof(UserStatus)) | ||||
return UserStatusConverter.Instance; | return UserStatusConverter.Instance; | ||||
if (type == typeof(EmbedType)) | |||||
return EmbedTypeConverter.Instance; | |||||
//Special | //Special | ||||
if (type == typeof(API.Image)) | if (type == typeof(API.Image)) | ||||
@@ -0,0 +1,73 @@ | |||||
using System; | |||||
using Newtonsoft.Json; | |||||
namespace Discord.Net.Converters | |||||
{ | |||||
internal class EmbedTypeConverter : JsonConverter | |||||
{ | |||||
public static readonly EmbedTypeConverter Instance = new EmbedTypeConverter(); | |||||
public override bool CanConvert(Type objectType) => true; | |||||
public override bool CanRead => true; | |||||
public override bool CanWrite => true; | |||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | |||||
{ | |||||
switch ((string)reader.Value) | |||||
{ | |||||
case "rich": | |||||
return EmbedType.Rich; | |||||
case "link": | |||||
return EmbedType.Link; | |||||
case "video": | |||||
return EmbedType.Video; | |||||
case "image": | |||||
return EmbedType.Image; | |||||
case "gifv": | |||||
return EmbedType.Gifv; | |||||
case "article": | |||||
return EmbedType.Article; | |||||
case "tweet": | |||||
return EmbedType.Tweet; | |||||
case "html": | |||||
return EmbedType.Html; | |||||
case "application_news": // TODO 2.2 EmbedType.News | |||||
default: | |||||
return EmbedType.Unknown; | |||||
} | |||||
} | |||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | |||||
{ | |||||
switch ((EmbedType)value) | |||||
{ | |||||
case EmbedType.Rich: | |||||
writer.WriteValue("rich"); | |||||
break; | |||||
case EmbedType.Link: | |||||
writer.WriteValue("link"); | |||||
break; | |||||
case EmbedType.Video: | |||||
writer.WriteValue("video"); | |||||
break; | |||||
case EmbedType.Image: | |||||
writer.WriteValue("image"); | |||||
break; | |||||
case EmbedType.Gifv: | |||||
writer.WriteValue("gifv"); | |||||
break; | |||||
case EmbedType.Article: | |||||
writer.WriteValue("article"); | |||||
break; | |||||
case EmbedType.Tweet: | |||||
writer.WriteValue("tweet"); | |||||
break; | |||||
case EmbedType.Html: | |||||
writer.WriteValue("html"); | |||||
break; | |||||
default: | |||||
throw new JsonSerializationException("Invalid embed type"); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1295,7 +1295,16 @@ namespace Discord.WebSocket | |||||
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage; | var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage; | ||||
bool isCached = cachedMsg != null; | bool isCached = cachedMsg != null; | ||||
var user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false); | var user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false); | ||||
var reaction = SocketReaction.Create(data, channel, cachedMsg, Optional.Create(user)); | |||||
var optionalMsg = !isCached | |||||
? Optional.Create<SocketUserMessage>() | |||||
: Optional.Create(cachedMsg); | |||||
var optionalUser = user is null | |||||
? Optional.Create<IUser>() | |||||
: Optional.Create(user); | |||||
var reaction = SocketReaction.Create(data, channel, optionalMsg, optionalUser); | |||||
var cacheable = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isCached, async () => await channel.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage); | var cacheable = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isCached, async () => await channel.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage); | ||||
cachedMsg?.AddReaction(reaction); | cachedMsg?.AddReaction(reaction); | ||||
@@ -1319,7 +1328,16 @@ namespace Discord.WebSocket | |||||
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage; | var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage; | ||||
bool isCached = cachedMsg != null; | bool isCached = cachedMsg != null; | ||||
var user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false); | var user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false); | ||||
var reaction = SocketReaction.Create(data, channel, cachedMsg, Optional.Create(user)); | |||||
var optionalMsg = !isCached | |||||
? Optional.Create<SocketUserMessage>() | |||||
: Optional.Create(cachedMsg); | |||||
var optionalUser = user is null | |||||
? Optional.Create<IUser>() | |||||
: Optional.Create(user); | |||||
var reaction = SocketReaction.Create(data, channel, optionalMsg, optionalUser); | |||||
var cacheable = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isCached, async () => await channel.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage); | var cacheable = new Cacheable<IUserMessage, ulong>(cachedMsg, data.MessageId, isCached, async () => await channel.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage); | ||||
cachedMsg?.RemoveReaction(reaction); | cachedMsg?.RemoveReaction(reaction); | ||||
@@ -30,6 +30,12 @@ namespace Discord.WebSocket | |||||
public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } | public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } | ||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } | internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } | ||||
/// <inheritdoc /> | |||||
public UserProperties Flags { get; internal set; } | |||||
/// <inheritdoc /> | |||||
public PremiumType PremiumType { get; internal set; } | |||||
/// <inheritdoc /> | |||||
public string Locale { get; internal set; } | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public override bool IsWebhook => false; | public override bool IsWebhook => false; | ||||
@@ -63,6 +69,21 @@ namespace Discord.WebSocket | |||||
IsMfaEnabled = model.MfaEnabled.Value; | IsMfaEnabled = model.MfaEnabled.Value; | ||||
hasGlobalChanges = true; | hasGlobalChanges = true; | ||||
} | } | ||||
if (model.Flags.IsSpecified && model.Flags.Value != Flags) | |||||
{ | |||||
Flags = (UserProperties)model.Flags.Value; | |||||
hasGlobalChanges = true; | |||||
} | |||||
if (model.PremiumType.IsSpecified && model.PremiumType.Value != PremiumType) | |||||
{ | |||||
PremiumType = model.PremiumType.Value; | |||||
hasGlobalChanges = true; | |||||
} | |||||
if (model.Locale.IsSpecified && model.Locale.Value != Locale) | |||||
{ | |||||
Locale = model.Locale.Value; | |||||
hasGlobalChanges = true; | |||||
} | |||||
return hasGlobalChanges; | return hasGlobalChanges; | ||||
} | } | ||||
@@ -25,7 +25,8 @@ namespace Discord.WebSocket | |||||
Artists = model.State.GetValueOrDefault()?.Split(';').Select(x=>x?.Trim()).ToImmutableArray(), | Artists = model.State.GetValueOrDefault()?.Split(';').Select(x=>x?.Trim()).ToImmutableArray(), | ||||
Duration = timestamps?.End - timestamps?.Start, | Duration = timestamps?.End - timestamps?.Start, | ||||
AlbumArtUrl = albumArtId != null ? CDN.GetSpotifyAlbumArtUrl(albumArtId) : null, | AlbumArtUrl = albumArtId != null ? CDN.GetSpotifyAlbumArtUrl(albumArtId) : null, | ||||
Type = ActivityType.Listening | |||||
Type = ActivityType.Listening, | |||||
Flags = model.Flags.GetValueOrDefault(), | |||||
}; | }; | ||||
} | } | ||||
@@ -44,18 +45,25 @@ namespace Discord.WebSocket | |||||
LargeAsset = assets?[1], | LargeAsset = assets?[1], | ||||
Party = model.Party.IsSpecified ? model.Party.Value.ToEntity() : null, | Party = model.Party.IsSpecified ? model.Party.Value.ToEntity() : null, | ||||
Secrets = model.Secrets.IsSpecified ? model.Secrets.Value.ToEntity() : null, | Secrets = model.Secrets.IsSpecified ? model.Secrets.Value.ToEntity() : null, | ||||
Timestamps = model.Timestamps.IsSpecified ? model.Timestamps.Value.ToEntity() : null | |||||
Timestamps = model.Timestamps.IsSpecified ? model.Timestamps.Value.ToEntity() : null, | |||||
Flags = model.Flags.GetValueOrDefault() | |||||
}; | }; | ||||
} | } | ||||
// Stream Game | // Stream Game | ||||
if (model.StreamUrl.IsSpecified) | if (model.StreamUrl.IsSpecified) | ||||
{ | { | ||||
return new StreamingGame( | return new StreamingGame( | ||||
model.Name, | |||||
model.StreamUrl.Value); | |||||
model.Name, | |||||
model.StreamUrl.Value) | |||||
{ | |||||
Flags = model.Flags.GetValueOrDefault(), | |||||
Details = model.Details.GetValueOrDefault() | |||||
}; | |||||
} | } | ||||
// Normal Game | // Normal Game | ||||
return new Game(model.Name, model.Type.GetValueOrDefault() ?? ActivityType.Playing); | |||||
return new Game(model.Name, model.Type.GetValueOrDefault() ?? ActivityType.Playing, | |||||
model.Flags.IsSpecified ? model.Flags.Value : ActivityProperties.None, | |||||
model.Details.GetValueOrDefault()); | |||||
} | } | ||||
// (Small, Large) | // (Small, Large) | ||||
@@ -2,7 +2,7 @@ | |||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> | <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> | ||||
<metadata> | <metadata> | ||||
<id>Discord.Net</id> | <id>Discord.Net</id> | ||||
<version>2.1.1-dev$suffix$</version> | |||||
<version>2.2.0-dev$suffix$</version> | |||||
<title>Discord.Net</title> | <title>Discord.Net</title> | ||||
<authors>Discord.Net Contributors</authors> | <authors>Discord.Net Contributors</authors> | ||||
<owners>RogueException</owners> | <owners>RogueException</owners> | ||||
@@ -14,25 +14,25 @@ | |||||
<iconUrl>https://github.com/RogueException/Discord.Net/raw/dev/docs/marketing/logo/PackageLogo.png</iconUrl> | <iconUrl>https://github.com/RogueException/Discord.Net/raw/dev/docs/marketing/logo/PackageLogo.png</iconUrl> | ||||
<dependencies> | <dependencies> | ||||
<group targetFramework="net46"> | <group targetFramework="net46"> | ||||
<dependency id="Discord.Net.Core" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Rest" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.WebSocket" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Commands" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Webhook" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Core" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Rest" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.WebSocket" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Commands" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Webhook" version="2.2.0-dev$suffix$" /> | |||||
</group> | </group> | ||||
<group targetFramework="netstandard1.3"> | <group targetFramework="netstandard1.3"> | ||||
<dependency id="Discord.Net.Core" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Rest" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.WebSocket" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Commands" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Webhook" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Core" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Rest" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.WebSocket" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Commands" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Webhook" version="2.2.0-dev$suffix$" /> | |||||
</group> | </group> | ||||
<group targetFramework="netstandard2.0"> | <group targetFramework="netstandard2.0"> | ||||
<dependency id="Discord.Net.Core" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Rest" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.WebSocket" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Commands" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Webhook" version="2.1.1-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Core" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Rest" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.WebSocket" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Commands" version="2.2.0-dev$suffix$" /> | |||||
<dependency id="Discord.Net.Webhook" version="2.2.0-dev$suffix$" /> | |||||
</group> | </group> | ||||
</dependencies> | </dependencies> | ||||
</metadata> | </metadata> | ||||
@@ -0,0 +1,24 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | |||||
<TargetFramework>netcoreapp2.1</TargetFramework> | |||||
<IsPackable>false</IsPackable> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<ProjectReference Include="../../src/Discord.Net.Commands/Discord.Net.Commands.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Core/Discord.Net.Core.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Rest/Discord.Net.Rest.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj" /> | |||||
<ProjectReference Include="..\..\src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.0.0-beta4-final" /> | |||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" /> | |||||
<PackageReference Include="xunit" Version="2.4.0" /> | |||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> | |||||
</ItemGroup> | |||||
</Project> |
@@ -0,0 +1,163 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
using Xunit.Abstractions; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Tests that channels can be created and modified. | |||||
/// </summary> | |||||
[CollectionDefinition("ChannelsTests", DisableParallelization = true)] | |||||
public class ChannelsTests : IClassFixture<RestGuildFixture> | |||||
{ | |||||
private IGuild guild; | |||||
private readonly ITestOutputHelper output; | |||||
public ChannelsTests(RestGuildFixture guildFixture, ITestOutputHelper output) | |||||
{ | |||||
guild = guildFixture.Guild; | |||||
this.output = output; | |||||
output.WriteLine($"RestGuildFixture using guild: {guild.Id}"); | |||||
// capture all console output | |||||
guildFixture.Client.Log += LogAsync; | |||||
} | |||||
private Task LogAsync(LogMessage message) | |||||
{ | |||||
output.WriteLine(message.ToString()); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Checks that a text channel can be created and modified. | |||||
/// </summary> | |||||
[Fact] | |||||
public async Task ModifyTextChannel() | |||||
{ | |||||
// create a text channel to modify | |||||
var channel = await guild.CreateTextChannelAsync("text"); | |||||
try | |||||
{ | |||||
Assert.NotNull(channel); | |||||
// check that it can be modified | |||||
await channel.ModifyAsync(x => | |||||
{ | |||||
x.IsNsfw = true; | |||||
x.Name = "updated"; | |||||
x.SlowModeInterval = 50; | |||||
x.Topic = "topic"; | |||||
x.CategoryId = null; | |||||
}); | |||||
// check the results of modifying this channel | |||||
Assert.True(channel.IsNsfw); | |||||
Assert.Equal("updated", channel.Name); | |||||
Assert.Equal(50, channel.SlowModeInterval); | |||||
Assert.Equal("topic", channel.Topic); | |||||
Assert.Null(channel.CategoryId); | |||||
} | |||||
finally | |||||
{ | |||||
// delete the channel when finished | |||||
await channel?.DeleteAsync(); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Checks that a voice channel can be created, modified, and deleted. | |||||
/// </summary> | |||||
[Fact] | |||||
public async Task ModifyVoiceChannel() | |||||
{ | |||||
var channel = await guild.CreateVoiceChannelAsync("voice"); | |||||
try | |||||
{ | |||||
Assert.NotNull(channel); | |||||
// try to modify it | |||||
await channel.ModifyAsync(x => | |||||
{ | |||||
x.Bitrate = 9001; | |||||
x.Name = "updated"; | |||||
x.UserLimit = 1; | |||||
}); | |||||
// check that these were updated | |||||
Assert.Equal(9001, channel.Bitrate); | |||||
Assert.Equal("updated", channel.Name); | |||||
Assert.Equal(1, channel.UserLimit); | |||||
} | |||||
finally | |||||
{ | |||||
// delete the channel when done | |||||
await channel.DeleteAsync(); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Creates a category channel, a voice channel, and a text channel, then tries to assign them under that category. | |||||
/// </summary> | |||||
[Fact] | |||||
public async Task ModifyChannelCategories() | |||||
{ | |||||
// util method for checking if a category is set | |||||
async Task CheckAsync(INestedChannel channel, ICategoryChannel cat) | |||||
{ | |||||
// check that the category is not set | |||||
if (cat == null) | |||||
{ | |||||
Assert.Null(channel.CategoryId); | |||||
Assert.Null(await channel.GetCategoryAsync()); | |||||
} | |||||
else | |||||
{ | |||||
Assert.NotNull(channel.CategoryId); | |||||
Assert.Equal(cat.Id, channel.CategoryId); | |||||
var getCat = await channel.GetCategoryAsync(); | |||||
Assert.NotNull(getCat); | |||||
Assert.Equal(cat.Id, getCat.Id); | |||||
} | |||||
} | |||||
// initially create these not under the category | |||||
var category = await guild.CreateCategoryAsync("category"); | |||||
var text = await guild.CreateTextChannelAsync("text"); | |||||
var voice = await guild.CreateVoiceChannelAsync("voice"); | |||||
try | |||||
{ | |||||
Assert.NotNull(category); | |||||
Assert.NotNull(text); | |||||
Assert.NotNull(voice); | |||||
// check that the category is not set for either | |||||
await CheckAsync(text, null); | |||||
await CheckAsync(voice, null); | |||||
// set the category | |||||
await text.ModifyAsync(x => x.CategoryId = category.Id); | |||||
await voice.ModifyAsync(x => x.CategoryId = category.Id); | |||||
// check that this is set, and that it's the category that was created earlier | |||||
await CheckAsync(text, category); | |||||
await CheckAsync(voice, category); | |||||
// create one more channel immediately under this category | |||||
var newText = await guild.CreateTextChannelAsync("new-text", x => x.CategoryId = category.Id); | |||||
try | |||||
{ | |||||
Assert.NotNull(newText); | |||||
await CheckAsync(newText, category); | |||||
} | |||||
finally | |||||
{ | |||||
await newText?.DeleteAsync(); | |||||
} | |||||
} | |||||
finally | |||||
{ | |||||
// clean up | |||||
await category?.DeleteAsync(); | |||||
await text?.DeleteAsync(); | |||||
await voice?.DeleteAsync(); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,27 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | |||||
<TargetFramework>netcoreapp2.1</TargetFramework> | |||||
<IsPackable>false</IsPackable> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<ProjectReference Include="../../src/Discord.Net.Commands/Discord.Net.Commands.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Core/Discord.Net.Core.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Rest/Discord.Net.Rest.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj" /> | |||||
<ProjectReference Include="..\..\src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" /> | |||||
<PackageReference Include="xunit" Version="2.4.0" /> | |||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Folder Include="Properties\" /> | |||||
</ItemGroup> | |||||
</Project> |
@@ -0,0 +1,34 @@ | |||||
using Discord.Rest; | |||||
using System; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Test fixture type for integration tests which sets up the client from | |||||
/// the token provided in environment variables. | |||||
/// </summary> | |||||
public class DiscordRestClientFixture : IDisposable | |||||
{ | |||||
public DiscordRestClient Client { get; private set; } | |||||
public DiscordRestClientFixture() | |||||
{ | |||||
var token = Environment.GetEnvironmentVariable("DNET_TEST_TOKEN", EnvironmentVariableTarget.Machine); | |||||
if (string.IsNullOrWhiteSpace(token)) | |||||
throw new Exception("The DNET_TEST_TOKEN environment variable was not provided."); | |||||
Client = new DiscordRestClient(new DiscordRestConfig() | |||||
{ | |||||
LogLevel = LogSeverity.Debug, | |||||
DefaultRetryMode = RetryMode.AlwaysRetry | |||||
}); | |||||
Client.LoginAsync(TokenType.Bot, token).Wait(); | |||||
} | |||||
public void Dispose() | |||||
{ | |||||
Client.LogoutAsync().Wait(); | |||||
Client.Dispose(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,114 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
using Xunit.Abstractions; | |||||
namespace Discord | |||||
{ | |||||
[CollectionDefinition("GuildTests", DisableParallelization = true)] | |||||
public class GuildTests : IClassFixture<RestGuildFixture> | |||||
{ | |||||
private IDiscordClient client; | |||||
private IGuild guild; | |||||
private readonly ITestOutputHelper output; | |||||
public GuildTests(RestGuildFixture guildFixture, ITestOutputHelper output) | |||||
{ | |||||
client = guildFixture.Client; | |||||
guild = guildFixture.Guild; | |||||
this.output = output; | |||||
output.WriteLine($"RestGuildFixture using guild: {guild.Id}"); | |||||
guildFixture.Client.Log += LogAsync; | |||||
} | |||||
private Task LogAsync(LogMessage message) | |||||
{ | |||||
output.WriteLine(message.ToString()); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Ensures that the CurrentUser is the owner of the guild. | |||||
/// </summary> | |||||
[Fact] | |||||
public void CheckOwner() | |||||
{ | |||||
Assert.Equal(client.CurrentUser.Id, guild.OwnerId); | |||||
} | |||||
/// <summary> | |||||
/// Checks that a Guild can be modified to non-default values. | |||||
/// </summary> | |||||
[Fact] | |||||
public async Task ModifyGuild() | |||||
{ | |||||
// set some initial properties of the guild that are not the defaults | |||||
await guild.ModifyAsync(x => | |||||
{ | |||||
x.ExplicitContentFilter = ExplicitContentFilterLevel.AllMembers; | |||||
x.Name = "updated"; | |||||
x.DefaultMessageNotifications = DefaultMessageNotifications.MentionsOnly; | |||||
x.AfkTimeout = 900; // 15 minutes | |||||
x.VerificationLevel = VerificationLevel.None; | |||||
}); | |||||
// check that they were set | |||||
Assert.Equal("updated", guild.Name); | |||||
Assert.Equal(ExplicitContentFilterLevel.AllMembers, guild.ExplicitContentFilter); | |||||
Assert.Equal(DefaultMessageNotifications.MentionsOnly, guild.DefaultMessageNotifications); | |||||
Assert.Equal(VerificationLevel.None, guild.VerificationLevel); | |||||
Assert.Equal(900, guild.AFKTimeout); | |||||
} | |||||
/// <summary> | |||||
/// Checks that the SystemChannel property of a guild can be modified. | |||||
/// </summary> | |||||
[Fact] | |||||
public async Task ModifySystemChannel() | |||||
{ | |||||
var systemChannel = await guild.CreateTextChannelAsync("system"); | |||||
// set using the Id | |||||
await guild.ModifyAsync(x => x.SystemChannelId = systemChannel.Id); | |||||
Assert.Equal(systemChannel.Id, guild.SystemChannelId); | |||||
// unset it | |||||
await guild.ModifyAsync(x => x.SystemChannelId = null); | |||||
Assert.Null(guild.SystemChannelId); | |||||
Assert.Null(await guild.GetSystemChannelAsync()); | |||||
// set using the ITextChannel | |||||
await guild.ModifyAsync(x => { x.SystemChannel = new Optional<ITextChannel>(systemChannel); }); | |||||
Assert.Equal(systemChannel.Id, guild.SystemChannelId); | |||||
await Assert.ThrowsAsync<NullReferenceException>( async () => | |||||
{ | |||||
await guild.ModifyAsync(x => x.SystemChannel = null); | |||||
}); | |||||
await systemChannel.DeleteAsync(); | |||||
} | |||||
/// <summary> | |||||
/// Checks that the AFK channel of a guild can be set. | |||||
/// </summary> | |||||
[Fact] | |||||
public async Task ModifyAfkChannel() | |||||
{ | |||||
var afkChannel = await guild.CreateVoiceChannelAsync("afk"); | |||||
// set using the Id | |||||
await guild.ModifyAsync(x => x.AfkChannelId = afkChannel.Id); | |||||
Assert.Equal(afkChannel.Id, guild.AFKChannelId); | |||||
// unset using Id | |||||
await guild.ModifyAsync(x => x.AfkChannelId = null); | |||||
Assert.Null(guild.AFKChannelId); | |||||
Assert.Null(await guild.GetAFKChannelAsync()); | |||||
// the same, but with the AfkChannel property | |||||
await guild.ModifyAsync(x => x.AfkChannel = new Optional<IVoiceChannel>(afkChannel)); | |||||
Assert.Equal(afkChannel.Id, guild.AFKChannelId); | |||||
await Assert.ThrowsAsync<NullReferenceException>( async () => | |||||
{ | |||||
await guild.ModifyAsync(x => x.AfkChannel = null); | |||||
}); | |||||
await afkChannel.DeleteAsync(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,44 @@ | |||||
using Discord.Rest; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Linq; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Gets or creates a guild to use for testing. | |||||
/// </summary> | |||||
public class RestGuildFixture : DiscordRestClientFixture | |||||
{ | |||||
public RestGuild Guild { get; private set; } | |||||
public RestGuildFixture() : base() | |||||
{ | |||||
var guilds = Client.GetGuildsAsync().Result.Where(x => x.OwnerId == Client.CurrentUser.Id).ToList(); | |||||
if (guilds.Count == 0) | |||||
{ | |||||
// create a new guild if none exists already | |||||
var region = Client.GetOptimalVoiceRegionAsync().Result; | |||||
Guild = Client.CreateGuildAsync("DNET INTEGRATION TEST", region).Result; | |||||
RemoveAllChannels(); | |||||
} | |||||
else | |||||
{ | |||||
// get the first one if there is a guild already created | |||||
Guild = guilds.First(); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Removes all channels in the guild. | |||||
/// </summary> | |||||
private void RemoveAllChannels() | |||||
{ | |||||
foreach (var channel in Guild.GetChannelsAsync().Result) | |||||
{ | |||||
channel.DeleteAsync().Wait(); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,223 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Tests the behavior of the <see cref="Discord.ChannelPermissions"/> type and related functions. | |||||
/// </summary> | |||||
public class ChannelPermissionsTests | |||||
{ | |||||
/// <summary> | |||||
/// Tests the default value of the <see cref="Discord.ChannelPermissions"/> constructor. | |||||
/// </summary> | |||||
[Fact] | |||||
public void DefaultConstructor() | |||||
{ | |||||
var permission = new ChannelPermissions(); | |||||
Assert.Equal((ulong)0, permission.RawValue); | |||||
Assert.Equal(ChannelPermissions.None.RawValue, permission.RawValue); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of the <see cref="Discord.ChannelPermission"/> raw value constructor. | |||||
/// </summary> | |||||
[Fact] | |||||
public void RawValueConstructor() | |||||
{ | |||||
// returns all of the values that will be tested | |||||
// a Theory cannot be used here, because these values are not all constants | |||||
IEnumerable<ulong> GetTestValues() | |||||
{ | |||||
yield return 0; | |||||
yield return ChannelPermissions.Category.RawValue; | |||||
yield return ChannelPermissions.DM.RawValue; | |||||
yield return ChannelPermissions.Group.RawValue; | |||||
yield return ChannelPermissions.None.RawValue; | |||||
yield return ChannelPermissions.Text.RawValue; | |||||
yield return ChannelPermissions.Voice.RawValue; | |||||
}; | |||||
foreach (var rawValue in GetTestValues()) | |||||
{ | |||||
var p = new ChannelPermissions(rawValue); | |||||
Assert.Equal(rawValue, p.RawValue); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of the <see cref="Discord.ChannelPermissions"/> constructor for each | |||||
/// of it's flags. | |||||
/// </summary> | |||||
[Fact] | |||||
public void FlagsConstructor() | |||||
{ | |||||
// util method for asserting that the constructor sets the given flag | |||||
void AssertFlag(Func<ChannelPermissions> cstr, ChannelPermission flag) | |||||
{ | |||||
var p = cstr(); | |||||
// ensure that this flag is set to true | |||||
Assert.True(p.Has(flag)); | |||||
// ensure that only this flag is set | |||||
Assert.Equal((ulong)flag, p.RawValue); | |||||
} | |||||
AssertFlag(() => new ChannelPermissions(createInstantInvite: true), ChannelPermission.CreateInstantInvite); | |||||
AssertFlag(() => new ChannelPermissions(manageChannel: true), ChannelPermission.ManageChannels); | |||||
AssertFlag(() => new ChannelPermissions(addReactions: true), ChannelPermission.AddReactions); | |||||
AssertFlag(() => new ChannelPermissions(viewChannel: true), ChannelPermission.ViewChannel); | |||||
AssertFlag(() => new ChannelPermissions(sendMessages: true), ChannelPermission.SendMessages); | |||||
AssertFlag(() => new ChannelPermissions(sendTTSMessages: true), ChannelPermission.SendTTSMessages); | |||||
AssertFlag(() => new ChannelPermissions(manageMessages: true), ChannelPermission.ManageMessages); | |||||
AssertFlag(() => new ChannelPermissions(embedLinks: true), ChannelPermission.EmbedLinks); | |||||
AssertFlag(() => new ChannelPermissions(attachFiles: true), ChannelPermission.AttachFiles); | |||||
AssertFlag(() => new ChannelPermissions(readMessageHistory: true), ChannelPermission.ReadMessageHistory); | |||||
AssertFlag(() => new ChannelPermissions(mentionEveryone: true), ChannelPermission.MentionEveryone); | |||||
AssertFlag(() => new ChannelPermissions(useExternalEmojis: true), ChannelPermission.UseExternalEmojis); | |||||
AssertFlag(() => new ChannelPermissions(connect: true), ChannelPermission.Connect); | |||||
AssertFlag(() => new ChannelPermissions(speak: true), ChannelPermission.Speak); | |||||
AssertFlag(() => new ChannelPermissions(muteMembers: true), ChannelPermission.MuteMembers); | |||||
AssertFlag(() => new ChannelPermissions(deafenMembers: true), ChannelPermission.DeafenMembers); | |||||
AssertFlag(() => new ChannelPermissions(moveMembers: true), ChannelPermission.MoveMembers); | |||||
AssertFlag(() => new ChannelPermissions(useVoiceActivation: true), ChannelPermission.UseVAD); | |||||
AssertFlag(() => new ChannelPermissions(prioritySpeaker: true), ChannelPermission.PrioritySpeaker); | |||||
AssertFlag(() => new ChannelPermissions(manageRoles: true), ChannelPermission.ManageRoles); | |||||
AssertFlag(() => new ChannelPermissions(manageWebhooks: true), ChannelPermission.ManageWebhooks); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="Discord.ChannelPermissions.Modify(bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?)"/> | |||||
/// with each of the parameters. | |||||
/// </summary> | |||||
[Fact] | |||||
public void Modify() | |||||
{ | |||||
// asserts that a channel permission flag value can be checked | |||||
// and that modify can set and unset each flag | |||||
// and that ToList performs as expected | |||||
void AssertUtil(ChannelPermission permission, | |||||
Func<ChannelPermissions, bool> has, | |||||
Func<ChannelPermissions, bool, ChannelPermissions> modify) | |||||
{ | |||||
var perm = new ChannelPermissions(); | |||||
// ensure permission initially false | |||||
// use both the function and Has to ensure that the GetPermission | |||||
// function is working | |||||
Assert.False(has(perm)); | |||||
Assert.False(perm.Has(permission)); | |||||
// enable it, and ensure that it gets set | |||||
perm = modify(perm, true); | |||||
Assert.True(has(perm)); | |||||
Assert.True(perm.Has(permission)); | |||||
// check ToList behavior | |||||
var list = perm.ToList(); | |||||
Assert.Contains(permission, list); | |||||
Assert.Single(list); | |||||
// set it false again | |||||
perm = modify(perm, false); | |||||
Assert.False(has(perm)); | |||||
Assert.False(perm.Has(permission)); | |||||
// ensure that no perms are set now | |||||
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue); | |||||
} | |||||
AssertUtil(ChannelPermission.CreateInstantInvite, x => x.CreateInstantInvite, (p, enable) => p.Modify(createInstantInvite: enable)); | |||||
AssertUtil(ChannelPermission.ManageChannels, x => x.ManageChannel, (p, enable) => p.Modify(manageChannel: enable)); | |||||
AssertUtil(ChannelPermission.AddReactions, x => x.AddReactions, (p, enable) => p.Modify(addReactions: enable)); | |||||
AssertUtil(ChannelPermission.ViewChannel, x => x.ViewChannel, (p, enable) => p.Modify(viewChannel: enable)); | |||||
AssertUtil(ChannelPermission.SendMessages, x => x.SendMessages, (p, enable) => p.Modify(sendMessages: enable)); | |||||
AssertUtil(ChannelPermission.SendTTSMessages, x => x.SendTTSMessages, (p, enable) => p.Modify(sendTTSMessages: enable)); | |||||
AssertUtil(ChannelPermission.ManageMessages, x => x.ManageMessages, (p, enable) => p.Modify(manageMessages: enable)); | |||||
AssertUtil(ChannelPermission.EmbedLinks, x => x.EmbedLinks, (p, enable) => p.Modify(embedLinks: enable)); | |||||
AssertUtil(ChannelPermission.AttachFiles, x => x.AttachFiles, (p, enable) => p.Modify(attachFiles: enable)); | |||||
AssertUtil(ChannelPermission.ReadMessageHistory, x => x.ReadMessageHistory, (p, enable) => p.Modify(readMessageHistory: enable)); | |||||
AssertUtil(ChannelPermission.MentionEveryone, x => x.MentionEveryone, (p, enable) => p.Modify(mentionEveryone: enable)); | |||||
AssertUtil(ChannelPermission.UseExternalEmojis, x => x.UseExternalEmojis, (p, enable) => p.Modify(useExternalEmojis: enable)); | |||||
AssertUtil(ChannelPermission.Connect, x => x.Connect, (p, enable) => p.Modify(connect: enable)); | |||||
AssertUtil(ChannelPermission.Speak, x => x.Speak, (p, enable) => p.Modify(speak: enable)); | |||||
AssertUtil(ChannelPermission.MuteMembers, x => x.MuteMembers, (p, enable) => p.Modify(muteMembers: enable)); | |||||
AssertUtil(ChannelPermission.DeafenMembers, x => x.DeafenMembers, (p, enable) => p.Modify(deafenMembers: enable)); | |||||
AssertUtil(ChannelPermission.MoveMembers, x => x.MoveMembers, (p, enable) => p.Modify(moveMembers: enable)); | |||||
AssertUtil(ChannelPermission.UseVAD, x => x.UseVAD, (p, enable) => p.Modify(useVoiceActivation: enable)); | |||||
AssertUtil(ChannelPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable)); | |||||
AssertUtil(ChannelPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable)); | |||||
AssertUtil(ChannelPermission.PrioritySpeaker, x => x.PrioritySpeaker, (p, enable) => p.Modify(prioritySpeaker: enable)); | |||||
} | |||||
/// <summary> | |||||
/// Tests that <see cref="ChannelPermissions.All(IChannel)"/> for a null channel will throw an <see cref="ArgumentException"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void ChannelTypeResolution_Null() | |||||
{ | |||||
Assert.Throws<ArgumentException>(() => | |||||
{ | |||||
ChannelPermissions.All(null); | |||||
}); | |||||
} | |||||
/// <summary> | |||||
/// Tests that <see cref="ChannelPermissions.All(IChannel)"/> for an <see cref="ITextChannel"/> will return a value | |||||
/// equivalent to <see cref="ChannelPermissions.Text"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void ChannelTypeResolution_Text() | |||||
{ | |||||
Assert.Equal(ChannelPermissions.Text.RawValue, ChannelPermissions.All(new MockedTextChannel()).RawValue); | |||||
} | |||||
/// <summary> | |||||
/// Tests that <see cref="ChannelPermissions.All(IChannel)"/> for an <see cref="IVoiceChannel"/> will return a value | |||||
/// equivalent to <see cref="ChannelPermissions.Voice"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void ChannelTypeResolution_Voice() | |||||
{ | |||||
Assert.Equal(ChannelPermissions.Voice.RawValue, ChannelPermissions.All(new MockedVoiceChannel()).RawValue); | |||||
} | |||||
/// <summary> | |||||
/// Tests that <see cref="ChannelPermissions.All(IChannel)"/> for an <see cref="ICategoryChannel"/> will return a value | |||||
/// equivalent to <see cref="ChannelPermissions.Category"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void ChannelTypeResolution_Category() | |||||
{ | |||||
Assert.Equal(ChannelPermissions.Category.RawValue, ChannelPermissions.All(new MockedCategoryChannel()).RawValue); | |||||
} | |||||
/// <summary> | |||||
/// Tests that <see cref="ChannelPermissions.All(IChannel)"/> for an <see cref="IDMChannel"/> will return a value | |||||
/// equivalent to <see cref="ChannelPermissions.DM"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void ChannelTypeResolution_DM() | |||||
{ | |||||
Assert.Equal(ChannelPermissions.DM.RawValue, ChannelPermissions.All(new MockedDMChannel()).RawValue); | |||||
} | |||||
/// <summary> | |||||
/// Tests that <see cref="ChannelPermissions.All(IChannel)"/> for an <see cref="IGroupChannel"/> will return a value | |||||
/// equivalent to <see cref="ChannelPermissions.Group"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void ChannelTypeResolution_Group() | |||||
{ | |||||
Assert.Equal(ChannelPermissions.Group.RawValue, ChannelPermissions.All(new MockedGroupChannel()).RawValue); | |||||
} | |||||
/// <summary> | |||||
/// Tests that <see cref="ChannelPermissions.All(IChannel)"/> for an invalid channel will throw an <see cref="ArgumentException"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void ChannelTypeResolution_Invalid() | |||||
{ | |||||
Assert.Throws<ArgumentException>(() => ChannelPermissions.All(new MockedInvalidChannel())); | |||||
} | |||||
} | |||||
} |
@@ -1,8 +1,13 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Xunit; | using Xunit; | ||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | |||||
/// Tests for the <see cref="Discord.Color"/> type. | |||||
/// </summary> | |||||
public class ColorTests | public class ColorTests | ||||
{ | { | ||||
[Fact] | [Fact] |
@@ -0,0 +1,21 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | |||||
<TargetFramework>netcoreapp2.1</TargetFramework> | |||||
<IsPackable>false</IsPackable> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<ProjectReference Include="../../src/Discord.Net.Commands/Discord.Net.Commands.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Core/Discord.Net.Core.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Rest/Discord.Net.Rest.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj" /> | |||||
<ProjectReference Include="..\..\src\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" /> | |||||
<PackageReference Include="xunit" Version="2.4.0" /> | |||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> | |||||
</ItemGroup> | |||||
</Project> |
@@ -0,0 +1,467 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Tests the <see cref="Discord.EmbedBuilder"/> class. | |||||
/// </summary> | |||||
public class EmbedBuilderTests | |||||
{ | |||||
private const string name = "chrisj"; | |||||
private const string icon = "https://meowpuffygottem.fun/blob.png"; | |||||
private const string url = "https://meowpuffygottem.fun/"; | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="EmbedBuilder.WithAuthor(string, string, string)"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void WithAuthor_Strings() | |||||
{ | |||||
var builder = new EmbedBuilder(); | |||||
// null by default | |||||
Assert.Null(builder.Author); | |||||
builder = new EmbedBuilder() | |||||
.WithAuthor(name, icon, url); | |||||
Assert.NotNull(builder.Author); | |||||
Assert.Equal(name, builder.Author.Name); | |||||
Assert.Equal(icon, builder.Author.IconUrl); | |||||
Assert.Equal(url, builder.Author.Url); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="EmbedBuilder.WithAuthor(EmbedAuthorBuilder)"/> | |||||
/// </summary> | |||||
[Fact] | |||||
public void WithAuthor_AuthorBuilder() | |||||
{ | |||||
var author = new EmbedAuthorBuilder() | |||||
.WithIconUrl(icon) | |||||
.WithName(name) | |||||
.WithUrl(url); | |||||
var builder = new EmbedBuilder() | |||||
.WithAuthor(author); | |||||
Assert.NotNull(builder.Author); | |||||
Assert.Equal(name, builder.Author.Name); | |||||
Assert.Equal(icon, builder.Author.IconUrl); | |||||
Assert.Equal(url, builder.Author.Url); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="EmbedBuilder.WithAuthor(Action{EmbedAuthorBuilder})"/> | |||||
/// </summary> | |||||
[Fact] | |||||
public void WithAuthor_ActionAuthorBuilder() | |||||
{ | |||||
var builder = new EmbedBuilder() | |||||
.WithAuthor((author) => | |||||
author.WithIconUrl(icon) | |||||
.WithName(name) | |||||
.WithUrl(url)); | |||||
Assert.NotNull(builder.Author); | |||||
Assert.Equal(name, builder.Author.Name); | |||||
Assert.Equal(icon, builder.Author.IconUrl); | |||||
Assert.Equal(url, builder.Author.Url); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="EmbedAuthorBuilder"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void EmbedAuthorBuilder() | |||||
{ | |||||
var builder = new EmbedAuthorBuilder() | |||||
.WithIconUrl(icon) | |||||
.WithName(name) | |||||
.WithUrl(url); | |||||
Assert.Equal(icon, builder.IconUrl); | |||||
Assert.Equal(name, builder.Name); | |||||
Assert.Equal(url, builder.Url); | |||||
} | |||||
/// <summary> | |||||
/// Tests that invalid titles throw an <see cref="ArgumentException"/>. | |||||
/// </summary> | |||||
/// <param name="title">The embed title to set.</param> | |||||
[Theory] | |||||
// 257 chars | |||||
[InlineData("jVyLChmA7aBZozXQuZ3VDEcwW6zOq0nteOVYBZi31ny73rpXfSSBXR4Jw6FiplDKQseKskwRMuBZkUewrewqAbkBZpslHirvC5nEzRySoDIdTRnkVvTXZUXg75l3bQCjuuHxDd6DfrY8ihd6yZX1Y0XFeg239YBcYV4TpL9uQ8H3HFYxrWhLlG2PRVjUmiglP5iXkawszNwMVm1SZ5LZT4jkMZHxFegVi7170d16iaPWOovu50aDDHy087XBtLKVa")] | |||||
// 257 chars of whitespace | |||||
[InlineData(" ")] | |||||
public void Title_Invalid(string title) | |||||
{ | |||||
Assert.Throws<ArgumentException>(() => | |||||
{ | |||||
var builder = new EmbedBuilder(); | |||||
builder.Title = title; | |||||
}); | |||||
Assert.Throws<ArgumentException>(() => | |||||
{ | |||||
new EmbedBuilder().WithTitle(title); | |||||
}); | |||||
} | |||||
/// <summary> | |||||
/// Tests that valid titles do not throw any exceptions. | |||||
/// </summary> | |||||
/// <param name="title">The embed title to set.</param> | |||||
[Theory] | |||||
// 256 chars | |||||
[InlineData("jVyLChmA7aBZozXQuZ3VDEcwW6zOq0nteOVYBZi31ny73rpXfSSBXR4Jw6FiplDKQseKskwRMuBZkUewrewqAbkBZpslHirvC5nEzRySoDIdTRnkVvTXZUXg75l3bQCjuuHxDd6DfrY8ihd6yZX1Y0XFeg239YBcYV4TpL9uQ8H3HFYxrWhLlG2PRVjUmiglP5iXkawszNwMVm1SZ5LZT4jkMZHxFegVi7170d16iaPWOovu50aDDHy087XBtLKV")] | |||||
public void Tile_Valid(string title) | |||||
{ | |||||
var builder = new EmbedBuilder(); | |||||
builder.Title = title; | |||||
new EmbedBuilder().WithTitle(title); | |||||
} | |||||
/// <summary> | |||||
/// Tests that invalid descriptions throw an <see cref="ArgumentException"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void Description_Invalid() | |||||
{ | |||||
IEnumerable<string> GetInvalid() | |||||
{ | |||||
yield return new string('a', 2049); | |||||
} | |||||
foreach (var description in GetInvalid()) | |||||
{ | |||||
Assert.Throws<ArgumentException>(() => new EmbedBuilder().WithDescription(description)); | |||||
Assert.Throws<ArgumentException>(() => | |||||
{ | |||||
var b = new EmbedBuilder(); | |||||
b.Description = description; | |||||
}); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Tests that valid descriptions do not throw any exceptions. | |||||
/// </summary> | |||||
[Fact] | |||||
public void Description_Valid() | |||||
{ | |||||
IEnumerable<string> GetValid() | |||||
{ | |||||
yield return string.Empty; | |||||
yield return null; | |||||
yield return new string('a', 2048); | |||||
} | |||||
foreach (var description in GetValid()) | |||||
{ | |||||
var b = new EmbedBuilder().WithDescription(description); | |||||
Assert.Equal(description, b.Description); | |||||
b = new EmbedBuilder(); | |||||
b.Description = description; | |||||
Assert.Equal(description, b.Description); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Tests that valid urls do not throw any exceptions. | |||||
/// </summary> | |||||
/// <param name="url">The url to set.</param> | |||||
[Theory] | |||||
[InlineData(null)] | |||||
[InlineData("")] | |||||
[InlineData("https://docs.stillu.cc")] | |||||
public void Url_Valid(string url) | |||||
{ | |||||
// does not throw an exception | |||||
var result = new EmbedBuilder() | |||||
.WithUrl(url) | |||||
.WithImageUrl(url) | |||||
.WithThumbnailUrl(url); | |||||
Assert.Equal(result.Url, url); | |||||
Assert.Equal(result.ImageUrl, url); | |||||
Assert.Equal(result.ThumbnailUrl, url); | |||||
result = new EmbedBuilder(); | |||||
result.Url = url; | |||||
result.ImageUrl = url; | |||||
result.ThumbnailUrl = url; | |||||
Assert.Equal(result.Url, url); | |||||
Assert.Equal(result.ImageUrl, url); | |||||
Assert.Equal(result.ThumbnailUrl, url); | |||||
} | |||||
/// <summary> | |||||
/// Tests that invalid urls throw an <see cref="ArgumentException"/>. | |||||
/// </summary> | |||||
/// <param name="url">The url to set.</param> | |||||
[Theory] | |||||
[InlineData(" ")] | |||||
[InlineData("not a url")] | |||||
public void Url_Invalid(string url) | |||||
{ | |||||
Assert.Throws<ArgumentException>(() | |||||
=> new EmbedBuilder() | |||||
.WithUrl(url)); | |||||
Assert.Throws<ArgumentException>(() | |||||
=> new EmbedBuilder() | |||||
.WithImageUrl(url)); | |||||
Assert.Throws<ArgumentException>(() | |||||
=> new EmbedBuilder() | |||||
.WithThumbnailUrl(url)); | |||||
Assert.Throws<ArgumentException>(() => | |||||
{ | |||||
var b = new EmbedBuilder(); | |||||
b.Url = url; | |||||
}); | |||||
Assert.Throws<ArgumentException>(() => | |||||
{ | |||||
var b = new EmbedBuilder(); | |||||
b.ImageUrl = url; | |||||
}); | |||||
Assert.Throws<ArgumentException>(() => | |||||
{ | |||||
var b = new EmbedBuilder(); | |||||
b.ThumbnailUrl = url; | |||||
}); | |||||
} | |||||
/// <summary> | |||||
/// Tests the value of the <see cref="EmbedBuilder.Length"/> property when there are no fields set. | |||||
/// </summary> | |||||
[Fact] | |||||
public void Length_Empty() | |||||
{ | |||||
var empty = new EmbedBuilder(); | |||||
Assert.Equal(0, empty.Length); | |||||
} | |||||
/// <summary> | |||||
/// Tests the value of the <see cref="EmbedBuilder.Length"/> property when all fields are set. | |||||
/// </summary> | |||||
[Fact] | |||||
public void Length() | |||||
{ | |||||
var e = new EmbedBuilder() | |||||
.WithAuthor(name, icon, url) | |||||
.WithColor(Color.Blue) | |||||
.WithDescription("This is the test description.") | |||||
.WithFooter("This is the footer", url) | |||||
.WithImageUrl(url) | |||||
.WithThumbnailUrl(url) | |||||
.WithTimestamp(DateTime.MinValue) | |||||
.WithTitle("This is the title") | |||||
.WithUrl(url) | |||||
.AddField("Field 1", "Inline", true) | |||||
.AddField("Field 2", "Not Inline", false); | |||||
Assert.Equal(100, e.Length); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="EmbedBuilder.WithCurrentTimestamp"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void WithCurrentTimestamp() | |||||
{ | |||||
var e = new EmbedBuilder() | |||||
.WithCurrentTimestamp(); | |||||
// ensure within a second of accuracy | |||||
Assert.Equal(DateTime.UtcNow, e.Timestamp.Value.UtcDateTime, TimeSpan.FromSeconds(1)); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="EmbedBuilder.WithColor(Color)"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void WithColor() | |||||
{ | |||||
// use WithColor | |||||
var e = new EmbedBuilder().WithColor(Color.Red); | |||||
Assert.Equal(Color.Red.RawValue, e.Color.Value.RawValue); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="EmbedBuilder.WithFooter(Action{EmbedFooterBuilder})"/> | |||||
/// </summary> | |||||
[Fact] | |||||
public void WithFooter_ActionFooterBuilder() | |||||
{ | |||||
var e = new EmbedBuilder() | |||||
.WithFooter(x => | |||||
{ | |||||
x.IconUrl = url; | |||||
x.Text = name; | |||||
}); | |||||
Assert.Equal(url, e.Footer.IconUrl); | |||||
Assert.Equal(name, e.Footer.Text); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="EmbedBuilder.WithFooter(EmbedFooterBuilder)"/> | |||||
/// </summary> | |||||
[Fact] | |||||
public void WithFooter_FooterBuilder() | |||||
{ | |||||
var footer = new EmbedFooterBuilder() | |||||
{ | |||||
IconUrl = url, | |||||
Text = name | |||||
}; | |||||
var e = new EmbedBuilder() | |||||
.WithFooter(footer); | |||||
Assert.Equal(url, e.Footer.IconUrl); | |||||
Assert.Equal(name, e.Footer.Text); | |||||
// use the property | |||||
e = new EmbedBuilder(); | |||||
e.Footer = footer; | |||||
Assert.Equal(url, e.Footer.IconUrl); | |||||
Assert.Equal(name, e.Footer.Text); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="EmbedBuilder.WithFooter(string, string)"/> | |||||
/// </summary> | |||||
[Fact] | |||||
public void WithFooter_Strings() | |||||
{ | |||||
var e = new EmbedBuilder() | |||||
.WithFooter(name, url); | |||||
Assert.Equal(url, e.Footer.IconUrl); | |||||
Assert.Equal(name, e.Footer.Text); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="EmbedFooterBuilder"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void EmbedFooterBuilder() | |||||
{ | |||||
var footer = new EmbedFooterBuilder() | |||||
.WithIconUrl(url) | |||||
.WithText(name); | |||||
Assert.Equal(url, footer.IconUrl); | |||||
Assert.Equal(name, footer.Text); | |||||
} | |||||
/// <summary> | |||||
/// Tests that invalid URLs throw an <see cref="ArgumentException"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void EmbedFooterBuilder_InvalidURL() | |||||
{ | |||||
IEnumerable<string> InvalidUrls() | |||||
{ | |||||
yield return "not a url"; | |||||
} | |||||
foreach (var url in InvalidUrls()) | |||||
{ | |||||
Assert.Throws<ArgumentException>(() => | |||||
{ | |||||
new EmbedFooterBuilder().WithIconUrl(url); | |||||
}); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Tests that invalid text throws an <see cref="ArgumentException"/>. | |||||
/// </summary> | |||||
[Fact] | |||||
public void EmbedFooterBuilder_InvalidText() | |||||
{ | |||||
Assert.Throws<ArgumentException>(() => | |||||
{ | |||||
new EmbedFooterBuilder().WithText(new string('a', 2049)); | |||||
}); | |||||
} | |||||
[Fact] | |||||
public void AddField_Strings() | |||||
{ | |||||
var e = new EmbedBuilder() | |||||
.AddField("name", "value", true); | |||||
Assert.Equal("name", e.Fields[0].Name); | |||||
Assert.Equal("value", e.Fields[0].Value); | |||||
Assert.True(e.Fields[0].IsInline); | |||||
} | |||||
[Fact] | |||||
public void AddField_EmbedFieldBuilder() | |||||
{ | |||||
var field = new EmbedFieldBuilder() | |||||
.WithIsInline(true) | |||||
.WithValue("value") | |||||
.WithName("name"); | |||||
var e = new EmbedBuilder() | |||||
.AddField(field); | |||||
Assert.Equal("name", e.Fields[0].Name); | |||||
Assert.Equal("value", e.Fields[0].Value); | |||||
Assert.True(e.Fields[0].IsInline); | |||||
} | |||||
[Fact] | |||||
public void AddField_ActionEmbedFieldBuilder() | |||||
{ | |||||
var e = new EmbedBuilder() | |||||
.AddField(x => x | |||||
.WithName("name") | |||||
.WithValue("value") | |||||
.WithIsInline(true)); | |||||
Assert.Equal("name", e.Fields[0].Name); | |||||
Assert.Equal("value", e.Fields[0].Value); | |||||
Assert.True(e.Fields[0].IsInline); | |||||
} | |||||
[Fact] | |||||
public void AddField_TooManyFields() | |||||
{ | |||||
var e = new EmbedBuilder(); | |||||
for (var i = 0; i < 25; i++) | |||||
{ | |||||
e = e.AddField("name", "value", false); | |||||
} | |||||
Assert.Throws<ArgumentException>(() => | |||||
{ | |||||
e = e.AddField("name", "value", false); | |||||
}); | |||||
} | |||||
[Fact] | |||||
public void EmbedFieldBuilder() | |||||
{ | |||||
var e = new EmbedFieldBuilder() | |||||
.WithIsInline(true) | |||||
.WithName("name") | |||||
.WithValue("value"); | |||||
Assert.Equal("name", e.Name); | |||||
Assert.Equal("value", e.Value); | |||||
Assert.True(e.IsInline); | |||||
// use the properties | |||||
e = new EmbedFieldBuilder(); | |||||
e.IsInline = true; | |||||
e.Name = "name"; | |||||
e.Value = "value"; | |||||
Assert.Equal("name", e.Name); | |||||
Assert.Equal("value", e.Value); | |||||
Assert.True(e.IsInline); | |||||
} | |||||
[Theory] | |||||
[InlineData("")] | |||||
[InlineData(" ")] | |||||
[InlineData(null)] | |||||
// 257 chars | |||||
[InlineData("jVyLChmA7aBZozXQuZ3VDEcwW6zOq0nteOVYBZi31ny73rpXfSSBXR4Jw6FiplDKQseKskwRMuBZkUewrewqAbkBZpslHirvC5nEzRySoDIdTRnkVvTXZUXg75l3bQCjuuHxDd6DfrY8ihd6yZX1Y0XFeg239YBcYV4TpL9uQ8H3HFYxrWhLlG2PRVjUmiglP5iXkawszNwMVm1SZ5LZT4jkMZHxFegVi7170d16iaPWOovu50aDDHy087XBtLKVa")] | |||||
// 257 chars of whitespace | |||||
[InlineData(" ")] | |||||
public void EmbedFieldBuilder_InvalidName(string name) | |||||
{ | |||||
Assert.Throws<ArgumentException>(() => new EmbedFieldBuilder().WithName(name)); | |||||
} | |||||
[Fact] | |||||
public void EmbedFieldBuilder_InvalidValue() | |||||
{ | |||||
IEnumerable<string> GetInvalidValue() | |||||
{ | |||||
yield return null; | |||||
yield return string.Empty; | |||||
yield return " "; | |||||
yield return new string('a', 1025); | |||||
}; | |||||
foreach (var v in GetInvalidValue()) | |||||
Assert.Throws<ArgumentException>(() => new EmbedFieldBuilder().WithValue(v)); | |||||
} | |||||
} | |||||
} |
@@ -1,4 +1,6 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Xunit; | using Xunit; | ||||
namespace Discord | namespace Discord |
@@ -0,0 +1,32 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
public class FormatTests | |||||
{ | |||||
[Theory] | |||||
[InlineData("@everyone", "@everyone")] | |||||
[InlineData(@"\", @"\\")] | |||||
[InlineData(@"*text*", @"\*text\*")] | |||||
[InlineData(@"~text~", @"\~text\~")] | |||||
[InlineData(@"`text`", @"\`text\`")] | |||||
[InlineData(@"_text_", @"\_text\_")] | |||||
public void Sanitize(string input, string expected) | |||||
{ | |||||
Assert.Equal(expected, Format.Sanitize(input)); | |||||
} | |||||
[Fact] | |||||
public void Code() | |||||
{ | |||||
// no language | |||||
Assert.Equal("`test`", Format.Code("test")); | |||||
Assert.Equal("```\nanother\none\n```", Format.Code("another\none")); | |||||
// language specified | |||||
Assert.Equal("```cs\ntest\n```", Format.Code("test", "cs")); | |||||
Assert.Equal("```cs\nanother\none\n```", Format.Code("another\none", "cs")); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,164 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Tests the behavior of the <see cref="Discord.GuildPermissions"/> type and related functions. | |||||
/// </summary> | |||||
public class GuildPermissionsTests | |||||
{ | |||||
/// <summary> | |||||
/// Tests the default value of the <see cref="Discord.GuildPermissions"/> constructor. | |||||
/// </summary> | |||||
[Fact] | |||||
public void DefaultConstructor() | |||||
{ | |||||
var p = new GuildPermissions(); | |||||
Assert.Equal((ulong)0, p.RawValue); | |||||
Assert.Equal(GuildPermissions.None.RawValue, p.RawValue); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of the <see cref="Discord.GuildPermissions"/> raw value constructor. | |||||
/// </summary> | |||||
[Fact] | |||||
public void RawValueConstructor() | |||||
{ | |||||
// returns all of the values that will be tested | |||||
// a Theory cannot be used here, because these values are not all constants | |||||
IEnumerable<ulong> GetTestValues() | |||||
{ | |||||
yield return 0; | |||||
yield return GuildPermissions.None.RawValue; | |||||
yield return GuildPermissions.All.RawValue; | |||||
yield return GuildPermissions.Webhook.RawValue; | |||||
}; | |||||
foreach (var rawValue in GetTestValues()) | |||||
{ | |||||
var p = new GuildPermissions(rawValue); | |||||
Assert.Equal(rawValue, p.RawValue); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of the <see cref="Discord.GuildPermissions"/> constructor for each | |||||
/// of it's flags. | |||||
/// </summary> | |||||
[Fact] | |||||
public void FlagsConstructor() | |||||
{ | |||||
// util method for asserting that the constructor sets the given flag | |||||
void AssertFlag(Func<GuildPermissions> cstr, GuildPermission flag) | |||||
{ | |||||
var p = cstr(); | |||||
// ensure flag set to true | |||||
Assert.True(p.Has(flag)); | |||||
// ensure only this flag is set | |||||
Assert.Equal((ulong)flag, p.RawValue); | |||||
} | |||||
AssertFlag(() => new GuildPermissions(createInstantInvite: true), GuildPermission.CreateInstantInvite); | |||||
AssertFlag(() => new GuildPermissions(kickMembers: true), GuildPermission.KickMembers); | |||||
AssertFlag(() => new GuildPermissions(banMembers: true), GuildPermission.BanMembers); | |||||
AssertFlag(() => new GuildPermissions(administrator: true), GuildPermission.Administrator); | |||||
AssertFlag(() => new GuildPermissions(manageChannels: true), GuildPermission.ManageChannels); | |||||
AssertFlag(() => new GuildPermissions(manageGuild: true), GuildPermission.ManageGuild); | |||||
AssertFlag(() => new GuildPermissions(addReactions: true), GuildPermission.AddReactions); | |||||
AssertFlag(() => new GuildPermissions(viewAuditLog: true), GuildPermission.ViewAuditLog); | |||||
AssertFlag(() => new GuildPermissions(viewChannel: true), GuildPermission.ViewChannel); | |||||
AssertFlag(() => new GuildPermissions(sendMessages: true), GuildPermission.SendMessages); | |||||
AssertFlag(() => new GuildPermissions(sendTTSMessages: true), GuildPermission.SendTTSMessages); | |||||
AssertFlag(() => new GuildPermissions(manageMessages: true), GuildPermission.ManageMessages); | |||||
AssertFlag(() => new GuildPermissions(embedLinks: true), GuildPermission.EmbedLinks); | |||||
AssertFlag(() => new GuildPermissions(attachFiles: true), GuildPermission.AttachFiles); | |||||
AssertFlag(() => new GuildPermissions(readMessageHistory: true), GuildPermission.ReadMessageHistory); | |||||
AssertFlag(() => new GuildPermissions(mentionEveryone: true), GuildPermission.MentionEveryone); | |||||
AssertFlag(() => new GuildPermissions(useExternalEmojis: true), GuildPermission.UseExternalEmojis); | |||||
AssertFlag(() => new GuildPermissions(connect: true), GuildPermission.Connect); | |||||
AssertFlag(() => new GuildPermissions(speak: true), GuildPermission.Speak); | |||||
AssertFlag(() => new GuildPermissions(muteMembers: true), GuildPermission.MuteMembers); | |||||
AssertFlag(() => new GuildPermissions(deafenMembers: true), GuildPermission.DeafenMembers); | |||||
AssertFlag(() => new GuildPermissions(moveMembers: true), GuildPermission.MoveMembers); | |||||
AssertFlag(() => new GuildPermissions(useVoiceActivation: true), GuildPermission.UseVAD); | |||||
AssertFlag(() => new GuildPermissions(prioritySpeaker: true), GuildPermission.PrioritySpeaker); | |||||
AssertFlag(() => new GuildPermissions(changeNickname: true), GuildPermission.ChangeNickname); | |||||
AssertFlag(() => new GuildPermissions(manageNicknames: true), GuildPermission.ManageNicknames); | |||||
AssertFlag(() => new GuildPermissions(manageRoles: true), GuildPermission.ManageRoles); | |||||
AssertFlag(() => new GuildPermissions(manageWebhooks: true), GuildPermission.ManageWebhooks); | |||||
AssertFlag(() => new GuildPermissions(manageEmojis: true), GuildPermission.ManageEmojis); | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of <see cref="Discord.GuildPermissions.Modify(bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?, bool?)"/> | |||||
/// with each of the parameters. | |||||
/// </summary> | |||||
[Fact] | |||||
public void Modify() | |||||
{ | |||||
// asserts that flag values can be checked | |||||
// and that flag values can be toggled on and off | |||||
// and that the behavior of ToList works as expected | |||||
void AssertUtil(GuildPermission permission, | |||||
Func<GuildPermissions, bool> has, | |||||
Func<GuildPermissions, bool, GuildPermissions> modify) | |||||
{ | |||||
var perm = new GuildPermissions(); | |||||
// ensure permission initially false | |||||
// use both the function and Has to ensure that the GetPermission | |||||
// function is working | |||||
Assert.False(has(perm)); | |||||
Assert.False(perm.Has(permission)); | |||||
// enable it, and ensure that it gets set | |||||
perm = modify(perm, true); | |||||
Assert.True(has(perm)); | |||||
Assert.True(perm.Has(permission)); | |||||
// check ToList behavior | |||||
var list = perm.ToList(); | |||||
Assert.Contains(permission, list); | |||||
Assert.Single(list); | |||||
// set it false again | |||||
perm = modify(perm, false); | |||||
Assert.False(has(perm)); | |||||
Assert.False(perm.Has(permission)); | |||||
// ensure that no perms are set now | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
} | |||||
AssertUtil(GuildPermission.CreateInstantInvite, x => x.CreateInstantInvite, (p, enable) => p.Modify(createInstantInvite: enable)); | |||||
AssertUtil(GuildPermission.KickMembers, x => x.KickMembers, (p, enable) => p.Modify(kickMembers: enable)); | |||||
AssertUtil(GuildPermission.BanMembers, x => x.BanMembers, (p, enable) => p.Modify(banMembers: enable)); | |||||
AssertUtil(GuildPermission.Administrator, x => x.Administrator, (p, enable) => p.Modify(administrator: enable)); | |||||
AssertUtil(GuildPermission.ManageChannels, x => x.ManageChannels, (p, enable) => p.Modify(manageChannels: enable)); | |||||
AssertUtil(GuildPermission.ManageGuild, x => x.ManageGuild, (p, enable) => p.Modify(manageGuild: enable)); | |||||
AssertUtil(GuildPermission.AddReactions, x => x.AddReactions, (p, enable) => p.Modify(addReactions: enable)); | |||||
AssertUtil(GuildPermission.ViewAuditLog, x => x.ViewAuditLog, (p, enable) => p.Modify(viewAuditLog: enable)); | |||||
AssertUtil(GuildPermission.ViewChannel, x => x.ViewChannel, (p, enable) => p.Modify(viewChannel: enable)); | |||||
AssertUtil(GuildPermission.SendMessages, x => x.SendMessages, (p, enable) => p.Modify(sendMessages: enable)); | |||||
AssertUtil(GuildPermission.SendTTSMessages, x => x.SendTTSMessages, (p, enable) => p.Modify(sendTTSMessages: enable)); | |||||
AssertUtil(GuildPermission.ManageMessages, x => x.ManageMessages, (p, enable) => p.Modify(manageMessages: enable)); | |||||
AssertUtil(GuildPermission.EmbedLinks, x => x.EmbedLinks, (p, enable) => p.Modify(embedLinks: enable)); | |||||
AssertUtil(GuildPermission.AttachFiles, x => x.AttachFiles, (p, enable) => p.Modify(attachFiles: enable)); | |||||
AssertUtil(GuildPermission.ReadMessageHistory, x => x.ReadMessageHistory, (p, enable) => p.Modify(readMessageHistory: enable)); | |||||
AssertUtil(GuildPermission.MentionEveryone, x => x.MentionEveryone, (p, enable) => p.Modify(mentionEveryone: enable)); | |||||
AssertUtil(GuildPermission.UseExternalEmojis, x => x.UseExternalEmojis, (p, enable) => p.Modify(useExternalEmojis: enable)); | |||||
AssertUtil(GuildPermission.Connect, x => x.Connect, (p, enable) => p.Modify(connect: enable)); | |||||
AssertUtil(GuildPermission.Speak, x => x.Speak, (p, enable) => p.Modify(speak: enable)); | |||||
AssertUtil(GuildPermission.MuteMembers, x => x.MuteMembers, (p, enable) => p.Modify(muteMembers: enable)); | |||||
AssertUtil(GuildPermission.MoveMembers, x => x.MoveMembers, (p, enable) => p.Modify(moveMembers: enable)); | |||||
AssertUtil(GuildPermission.UseVAD, x => x.UseVAD, (p, enable) => p.Modify(useVoiceActivation: enable)); | |||||
AssertUtil(GuildPermission.ChangeNickname, x => x.ChangeNickname, (p, enable) => p.Modify(changeNickname: enable)); | |||||
AssertUtil(GuildPermission.ManageNicknames, x => x.ManageNicknames, (p, enable) => p.Modify(manageNicknames: enable)); | |||||
AssertUtil(GuildPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable)); | |||||
AssertUtil(GuildPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable)); | |||||
AssertUtil(GuildPermission.ManageEmojis, x => x.ManageEmojis, (p, enable) => p.Modify(manageEmojis: enable)); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,128 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Tests the methods provided in <see cref="MentionUtils"/>. | |||||
/// </summary> | |||||
public class MentionUtilsTests | |||||
{ | |||||
/// <summary> | |||||
/// Tests <see cref="MentionUtils.MentionUser(string, bool)"/> | |||||
/// </summary> | |||||
[Fact] | |||||
public void MentionUser() | |||||
{ | |||||
Assert.Equal("<@!123>", MentionUtils.MentionUser(123u)); | |||||
Assert.Equal("<@!123>", MentionUtils.MentionUser("123")); | |||||
Assert.Equal("<@!123>", MentionUtils.MentionUser("123", true)); | |||||
Assert.Equal("<@123>", MentionUtils.MentionUser("123", false)); | |||||
} | |||||
/// <summary> | |||||
/// Tests <see cref="MentionUtils.MentionChannel(string)"/> | |||||
/// </summary> | |||||
[Fact] | |||||
public void MentionChannel() | |||||
{ | |||||
Assert.Equal("<#123>", MentionUtils.MentionChannel(123u)); | |||||
Assert.Equal("<#123>", MentionUtils.MentionChannel("123")); | |||||
} | |||||
/// <summary> | |||||
/// Tests <see cref="MentionUtils.MentionRole(string)"/> | |||||
/// </summary> | |||||
[Fact] | |||||
public void MentionRole() | |||||
{ | |||||
Assert.Equal("<@&123>", MentionUtils.MentionRole(123u)); | |||||
Assert.Equal("<@&123>", MentionUtils.MentionRole("123")); | |||||
} | |||||
[Theory] | |||||
[InlineData("<@!123>", 123)] | |||||
[InlineData("<@123>", 123)] | |||||
public void ParseUser_Pass(string user, ulong id) | |||||
{ | |||||
var parsed = MentionUtils.ParseUser(user); | |||||
Assert.Equal(id, parsed); | |||||
// also check tryparse | |||||
ulong result; | |||||
Assert.True(MentionUtils.TryParseUser(user, out result)); | |||||
Assert.Equal(id, result); | |||||
} | |||||
[Theory] | |||||
[InlineData(" ")] | |||||
[InlineData("invalid")] | |||||
[InlineData("<12!3@>")] | |||||
[InlineData("<123>")] | |||||
public void ParseUser_Fail(string user) | |||||
{ | |||||
Assert.Throws<ArgumentException>(() => MentionUtils.ParseUser(user)); | |||||
Assert.False(MentionUtils.TryParseUser(user, out _)); | |||||
} | |||||
[Fact] | |||||
public void ParseUser_Null() | |||||
{ | |||||
Assert.Throws<NullReferenceException>(() => MentionUtils.ParseUser(null)); | |||||
Assert.Throws<NullReferenceException>(() => MentionUtils.TryParseUser(null, out _)); | |||||
} | |||||
[Theory] | |||||
[InlineData("<#123>", 123)] | |||||
public void ParseChannel_Pass(string channel, ulong id) | |||||
{ | |||||
var parsed = MentionUtils.ParseChannel(channel); | |||||
Assert.Equal(id, parsed); | |||||
// also check tryparse | |||||
ulong result; | |||||
Assert.True(MentionUtils.TryParseChannel(channel, out result)); | |||||
Assert.Equal(id, result); | |||||
} | |||||
[Theory] | |||||
[InlineData(" ")] | |||||
[InlineData("invalid")] | |||||
[InlineData("<12#3>")] | |||||
[InlineData("<123>")] | |||||
public void ParseChannel_Fail(string channel) | |||||
{ | |||||
Assert.Throws<ArgumentException>(() => MentionUtils.ParseChannel(channel)); | |||||
Assert.False(MentionUtils.TryParseChannel(channel, out _)); | |||||
} | |||||
[Fact] | |||||
public void ParseChannel_Null() | |||||
{ | |||||
Assert.Throws<NullReferenceException>(() => MentionUtils.ParseChannel(null)); | |||||
Assert.Throws<NullReferenceException>(() => MentionUtils.TryParseChannel(null, out _)); | |||||
} | |||||
[Theory] | |||||
[InlineData("<@&123>", 123)] | |||||
public void ParseRole_Pass(string role, ulong id) | |||||
{ | |||||
var parsed = MentionUtils.ParseRole(role); | |||||
Assert.Equal(id, parsed); | |||||
// also check tryparse | |||||
ulong result; | |||||
Assert.True(MentionUtils.TryParseRole(role, out result)); | |||||
Assert.Equal(id, result); | |||||
} | |||||
[Theory] | |||||
[InlineData(" ")] | |||||
[InlineData("invalid")] | |||||
[InlineData("<12@&3>")] | |||||
[InlineData("<123>")] | |||||
public void ParseRole_Fail(string role) | |||||
{ | |||||
Assert.Throws<ArgumentException>(() => MentionUtils.ParseRole(role)); | |||||
Assert.False(MentionUtils.TryParseRole(role, out _)); | |||||
} | |||||
[Fact] | |||||
public void ParseRole_Null() | |||||
{ | |||||
Assert.Throws<NullReferenceException>(() => MentionUtils.ParseRole(null)); | |||||
Assert.Throws<NullReferenceException>(() => MentionUtils.TryParseRole(null, out _)); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,84 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
internal sealed class MockedCategoryChannel : ICategoryChannel | |||||
{ | |||||
public int Position => throw new NotImplementedException(); | |||||
public IGuild Guild => throw new NotImplementedException(); | |||||
public ulong GuildId => throw new NotImplementedException(); | |||||
public IReadOnlyCollection<Overwrite> PermissionOverwrites => throw new NotImplementedException(); | |||||
public string Name => throw new NotImplementedException(); | |||||
public DateTimeOffset CreatedAt => throw new NotImplementedException(); | |||||
public ulong Id => throw new NotImplementedException(); | |||||
public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public OverwritePermissions? GetPermissionOverwrite(IRole role) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public OverwritePermissions? GetPermissionOverwrite(IUser user) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task RemovePermissionOverwriteAsync(IRole role, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,96 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
internal sealed class MockedDMChannel : IDMChannel | |||||
{ | |||||
public IUser Recipient => throw new NotImplementedException(); | |||||
public IReadOnlyCollection<IUser> Recipients => throw new NotImplementedException(); | |||||
public string Name => throw new NotImplementedException(); | |||||
public DateTimeOffset CreatedAt => throw new NotImplementedException(); | |||||
public ulong Id => throw new NotImplementedException(); | |||||
public Task CloseAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IDisposable EnterTypingState(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IMessage> GetMessageAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task TriggerTypingAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,105 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Discord.Audio; | |||||
namespace Discord | |||||
{ | |||||
internal sealed class MockedGroupChannel : IGroupChannel | |||||
{ | |||||
public IReadOnlyCollection<IUser> Recipients => throw new NotImplementedException(); | |||||
public string Name => throw new NotImplementedException(); | |||||
public DateTimeOffset CreatedAt => throw new NotImplementedException(); | |||||
public ulong Id => throw new NotImplementedException(); | |||||
public Task<IAudioClient> ConnectAsync(bool selfDeaf = false, bool selfMute = false, bool external = false) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DisconnectAsync() | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IDisposable EnterTypingState(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IMessage> GetMessageAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task LeaveAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task TriggerTypingAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,29 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
/// <summary> | |||||
/// Represents a channel that is of an unrecognized type. | |||||
/// </summary> | |||||
internal sealed class MockedInvalidChannel : IChannel | |||||
{ | |||||
public string Name => throw new NotImplementedException(); | |||||
public DateTimeOffset CreatedAt => throw new NotImplementedException(); | |||||
public ulong Id => throw new NotImplementedException(); | |||||
public Task<IUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,205 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
namespace Discord | |||||
{ | |||||
internal sealed class MockedTextChannel : ITextChannel | |||||
{ | |||||
public bool IsNsfw => throw new NotImplementedException(); | |||||
public string Topic => throw new NotImplementedException(); | |||||
public int SlowModeInterval => throw new NotImplementedException(); | |||||
public string Mention => throw new NotImplementedException(); | |||||
public ulong? CategoryId => throw new NotImplementedException(); | |||||
public int Position => throw new NotImplementedException(); | |||||
public IGuild Guild => throw new NotImplementedException(); | |||||
public ulong GuildId => throw new NotImplementedException(); | |||||
public IReadOnlyCollection<Overwrite> PermissionOverwrites => throw new NotImplementedException(); | |||||
public string Name => throw new NotImplementedException(); | |||||
public DateTimeOffset CreatedAt => throw new NotImplementedException(); | |||||
public ulong Id => throw new NotImplementedException(); | |||||
public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IWebhook> CreateWebhookAsync(string name, Stream avatar = null, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteMessagesAsync(IEnumerable<ulong> messageIds, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IDisposable EnterTypingState(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<ICategoryChannel> GetCategoryAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IMessage> GetMessageAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = 100, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public OverwritePermissions? GetPermissionOverwrite(IRole role) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public OverwritePermissions? GetPermissionOverwrite(IUser user) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IReadOnlyCollection<IMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IWebhook> GetWebhookAsync(ulong id, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IReadOnlyCollection<IWebhook>> GetWebhooksAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task ModifyAsync(Action<TextChannelProperties> func, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task RemovePermissionOverwriteAsync(IRole role, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task SyncPermissionsAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task TriggerTypingAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,126 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Discord.Audio; | |||||
namespace Discord | |||||
{ | |||||
internal sealed class MockedVoiceChannel : IVoiceChannel | |||||
{ | |||||
public int Bitrate => throw new NotImplementedException(); | |||||
public int? UserLimit => throw new NotImplementedException(); | |||||
public ulong? CategoryId => throw new NotImplementedException(); | |||||
public int Position => throw new NotImplementedException(); | |||||
public IGuild Guild => throw new NotImplementedException(); | |||||
public ulong GuildId => throw new NotImplementedException(); | |||||
public IReadOnlyCollection<Overwrite> PermissionOverwrites => throw new NotImplementedException(); | |||||
public string Name => throw new NotImplementedException(); | |||||
public DateTimeOffset CreatedAt => throw new NotImplementedException(); | |||||
public ulong Id => throw new NotImplementedException(); | |||||
public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IAudioClient> ConnectAsync(bool selfDeaf = false, bool selfMute = false, bool external = false) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 86400, int? maxUses = null, bool isTemporary = false, bool isUnique = false, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DeleteAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task DisconnectAsync() | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<ICategoryChannel> GetCategoryAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public OverwritePermissions? GetPermissionOverwrite(IRole role) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public OverwritePermissions? GetPermissionOverwrite(IUser user) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task<IGuildUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> GetUsersAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task ModifyAsync(Action<VoiceChannelProperties> func, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task RemovePermissionOverwriteAsync(IRole role, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
public Task SyncPermissionsAsync(RequestOptions options = null) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,24 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
public class SnowflakeUtilsTests | |||||
{ | |||||
[Fact] | |||||
public void FromSnowflake() | |||||
{ | |||||
// snowflake from a userid | |||||
var id = 163184946742034432u; | |||||
Assert.Equal(new DateTime(2016, 3, 26, 7, 18, 43), SnowflakeUtils.FromSnowflake(id).UtcDateTime, TimeSpan.FromSeconds(1)); | |||||
} | |||||
[Fact] | |||||
public void ToSnowflake() | |||||
{ | |||||
// most significant digits should match, but least significant digits cannot be determined from here | |||||
Assert.Equal(163184946184192000u, SnowflakeUtils.ToSnowflake(new DateTimeOffset(2016, 3, 26, 7, 18, 43, TimeSpan.Zero))); | |||||
} | |||||
} | |||||
} |
@@ -5,6 +5,9 @@ using Xunit; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
/// <summary> | |||||
/// Tests for the <see cref="Discord.TokenUtils"/> methods. | |||||
/// </summary> | |||||
public class TokenUtilsTests | public class TokenUtilsTests | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
@@ -18,14 +21,14 @@ namespace Discord | |||||
[InlineData(" ")] | [InlineData(" ")] | ||||
[InlineData(" ")] | [InlineData(" ")] | ||||
[InlineData("\t")] | [InlineData("\t")] | ||||
public void TestNullOrWhitespaceToken(string token) | |||||
public void NullOrWhitespaceToken(string token) | |||||
{ | { | ||||
// an ArgumentNullException should be thrown, regardless of the TokenType | // an ArgumentNullException should be thrown, regardless of the TokenType | ||||
Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Bearer, token)); | Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Bearer, token)); | ||||
Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Bot, token)); | Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Bot, token)); | ||||
Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Webhook, token)); | Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Webhook, token)); | ||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// Tests the behavior of <see cref="TokenUtils.ValidateToken(TokenType, string)"/> | /// Tests the behavior of <see cref="TokenUtils.ValidateToken(TokenType, string)"/> | ||||
/// to see that valid Webhook tokens do not throw Exceptions. | /// to see that valid Webhook tokens do not throw Exceptions. | ||||
@@ -39,7 +42,7 @@ namespace Discord | |||||
[InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")] | [InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")] | ||||
// client secret | // client secret | ||||
[InlineData("937it3ow87i4ery69876wqire")] | [InlineData("937it3ow87i4ery69876wqire")] | ||||
public void TestWebhookTokenDoesNotThrowExceptions(string token) | |||||
public void WebhookTokenDoesNotThrowExceptions(string token) | |||||
{ | { | ||||
TokenUtils.ValidateToken(TokenType.Webhook, token); | TokenUtils.ValidateToken(TokenType.Webhook, token); | ||||
} | } | ||||
@@ -59,7 +62,7 @@ namespace Discord | |||||
[InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")] | [InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")] | ||||
// client secret | // client secret | ||||
[InlineData("937it3ow87i4ery69876wqire")] | [InlineData("937it3ow87i4ery69876wqire")] | ||||
public void TestBearerTokenDoesNotThrowExceptions(string token) | |||||
public void BearerTokenDoesNotThrowExceptions(string token) | |||||
{ | { | ||||
TokenUtils.ValidateToken(TokenType.Bearer, token); | TokenUtils.ValidateToken(TokenType.Bearer, token); | ||||
} | } | ||||
@@ -77,9 +80,7 @@ namespace Discord | |||||
// 59 char token | // 59 char token | ||||
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] | [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] | ||||
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWss")] | [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWss")] | ||||
// simulated token with a very old user id | |||||
[InlineData("ODIzNjQ4MDEzNTAxMDcxMzY=.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKW")] | |||||
public void TestBotTokenDoesNotThrowExceptions(string token) | |||||
public void BotTokenDoesNotThrowExceptions(string token) | |||||
{ | { | ||||
// This example token is pulled from the Discord Docs | // This example token is pulled from the Discord Docs | ||||
// https://discordapp.com/developers/docs/reference#authentication-example-bot-token-authorization-header | // https://discordapp.com/developers/docs/reference#authentication-example-bot-token-authorization-header | ||||
@@ -112,7 +113,7 @@ namespace Discord | |||||
[InlineData("This is an invalid token, but it passes the check for string length.")] | [InlineData("This is an invalid token, but it passes the check for string length.")] | ||||
// valid token, but passed in twice | // valid token, but passed in twice | ||||
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWsMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] | [InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWsMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] | ||||
public void TestBotTokenInvalidThrowsArgumentException(string token) | |||||
public void BotTokenInvalidThrowsArgumentException(string token) | |||||
{ | { | ||||
Assert.Throws<ArgumentException>(() => TokenUtils.ValidateToken(TokenType.Bot, token)); | Assert.Throws<ArgumentException>(() => TokenUtils.ValidateToken(TokenType.Bot, token)); | ||||
} | } | ||||
@@ -132,7 +133,7 @@ namespace Discord | |||||
[InlineData(-1)] | [InlineData(-1)] | ||||
[InlineData(4)] | [InlineData(4)] | ||||
[InlineData(7)] | [InlineData(7)] | ||||
public void TestUnrecognizedTokenType(int type) | |||||
public void UnrecognizedTokenType(int type) | |||||
{ | { | ||||
Assert.Throws<ArgumentException>(() => | Assert.Throws<ArgumentException>(() => | ||||
TokenUtils.ValidateToken((TokenType)type, "MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")); | TokenUtils.ValidateToken((TokenType)type, "MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")); | ||||
@@ -154,7 +155,7 @@ namespace Discord | |||||
// should not throw an unexpected exception | // should not throw an unexpected exception | ||||
[InlineData("", false)] | [InlineData("", false)] | ||||
[InlineData(null, false)] | [InlineData(null, false)] | ||||
public void TestCheckBotTokenValidity(string token, bool expected) | |||||
public void CheckBotTokenValidity(string token, bool expected) | |||||
{ | { | ||||
Assert.Equal(expected, TokenUtils.CheckBotTokenValidity(token)); | Assert.Equal(expected, TokenUtils.CheckBotTokenValidity(token)); | ||||
} | } | ||||
@@ -163,16 +164,12 @@ namespace Discord | |||||
// cannot pass a ulong? as a param in InlineData, so have to have a separate param | // cannot pass a ulong? as a param in InlineData, so have to have a separate param | ||||
// indicating if a value is null | // indicating if a value is null | ||||
[InlineData("NDI4NDc3OTQ0MDA5MTk1NTIw", false, 428477944009195520)] | [InlineData("NDI4NDc3OTQ0MDA5MTk1NTIw", false, 428477944009195520)] | ||||
// user id that has base 64 '=' padding | |||||
[InlineData("ODIzNjQ4MDEzNTAxMDcxMzY=", false, 82364801350107136)] | |||||
// user id that does not have '=' padding, and needs it | |||||
[InlineData("ODIzNjQ4MDEzNTAxMDcxMzY", false, 82364801350107136)] | |||||
// should return null w/o throwing other exceptions | // should return null w/o throwing other exceptions | ||||
[InlineData("", true, 0)] | [InlineData("", true, 0)] | ||||
[InlineData(" ", true, 0)] | [InlineData(" ", true, 0)] | ||||
[InlineData(null, true, 0)] | [InlineData(null, true, 0)] | ||||
[InlineData("these chars aren't allowed @U#)*@#!)*", true, 0)] | [InlineData("these chars aren't allowed @U#)*@#!)*", true, 0)] | ||||
public void TestDecodeBase64UserId(string encodedUserId, bool isNull, ulong expectedUserId) | |||||
public void DecodeBase64UserId(string encodedUserId, bool isNull, ulong expectedUserId) | |||||
{ | { | ||||
var result = TokenUtils.DecodeBase64UserId(encodedUserId); | var result = TokenUtils.DecodeBase64UserId(encodedUserId); | ||||
if (isNull) | if (isNull) | ||||
@@ -180,37 +177,5 @@ namespace Discord | |||||
else | else | ||||
Assert.Equal(expectedUserId, result); | Assert.Equal(expectedUserId, result); | ||||
} | } | ||||
[Theory] | |||||
[InlineData("QQ", "QQ==")] // "A" encoded | |||||
[InlineData("QUE", "QUE=")] // "AA" | |||||
[InlineData("QUFB", "QUFB")] // "AAA" | |||||
[InlineData("QUFBQQ", "QUFBQQ==")] // "AAAA" | |||||
[InlineData("QUFBQUFB", "QUFBQUFB")] // "AAAAAA" | |||||
// strings that already contain padding will be returned, even if invalid | |||||
[InlineData("QUFBQQ==", "QUFBQQ==")] | |||||
[InlineData("QUFBQQ=", "QUFBQQ=")] | |||||
[InlineData("=", "=")] | |||||
public void TestPadBase64String(string input, string expected) | |||||
{ | |||||
Assert.Equal(expected, TokenUtils.PadBase64String(input)); | |||||
} | |||||
[Theory] | |||||
// no null, empty, or whitespace | |||||
[InlineData("", typeof(ArgumentNullException))] | |||||
[InlineData(" ", typeof(ArgumentNullException))] | |||||
[InlineData("\t", typeof(ArgumentNullException))] | |||||
[InlineData(null, typeof(ArgumentNullException))] | |||||
// cannot require 3 padding chars | |||||
[InlineData("A", typeof(FormatException))] | |||||
[InlineData("QUFBQ", typeof(FormatException))] | |||||
public void TestPadBase64StringException(string input, Type type) | |||||
{ | |||||
Assert.Throws(type, () => | |||||
{ | |||||
TokenUtils.PadBase64String(input); | |||||
}); | |||||
} | |||||
} | } | ||||
} | } |
@@ -0,0 +1,142 @@ | |||||
using Discord.Commands; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
public sealed class TypeReaderTests | |||||
{ | |||||
[Fact] | |||||
public async Task TestNamedArgumentReader() | |||||
{ | |||||
using (var commands = new CommandService()) | |||||
{ | |||||
var module = await commands.AddModuleAsync<TestModule>(null); | |||||
Assert.NotNull(module); | |||||
Assert.NotEmpty(module.Commands); | |||||
var cmd = module.Commands[0]; | |||||
Assert.NotNull(cmd); | |||||
Assert.NotEmpty(cmd.Parameters); | |||||
var param = cmd.Parameters[0]; | |||||
Assert.NotNull(param); | |||||
Assert.True(param.IsRemainder); | |||||
var result = await param.ParseAsync(null, "bar: hello foo: 42"); | |||||
Assert.True(result.IsSuccess); | |||||
var m = result.BestMatch as ArgumentType; | |||||
Assert.NotNull(m); | |||||
Assert.Equal(expected: 42, actual: m.Foo); | |||||
Assert.Equal(expected: "hello", actual: m.Bar); | |||||
} | |||||
} | |||||
[Fact] | |||||
public async Task TestQuotedArgumentValue() | |||||
{ | |||||
using (var commands = new CommandService()) | |||||
{ | |||||
var module = await commands.AddModuleAsync<TestModule>(null); | |||||
Assert.NotNull(module); | |||||
Assert.NotEmpty(module.Commands); | |||||
var cmd = module.Commands[0]; | |||||
Assert.NotNull(cmd); | |||||
Assert.NotEmpty(cmd.Parameters); | |||||
var param = cmd.Parameters[0]; | |||||
Assert.NotNull(param); | |||||
Assert.True(param.IsRemainder); | |||||
var result = await param.ParseAsync(null, "foo: 42 bar: 《hello》"); | |||||
Assert.True(result.IsSuccess); | |||||
var m = result.BestMatch as ArgumentType; | |||||
Assert.NotNull(m); | |||||
Assert.Equal(expected: 42, actual: m.Foo); | |||||
Assert.Equal(expected: "hello", actual: m.Bar); | |||||
} | |||||
} | |||||
[Fact] | |||||
public async Task TestNonPatternInput() | |||||
{ | |||||
using (var commands = new CommandService()) | |||||
{ | |||||
var module = await commands.AddModuleAsync<TestModule>(null); | |||||
Assert.NotNull(module); | |||||
Assert.NotEmpty(module.Commands); | |||||
var cmd = module.Commands[0]; | |||||
Assert.NotNull(cmd); | |||||
Assert.NotEmpty(cmd.Parameters); | |||||
var param = cmd.Parameters[0]; | |||||
Assert.NotNull(param); | |||||
Assert.True(param.IsRemainder); | |||||
var result = await param.ParseAsync(null, "foobar"); | |||||
Assert.False(result.IsSuccess); | |||||
Assert.Equal(expected: CommandError.Exception, actual: result.Error); | |||||
} | |||||
} | |||||
[Fact] | |||||
public async Task TestMultiple() | |||||
{ | |||||
using (var commands = new CommandService()) | |||||
{ | |||||
var module = await commands.AddModuleAsync<TestModule>(null); | |||||
Assert.NotNull(module); | |||||
Assert.NotEmpty(module.Commands); | |||||
var cmd = module.Commands[0]; | |||||
Assert.NotNull(cmd); | |||||
Assert.NotEmpty(cmd.Parameters); | |||||
var param = cmd.Parameters[0]; | |||||
Assert.NotNull(param); | |||||
Assert.True(param.IsRemainder); | |||||
var result = await param.ParseAsync(null, "manyints: \"1, 2, 3, 4, 5, 6, 7\""); | |||||
Assert.True(result.IsSuccess); | |||||
var m = result.BestMatch as ArgumentType; | |||||
Assert.NotNull(m); | |||||
Assert.Equal(expected: new int[] { 1, 2, 3, 4, 5, 6, 7 }, actual: m.ManyInts); | |||||
} | |||||
} | |||||
} | |||||
[NamedArgumentType] | |||||
public sealed class ArgumentType | |||||
{ | |||||
public int Foo { get; set; } | |||||
[OverrideTypeReader(typeof(CustomTypeReader))] | |||||
public string Bar { get; set; } | |||||
public IEnumerable<int> ManyInts { get; set; } | |||||
} | |||||
public sealed class CustomTypeReader : TypeReader | |||||
{ | |||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | |||||
=> Task.FromResult(TypeReaderResult.FromSuccess(input)); | |||||
} | |||||
public sealed class TestModule : ModuleBase | |||||
{ | |||||
[Command("test")] | |||||
public Task TestCommand(ArgumentType arg) => Task.Delay(0); | |||||
} | |||||
} |
@@ -1,35 +0,0 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | |||||
<OutputType>Exe</OutputType> | |||||
<RootNamespace>Discord</RootNamespace> | |||||
<TargetFramework>netcoreapp2.1</TargetFramework> | |||||
<DebugType>portable</DebugType> | |||||
<NoWarn>IDISP001,IDISP002,IDISP004,IDISP005</NoWarn> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<Content Include="xunit.runner.json"> | |||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | |||||
</Content> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="Tests.Permissions.cs" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<ProjectReference Include="../../src/Discord.Net.Commands/Discord.Net.Commands.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Core/Discord.Net.Core.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Rest/Discord.Net.Rest.csproj" /> | |||||
<ProjectReference Include="../../src/Discord.Net.Analyzers/Discord.Net.Analyzers.csproj" /> | |||||
<ProjectReference Include="..\..\src\Discord.Net.Webhook\Discord.Net.Webhook.csproj" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<PackageReference Include="Akavache" Version="6.0.31" /> | |||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" /> | |||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> | |||||
<PackageReference Include="xunit" Version="2.4.1" /> | |||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1"> | |||||
<PrivateAssets>all</PrivateAssets> | |||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | |||||
</PackageReference> | |||||
<PackageReference Include="xunit.runner.reporters" Version="2.4.1" /> | |||||
</ItemGroup> | |||||
</Project> |
@@ -1,12 +0,0 @@ | |||||
using Newtonsoft.Json; | |||||
namespace Discord.Net | |||||
{ | |||||
internal class CacheInfo | |||||
{ | |||||
[JsonProperty("guild_id")] | |||||
public ulong? GuildId { get; set; } | |||||
[JsonProperty("version")] | |||||
public uint Version { get; set; } | |||||
} | |||||
} |
@@ -1,123 +0,0 @@ | |||||
using Akavache; | |||||
using Akavache.Sqlite3; | |||||
using Discord.Net.Rest; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.IO; | |||||
using System.Net; | |||||
using System.Reactive.Concurrency; | |||||
using System.Reactive.Linq; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
using Splat; | |||||
namespace Discord.Net | |||||
{ | |||||
internal class CachedRestClient : IRestClient | |||||
{ | |||||
private readonly Dictionary<string, string> _headers; | |||||
private IBlobCache _blobCache; | |||||
private string _baseUrl; | |||||
private CancellationTokenSource _cancelTokenSource; | |||||
private CancellationToken _cancelToken, _parentToken; | |||||
private bool _isDisposed; | |||||
public CacheInfo Info { get; private set; } | |||||
public CachedRestClient() | |||||
{ | |||||
_headers = new Dictionary<string, string>(); | |||||
_cancelTokenSource = new CancellationTokenSource(); | |||||
_cancelToken = CancellationToken.None; | |||||
_parentToken = CancellationToken.None; | |||||
Locator.CurrentMutable.Register(() => Scheduler.Default, typeof(IScheduler), "Taskpool"); | |||||
Locator.CurrentMutable.Register(() => new FilesystemProvider(), typeof(IFilesystemProvider), null); | |||||
Locator.CurrentMutable.Register(() => new HttpMixin(), typeof(IAkavacheHttpMixin), null); | |||||
//new Akavache.Sqlite3.Registrations().Register(Locator.CurrentMutable); | |||||
_blobCache = new SQLitePersistentBlobCache("cache.db"); | |||||
} | |||||
private void Dispose(bool disposing) | |||||
{ | |||||
if (!_isDisposed) | |||||
{ | |||||
if (disposing) | |||||
{ | |||||
_blobCache.Dispose(); | |||||
_cancelTokenSource?.Dispose(); | |||||
} | |||||
_isDisposed = true; | |||||
} | |||||
} | |||||
public void Dispose() | |||||
{ | |||||
Dispose(true); | |||||
} | |||||
public void SetUrl(string url) | |||||
{ | |||||
_baseUrl = url; | |||||
} | |||||
public void SetHeader(string key, string value) | |||||
{ | |||||
_headers[key] = value; | |||||
} | |||||
public void SetCancelToken(CancellationToken cancelToken) | |||||
{ | |||||
_parentToken = cancelToken; | |||||
_cancelToken = CancellationTokenSource.CreateLinkedTokenSource(_parentToken, _cancelTokenSource.Token).Token; | |||||
} | |||||
public async Task<RestResponse> SendAsync(string method, string endpoint, CancellationToken cancelToken, bool headerOnly, string reason = null) | |||||
{ | |||||
if (method != "GET") | |||||
throw new InvalidOperationException("This RestClient only supports GET requests."); | |||||
string uri = Path.Combine(_baseUrl, endpoint); | |||||
var bytes = await _blobCache.DownloadUrl(uri, _headers); | |||||
return new RestResponse(HttpStatusCode.OK, _headers, new MemoryStream(bytes)); | |||||
} | |||||
public Task<RestResponse> SendAsync(string method, string endpoint, string json, CancellationToken cancelToken, bool headerOnly, string reason = null) | |||||
{ | |||||
throw new InvalidOperationException("This RestClient does not support payloads."); | |||||
} | |||||
public Task<RestResponse> SendAsync(string method, string endpoint, IReadOnlyDictionary<string, object> multipartParams, CancellationToken cancelToken, bool headerOnly, string reason = null) | |||||
{ | |||||
throw new InvalidOperationException("This RestClient does not support multipart requests."); | |||||
} | |||||
public async Task ClearAsync() | |||||
{ | |||||
await _blobCache.InvalidateAll(); | |||||
} | |||||
public async Task LoadInfoAsync(ulong guildId) | |||||
{ | |||||
if (Info != null) | |||||
return; | |||||
bool needsReset = false; | |||||
try | |||||
{ | |||||
Info = await _blobCache.GetObject<CacheInfo>("info"); | |||||
if (Info.GuildId != guildId) | |||||
needsReset = true; | |||||
} | |||||
catch (KeyNotFoundException) | |||||
{ | |||||
needsReset = true; | |||||
} | |||||
if (needsReset) | |||||
{ | |||||
Info = new CacheInfo() { GuildId = guildId, Version = 0 }; | |||||
await SaveInfoAsync().ConfigureAwait(false); | |||||
} | |||||
} | |||||
public async Task SaveInfoAsync() | |||||
{ | |||||
await ClearAsync().ConfigureAwait(false); //Version changed, invalidate cache | |||||
await _blobCache.InsertObject<CacheInfo>("info", Info); | |||||
} | |||||
} | |||||
} |
@@ -1,128 +0,0 @@ | |||||
//From https://github.com/akavache/Akavache | |||||
//Copyright (c) 2012 GitHub | |||||
//TODO: Remove once netstandard support is added | |||||
using Akavache; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
using System.IO; | |||||
using System.Linq; | |||||
using System.Reactive; | |||||
using System.Reactive.Concurrency; | |||||
using System.Reactive.Linq; | |||||
using System.Reactive.Subjects; | |||||
using System.Reflection; | |||||
namespace Discord | |||||
{ | |||||
public class FilesystemProvider : IFilesystemProvider | |||||
{ | |||||
public IObservable<Stream> OpenFileForReadAsync(string path, IScheduler scheduler) | |||||
{ | |||||
return SafeOpenFileAsync(path, FileMode.Open, FileAccess.Read, FileShare.Read, scheduler); | |||||
} | |||||
public IObservable<Stream> OpenFileForWriteAsync(string path, IScheduler scheduler) | |||||
{ | |||||
return SafeOpenFileAsync(path, FileMode.Create, FileAccess.Write, FileShare.None, scheduler); | |||||
} | |||||
public IObservable<Unit> CreateRecursive(string path) | |||||
{ | |||||
CreateRecursive(new DirectoryInfo(path)); | |||||
return Observable.Return(Unit.Default); | |||||
} | |||||
public IObservable<Unit> Delete(string path) | |||||
{ | |||||
return Observable.Start(() => File.Delete(path), Scheduler.Default); | |||||
} | |||||
public string GetDefaultRoamingCacheDirectory() | |||||
{ | |||||
throw new NotSupportedException(); | |||||
} | |||||
public string GetDefaultSecretCacheDirectory() | |||||
{ | |||||
throw new NotSupportedException(); | |||||
} | |||||
public string GetDefaultLocalMachineCacheDirectory() | |||||
{ | |||||
throw new NotSupportedException(); | |||||
} | |||||
protected static string GetAssemblyDirectoryName() | |||||
{ | |||||
var assemblyDirectoryName = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); | |||||
Debug.Assert(assemblyDirectoryName != null, "The directory name of the assembly location is null"); | |||||
return assemblyDirectoryName; | |||||
} | |||||
private static IObservable<Stream> SafeOpenFileAsync(string path, FileMode mode, FileAccess access, FileShare share, IScheduler scheduler = null) | |||||
{ | |||||
scheduler = scheduler ?? Scheduler.Default; | |||||
var ret = new AsyncSubject<Stream>(); | |||||
Observable.Start(() => | |||||
{ | |||||
try | |||||
{ | |||||
var createModes = new[] | |||||
{ | |||||
FileMode.Create, | |||||
FileMode.CreateNew, | |||||
FileMode.OpenOrCreate, | |||||
}; | |||||
// NB: We do this (even though it's incorrect!) because | |||||
// throwing lots of 1st chance exceptions makes debugging | |||||
// obnoxious, as well as a bug in VS where it detects | |||||
// exceptions caught by Observable.Start as Unhandled. | |||||
if (!createModes.Contains(mode) && !File.Exists(path)) | |||||
{ | |||||
ret.OnError(new FileNotFoundException()); | |||||
return; | |||||
} | |||||
Observable.Start(() => new FileStream(path, mode, access, share, 4096, false), scheduler).Cast<Stream>().Subscribe(ret); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
ret.OnError(ex); | |||||
} | |||||
}, scheduler); | |||||
return ret; | |||||
} | |||||
private static void CreateRecursive(DirectoryInfo info) | |||||
{ | |||||
SplitFullPath(info).Aggregate((parent, dir) => | |||||
{ | |||||
var path = Path.Combine(parent, dir); | |||||
if (!Directory.Exists(path)) | |||||
Directory.CreateDirectory(path); | |||||
return path; | |||||
}); | |||||
} | |||||
private static IEnumerable<string> SplitFullPath(DirectoryInfo info) | |||||
{ | |||||
var root = Path.GetPathRoot(info.FullName); | |||||
var components = new List<string>(); | |||||
for (var path = info.FullName; path != root && path != null; path = Path.GetDirectoryName(path)) | |||||
{ | |||||
var filename = Path.GetFileName(path); | |||||
if (String.IsNullOrEmpty(filename)) | |||||
continue; | |||||
components.Add(filename); | |||||
} | |||||
components.Add(root); | |||||
components.Reverse(); | |||||
return components; | |||||
} | |||||
} | |||||
} |
@@ -1,144 +0,0 @@ | |||||
//From https://github.com/akavache/Akavache | |||||
//Copyright (c) 2012 GitHub | |||||
//TODO: Remove once netstandard support is added | |||||
#pragma warning disable CS0618 | |||||
using Akavache; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Diagnostics; | |||||
using System.IO; | |||||
using System.Net; | |||||
using System.Reactive.Linq; | |||||
using System.Reactive.Subjects; | |||||
using System.Text; | |||||
using System.Reactive; | |||||
using System.Reactive.Threading.Tasks; | |||||
namespace Discord.Net | |||||
{ | |||||
public class HttpMixin : IAkavacheHttpMixin | |||||
{ | |||||
/// <summary> | |||||
/// Download data from an HTTP URL and insert the result into the | |||||
/// cache. If the data is already in the cache, this returns | |||||
/// a cached value. The URL itself is used as the key. | |||||
/// </summary> | |||||
/// <param name="url">The URL to download.</param> | |||||
/// <param name="headers">An optional Dictionary containing the HTTP | |||||
/// request headers.</param> | |||||
/// <param name="fetchAlways">Force a web request to always be issued, skipping the cache.</param> | |||||
/// <param name="absoluteExpiration">An optional expiration date.</param> | |||||
/// <returns>The data downloaded from the URL.</returns> | |||||
public IObservable<byte[]> DownloadUrl(IBlobCache This, string url, IDictionary<string, string> headers = null, bool fetchAlways = false, DateTimeOffset? absoluteExpiration = null) | |||||
{ | |||||
return This.DownloadUrl(url, url, headers, fetchAlways, absoluteExpiration); | |||||
} | |||||
/// <summary> | |||||
/// Download data from an HTTP URL and insert the result into the | |||||
/// cache. If the data is already in the cache, this returns | |||||
/// a cached value. An explicit key is provided rather than the URL itself. | |||||
/// </summary> | |||||
/// <param name="key">The key to store with.</param> | |||||
/// <param name="url">The URL to download.</param> | |||||
/// <param name="headers">An optional Dictionary containing the HTTP | |||||
/// request headers.</param> | |||||
/// <param name="fetchAlways">Force a web request to always be issued, skipping the cache.</param> | |||||
/// <param name="absoluteExpiration">An optional expiration date.</param> | |||||
/// <returns>The data downloaded from the URL.</returns> | |||||
public IObservable<byte[]> DownloadUrl(IBlobCache This, string key, string url, IDictionary<string, string> headers = null, bool fetchAlways = false, DateTimeOffset? absoluteExpiration = null) | |||||
{ | |||||
var doFetch = MakeWebRequest(new Uri(url), headers).SelectMany(x => ProcessWebResponse(x, url, absoluteExpiration)); | |||||
var fetchAndCache = doFetch.SelectMany(x => This.Insert(key, x, absoluteExpiration).Select(_ => x)); | |||||
var ret = default(IObservable<byte[]>); | |||||
if (!fetchAlways) | |||||
{ | |||||
ret = This.Get(key).Catch(fetchAndCache); | |||||
} | |||||
else | |||||
{ | |||||
ret = fetchAndCache; | |||||
} | |||||
var conn = ret.PublishLast(); | |||||
conn.Connect(); | |||||
return conn; | |||||
} | |||||
IObservable<byte[]> ProcessWebResponse(WebResponse wr, string url, DateTimeOffset? absoluteExpiration) | |||||
{ | |||||
var hwr = (HttpWebResponse)wr; | |||||
Debug.Assert(hwr != null, "The Web Response is somehow null but shouldn't be."); | |||||
if ((int)hwr.StatusCode >= 400) | |||||
{ | |||||
return Observable.Throw<byte[]>(new WebException(hwr.StatusDescription)); | |||||
} | |||||
var ms = new MemoryStream(); | |||||
using (var responseStream = hwr.GetResponseStream()) | |||||
{ | |||||
Debug.Assert(responseStream != null, "The response stream is somehow null"); | |||||
responseStream.CopyTo(ms); | |||||
} | |||||
var ret = ms.ToArray(); | |||||
return Observable.Return(ret); | |||||
} | |||||
static IObservable<WebResponse> MakeWebRequest( | |||||
Uri uri, | |||||
IDictionary<string, string> headers = null, | |||||
string content = null, | |||||
int retries = 3, | |||||
TimeSpan? timeout = null) | |||||
{ | |||||
IObservable<WebResponse> request; | |||||
request = Observable.Defer(() => | |||||
{ | |||||
var hwr = CreateWebRequest(uri, headers); | |||||
if (content == null) | |||||
return Observable.FromAsyncPattern<WebResponse>(hwr.BeginGetResponse, hwr.EndGetResponse)(); | |||||
var buf = Encoding.UTF8.GetBytes(content); | |||||
// NB: You'd think that BeginGetResponse would never block, | |||||
// seeing as how it's asynchronous. You'd be wrong :-/ | |||||
var ret = new AsyncSubject<WebResponse>(); | |||||
Observable.Start(() => | |||||
{ | |||||
Observable.FromAsyncPattern<Stream>(hwr.BeginGetRequestStream, hwr.EndGetRequestStream)() | |||||
.SelectMany(x => WriteAsyncRx(x, buf, 0, buf.Length)) | |||||
.SelectMany(_ => Observable.FromAsyncPattern<WebResponse>(hwr.BeginGetResponse, hwr.EndGetResponse)()) | |||||
.Multicast(ret).Connect(); | |||||
}, BlobCache.TaskpoolScheduler); | |||||
return ret; | |||||
}); | |||||
return request.Timeout(timeout ?? TimeSpan.FromSeconds(15), BlobCache.TaskpoolScheduler).Retry(retries); | |||||
} | |||||
private static WebRequest CreateWebRequest(Uri uri, IDictionary<string, string> headers) | |||||
{ | |||||
var hwr = WebRequest.Create(uri); | |||||
if (headers != null) | |||||
{ | |||||
foreach (var x in headers) | |||||
{ | |||||
hwr.Headers[x.Key] = x.Value; | |||||
} | |||||
} | |||||
return hwr; | |||||
} | |||||
private static IObservable<Unit> WriteAsyncRx(Stream stream, byte[] data, int start, int length) | |||||
{ | |||||
return stream.WriteAsync(data, start, length).ToObservable(); | |||||
} | |||||
} | |||||
} |
@@ -1,33 +0,0 @@ | |||||
using Newtonsoft.Json; | |||||
using System.IO; | |||||
using System; | |||||
namespace Discord | |||||
{ | |||||
internal class TestConfig | |||||
{ | |||||
[JsonProperty("token")] | |||||
public string Token { get; private set; } | |||||
[JsonProperty("guild_id")] | |||||
public ulong GuildId { get; private set; } | |||||
public static TestConfig LoadFile(string path) | |||||
{ | |||||
if (File.Exists(path)) | |||||
{ | |||||
using (var stream = new FileStream(path, FileMode.Open)) | |||||
using (var reader = new StreamReader(stream)) | |||||
using (var jsonReader = new JsonTextReader(reader)) | |||||
return new JsonSerializer().Deserialize<TestConfig>(jsonReader); | |||||
} | |||||
else | |||||
{ | |||||
return new TestConfig() | |||||
{ | |||||
Token = Environment.GetEnvironmentVariable("DNET_TEST_TOKEN"), | |||||
GuildId = ulong.Parse(Environment.GetEnvironmentVariable("DNET_TEST_GUILDID")) | |||||
}; | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,177 +0,0 @@ | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
public class ChannelPermissionsTests | |||||
{ | |||||
// seems like all these tests are broken | |||||
/*[Fact] | |||||
public Task TestChannelPermission() | |||||
{ | |||||
var perm = new ChannelPermissions(); | |||||
// check initial values | |||||
Assert.Equal((ulong)0, perm.RawValue); | |||||
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue); | |||||
// permissions list empty by default | |||||
Assert.Empty(perm.ToList()); | |||||
// test modify with no parameters | |||||
var copy = perm.Modify(); | |||||
Assert.Equal((ulong)0, copy.RawValue); | |||||
// test modify with no parameters after using all | |||||
copy = ChannelPermissions.Text; | |||||
var modified = copy.Modify(); // no params should not change the result | |||||
Assert.Equal(ChannelPermissions.Text.RawValue, modified.RawValue); | |||||
copy = ChannelPermissions.Voice; | |||||
modified = copy.Modify(); // no params should not change the result | |||||
Assert.Equal(ChannelPermissions.Voice.RawValue, modified.RawValue); | |||||
copy = ChannelPermissions.Group; | |||||
modified = copy.Modify(); // no params should not change the result | |||||
Assert.Equal(ChannelPermissions.Group.RawValue, modified.RawValue); | |||||
copy = ChannelPermissions.DM; | |||||
modified = copy.Modify(); // no params should not change the result | |||||
Assert.Equal(ChannelPermissions.DM.RawValue, modified.RawValue); | |||||
copy = new ChannelPermissions(useExternalEmojis: true); | |||||
modified = copy.Modify(); | |||||
Assert.Equal(copy.RawValue, modified.RawValue); | |||||
// test the values that are returned by ChannelPermission.All | |||||
Assert.Equal((ulong)0, ChannelPermissions.None.RawValue); | |||||
// for text channels | |||||
ulong textChannel = (ulong)( ChannelPermission.CreateInstantInvite | |||||
| ChannelPermission.ManageChannels | |||||
| ChannelPermission.AddReactions | |||||
| ChannelPermission.ViewChannel | |||||
| ChannelPermission.SendMessages | |||||
| ChannelPermission.SendTTSMessages | |||||
| ChannelPermission.ManageMessages | |||||
| ChannelPermission.EmbedLinks | |||||
| ChannelPermission.AttachFiles | |||||
| ChannelPermission.ReadMessageHistory | |||||
| ChannelPermission.MentionEveryone | |||||
| ChannelPermission.UseExternalEmojis | |||||
| ChannelPermission.ManageRoles | |||||
| ChannelPermission.ManageWebhooks); | |||||
Assert.Equal(textChannel, ChannelPermissions.Text.RawValue); | |||||
// voice channels | |||||
ulong voiceChannel = (ulong)( | |||||
ChannelPermission.CreateInstantInvite | |||||
| ChannelPermission.ManageChannels | |||||
| ChannelPermission.ViewChannel | |||||
| ChannelPermission.Connect | |||||
| ChannelPermission.Speak | |||||
| ChannelPermission.MuteMembers | |||||
| ChannelPermission.DeafenMembers | |||||
| ChannelPermission.MoveMembers | |||||
| ChannelPermission.UseVAD | |||||
| ChannelPermission.ManageRoles | |||||
| ChannelPermission.PrioritySpeaker); | |||||
Assert.Equal(voiceChannel, ChannelPermissions.Voice.RawValue); | |||||
// DM Channels | |||||
ulong dmChannel = (ulong)( | |||||
ChannelPermission.ViewChannel | |||||
| ChannelPermission.SendMessages | |||||
| ChannelPermission.EmbedLinks | |||||
| ChannelPermission.AttachFiles | |||||
| ChannelPermission.ReadMessageHistory | |||||
| ChannelPermission.UseExternalEmojis | |||||
| ChannelPermission.Connect | |||||
| ChannelPermission.Speak | |||||
| ChannelPermission.UseVAD | |||||
); | |||||
//Assert.Equal(dmChannel, ChannelPermissions.DM.RawValue); | |||||
// TODO: this test is failing and that's a bad thing | |||||
// group channel | |||||
ulong groupChannel = (ulong)( | |||||
ChannelPermission.SendMessages | |||||
| ChannelPermission.EmbedLinks | |||||
| ChannelPermission.AttachFiles | |||||
| ChannelPermission.SendTTSMessages | |||||
| ChannelPermission.Connect | |||||
| ChannelPermission.Speak | |||||
| ChannelPermission.UseVAD | |||||
); | |||||
// TODO: this test is also broken | |||||
//Assert.Equal(groupChannel, ChannelPermissions.Group.RawValue); | |||||
return Task.CompletedTask; | |||||
}*/ | |||||
[Fact] | |||||
public Task TestChannelPermissionModify() | |||||
{ | |||||
// test that channel permissions could be modified correctly | |||||
var perm = new ChannelPermissions(); | |||||
void Check(ChannelPermission permission, | |||||
Func<ChannelPermissions, bool> has, | |||||
Func<ChannelPermissions, bool, ChannelPermissions> modify) | |||||
{ | |||||
// ensure permission initially false | |||||
// use both the function and Has to ensure that the GetPermission | |||||
// function is working | |||||
Assert.False(has(perm)); | |||||
Assert.False(perm.Has(permission)); | |||||
// enable it, and ensure that it gets set | |||||
perm = modify(perm, true); | |||||
Assert.True(has(perm)); | |||||
Assert.True(perm.Has(permission)); | |||||
// set it false again | |||||
perm = modify(perm, false); | |||||
Assert.False(has(perm)); | |||||
Assert.False(perm.Has(permission)); | |||||
// ensure that no perms are set now | |||||
Assert.Equal(ChannelPermissions.None.RawValue, perm.RawValue); | |||||
} | |||||
Check(ChannelPermission.CreateInstantInvite, x => x.CreateInstantInvite, (p, enable) => p.Modify(createInstantInvite: enable)); | |||||
Check(ChannelPermission.ManageChannels, x => x.ManageChannel, (p, enable) => p.Modify(manageChannel: enable)); | |||||
Check(ChannelPermission.AddReactions, x => x.AddReactions, (p, enable) => p.Modify(addReactions: enable)); | |||||
Check(ChannelPermission.ViewChannel, x => x.ViewChannel, (p, enable) => p.Modify(viewChannel: enable)); | |||||
Check(ChannelPermission.SendMessages, x => x.SendMessages, (p, enable) => p.Modify(sendMessages: enable)); | |||||
Check(ChannelPermission.SendTTSMessages, x => x.SendTTSMessages, (p, enable) => p.Modify(sendTTSMessages: enable)); | |||||
Check(ChannelPermission.ManageMessages, x => x.ManageMessages, (p, enable) => p.Modify(manageMessages: enable)); | |||||
Check(ChannelPermission.EmbedLinks, x => x.EmbedLinks, (p, enable) => p.Modify(embedLinks: enable)); | |||||
Check(ChannelPermission.AttachFiles, x => x.AttachFiles, (p, enable) => p.Modify(attachFiles: enable)); | |||||
Check(ChannelPermission.ReadMessageHistory, x => x.ReadMessageHistory, (p, enable) => p.Modify(readMessageHistory: enable)); | |||||
Check(ChannelPermission.MentionEveryone, x => x.MentionEveryone, (p, enable) => p.Modify(mentionEveryone: enable)); | |||||
Check(ChannelPermission.UseExternalEmojis, x => x.UseExternalEmojis, (p, enable) => p.Modify(useExternalEmojis: enable)); | |||||
Check(ChannelPermission.Connect, x => x.Connect, (p, enable) => p.Modify(connect: enable)); | |||||
Check(ChannelPermission.Speak, x => x.Speak, (p, enable) => p.Modify(speak: enable)); | |||||
Check(ChannelPermission.MuteMembers, x => x.MuteMembers, (p, enable) => p.Modify(muteMembers: enable)); | |||||
Check(ChannelPermission.DeafenMembers, x => x.DeafenMembers, (p, enable) => p.Modify(deafenMembers: enable)); | |||||
Check(ChannelPermission.MoveMembers, x => x.MoveMembers, (p, enable) => p.Modify(moveMembers: enable)); | |||||
Check(ChannelPermission.UseVAD, x => x.UseVAD, (p, enable) => p.Modify(useVoiceActivation: enable)); | |||||
Check(ChannelPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable)); | |||||
Check(ChannelPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable)); | |||||
Check(ChannelPermission.PrioritySpeaker, x => x.PrioritySpeaker, (p, enable) => p.Modify(prioritySpeaker: enable)); | |||||
return Task.CompletedTask; | |||||
} | |||||
[Fact] | |||||
public Task TestChannelTypeResolution() | |||||
{ | |||||
ITextChannel someChannel = null; | |||||
// null channels will throw exception | |||||
Assert.Throws<ArgumentException>(() => ChannelPermissions.All(someChannel)); | |||||
return Task.CompletedTask; | |||||
} | |||||
} | |||||
} |
@@ -1,218 +0,0 @@ | |||||
using Discord.Rest; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
#if IXTEST | |||||
namespace Discord | |||||
{ | |||||
public partial class Tests | |||||
{ | |||||
internal static async Task Migration_CreateTextChannels(DiscordRestClient client, RestGuild guild) | |||||
{ | |||||
var text1 = await guild.GetDefaultChannelAsync(); | |||||
var text2 = await guild.CreateTextChannelAsync("text2"); | |||||
var text3 = await guild.CreateTextChannelAsync("text3"); | |||||
var text4 = await guild.CreateTextChannelAsync("text4"); | |||||
var text5 = await guild.CreateTextChannelAsync("text5"); | |||||
// create a channel category | |||||
var cat1 = await guild.CreateCategoryChannelAsync("cat1"); | |||||
if (text1 == null) | |||||
{ | |||||
// the guild did not have a default channel, so make a new one | |||||
text1 = await guild.CreateTextChannelAsync("default"); | |||||
} | |||||
//Modify #general | |||||
await text1.ModifyAsync(x => | |||||
{ | |||||
x.Name = "text1"; | |||||
x.Position = 1; | |||||
x.Topic = "Topic1"; | |||||
x.CategoryId = cat1.Id; | |||||
}); | |||||
await text2.ModifyAsync(x => | |||||
{ | |||||
x.Position = 2; | |||||
x.CategoryId = cat1.Id; | |||||
}); | |||||
await text3.ModifyAsync(x => | |||||
{ | |||||
x.Topic = "Topic2"; | |||||
}); | |||||
await text4.ModifyAsync(x => | |||||
{ | |||||
x.Position = 3; | |||||
x.Topic = "Topic2"; | |||||
}); | |||||
await text5.ModifyAsync(x => | |||||
{ | |||||
}); | |||||
CheckTextChannels(guild, text1, text2, text3, text4, text5); | |||||
} | |||||
[Fact] | |||||
public async Task TestTextChannels() | |||||
{ | |||||
CheckTextChannels(_guild, (await _guild.GetTextChannelsAsync()).ToArray()); | |||||
} | |||||
private static void CheckTextChannels(RestGuild guild, params RestTextChannel[] textChannels) | |||||
{ | |||||
Assert.Equal(5, textChannels.Length); | |||||
Assert.All(textChannels, x => | |||||
{ | |||||
Assert.NotNull(x); | |||||
Assert.NotEqual(0UL, x.Id); | |||||
Assert.True(x.Position >= 0); | |||||
}); | |||||
var text1 = textChannels.FirstOrDefault(x => x.Name == "text1"); | |||||
var text2 = textChannels.FirstOrDefault(x => x.Name == "text2"); | |||||
var text3 = textChannels.FirstOrDefault(x => x.Name == "text3"); | |||||
var text4 = textChannels.FirstOrDefault(x => x.Name == "text4"); | |||||
var text5 = textChannels.FirstOrDefault(x => x.Name == "text5"); | |||||
Assert.NotNull(text1); | |||||
//Assert.True(text1.Id == guild.DefaultChannelId); | |||||
Assert.Equal(1, text1.Position); | |||||
Assert.Equal("Topic1", text1.Topic); | |||||
Assert.NotNull(text2); | |||||
Assert.Equal(2, text2.Position); | |||||
Assert.Null(text2.Topic); | |||||
Assert.NotNull(text3); | |||||
Assert.Equal("Topic2", text3.Topic); | |||||
Assert.NotNull(text4); | |||||
Assert.Equal(3, text4.Position); | |||||
Assert.Equal("Topic2", text4.Topic); | |||||
Assert.NotNull(text5); | |||||
Assert.Null(text5.Topic); | |||||
} | |||||
internal static async Task Migration_CreateVoiceChannels(DiscordRestClient client, RestGuild guild) | |||||
{ | |||||
var voice1 = await guild.CreateVoiceChannelAsync("voice1"); | |||||
var voice2 = await guild.CreateVoiceChannelAsync("voice2"); | |||||
var voice3 = await guild.CreateVoiceChannelAsync("voice3"); | |||||
var cat2 = await guild.CreateCategoryChannelAsync("cat2"); | |||||
await voice1.ModifyAsync(x => | |||||
{ | |||||
x.Bitrate = 96000; | |||||
x.Position = 1; | |||||
x.CategoryId = cat2.Id; | |||||
}); | |||||
await voice2.ModifyAsync(x => | |||||
{ | |||||
x.UserLimit = null; | |||||
}); | |||||
await voice3.ModifyAsync(x => | |||||
{ | |||||
x.Bitrate = 8000; | |||||
x.Position = 1; | |||||
x.UserLimit = 16; | |||||
x.CategoryId = cat2.Id; | |||||
}); | |||||
CheckVoiceChannels(voice1, voice2, voice3); | |||||
} | |||||
[Fact] | |||||
public async Task TestVoiceChannels() | |||||
{ | |||||
CheckVoiceChannels((await _guild.GetVoiceChannelsAsync()).ToArray()); | |||||
} | |||||
private static void CheckVoiceChannels(params RestVoiceChannel[] voiceChannels) | |||||
{ | |||||
Assert.Equal(3, voiceChannels.Length); | |||||
Assert.All(voiceChannels, x => | |||||
{ | |||||
Assert.NotNull(x); | |||||
Assert.NotEqual(0UL, x.Id); | |||||
Assert.NotEqual(0, x.UserLimit); | |||||
Assert.True(x.Bitrate > 0); | |||||
Assert.True(x.Position >= 0); | |||||
}); | |||||
var voice1 = voiceChannels.FirstOrDefault(x => x.Name == "voice1"); | |||||
var voice2 = voiceChannels.FirstOrDefault(x => x.Name == "voice2"); | |||||
var voice3 = voiceChannels.FirstOrDefault(x => x.Name == "voice3"); | |||||
Assert.NotNull(voice1); | |||||
Assert.Equal(96000, voice1.Bitrate); | |||||
Assert.Equal(1, voice1.Position); | |||||
Assert.NotNull(voice2); | |||||
Assert.Null(voice2.UserLimit); | |||||
Assert.NotNull(voice3); | |||||
Assert.Equal(8000, voice3.Bitrate); | |||||
Assert.Equal(1, voice3.Position); | |||||
Assert.Equal(16, voice3.UserLimit); | |||||
} | |||||
[Fact] | |||||
public async Task TestChannelCategories() | |||||
{ | |||||
// (await _guild.GetVoiceChannelsAsync()).ToArray() | |||||
var channels = await _guild.GetCategoryChannelsAsync(); | |||||
await CheckChannelCategories(channels.ToArray(), (await _guild.GetChannelsAsync()).ToArray()); | |||||
} | |||||
private async Task CheckChannelCategories(RestCategoryChannel[] categories, RestGuildChannel[] allChannels) | |||||
{ | |||||
// 2 categories | |||||
Assert.Equal(2, categories.Length); | |||||
var cat1 = categories.FirstOrDefault(x => x.Name == "cat1"); | |||||
var cat2 = categories.FirstOrDefault(x => x.Name == "cat2"); | |||||
Assert.NotNull(cat1); | |||||
Assert.NotNull(cat2); | |||||
// get text1, text2, ensure they have category id == cat1 | |||||
var text1 = allChannels.FirstOrDefault(x => x.Name == "text1") as RestTextChannel; | |||||
var text2 = allChannels.FirstOrDefault(x => x.Name == "text2") as RestTextChannel; | |||||
Assert.NotNull(text1); | |||||
Assert.NotNull(text2); | |||||
// check that CategoryID and .GetCategoryAsync work correctly | |||||
// for both of the text channels | |||||
Assert.Equal(text1.CategoryId, cat1.Id); | |||||
var text1Cat = await text1.GetCategoryAsync(); | |||||
Assert.Equal(text1Cat.Id, cat1.Id); | |||||
Assert.Equal(text1Cat.Name, cat1.Name); | |||||
Assert.Equal(text2.CategoryId, cat1.Id); | |||||
var text2Cat = await text2.GetCategoryAsync(); | |||||
Assert.Equal(text2Cat.Id, cat1.Id); | |||||
Assert.Equal(text2Cat.Name, cat1.Name); | |||||
// do the same for the voice channels | |||||
var voice1 = allChannels.FirstOrDefault(x => x.Name == "voice1") as RestVoiceChannel; | |||||
var voice3 = allChannels.FirstOrDefault(x => x.Name == "voice3") as RestVoiceChannel; | |||||
Assert.NotNull(voice1); | |||||
Assert.NotNull(voice3); | |||||
Assert.Equal(voice1.CategoryId, cat2.Id); | |||||
var voice1Cat = await voice1.GetCategoryAsync(); | |||||
Assert.Equal(voice1Cat.Id, cat2.Id); | |||||
Assert.Equal(voice1Cat.Name, cat2.Name); | |||||
Assert.Equal(voice3.CategoryId, cat2.Id); | |||||
var voice3Cat = await voice3.GetCategoryAsync(); | |||||
Assert.Equal(voice3Cat.Id, cat2.Id); | |||||
Assert.Equal(voice3Cat.Name, cat2.Name); | |||||
} | |||||
} | |||||
} | |||||
#endif |
@@ -1,342 +0,0 @@ | |||||
using System; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
#if IXTEST | |||||
namespace Discord | |||||
{ | |||||
public partial class Tests | |||||
{ | |||||
/// <summary> | |||||
/// Tests the behavior of modifying the ExplicitContentFilter property of a Guild. | |||||
/// </summary> | |||||
[Fact] | |||||
public async Task TestExplicitContentFilter() | |||||
{ | |||||
foreach (var level in Enum.GetValues(typeof(ExplicitContentFilterLevel))) | |||||
{ | |||||
await _guild.ModifyAsync(x => x.ExplicitContentFilter = (ExplicitContentFilterLevel)level); | |||||
await _guild.UpdateAsync(); | |||||
Assert.Equal(level, _guild.ExplicitContentFilter); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Tests the behavior of the GuildPermissions class. | |||||
/// </summary> | |||||
[Fact] | |||||
public Task TestGuildPermission() | |||||
{ | |||||
// Test Guild Permission Constructors | |||||
var perm = new GuildPermissions(); | |||||
// the default raw value is 0 | |||||
Assert.Equal((ulong)0, perm.RawValue); | |||||
// also check that it is the same as none | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// permissions list is empty by default | |||||
Assert.Empty(perm.ToList()); | |||||
Assert.NotNull(perm.ToList()); | |||||
// Test modify with no parameters | |||||
var copy = perm.Modify(); | |||||
// ensure that the raw values match | |||||
Assert.Equal((ulong)0, copy.RawValue); | |||||
// test modify with no parameters | |||||
copy = GuildPermissions.None.Modify(); | |||||
Assert.Equal(GuildPermissions.None.RawValue, copy.RawValue); | |||||
// test modify with no parameters on all permissions | |||||
copy = GuildPermissions.All.Modify(); | |||||
Assert.Equal(GuildPermissions.All.RawValue, copy.RawValue); | |||||
// test modify with no parameters on webhook permissions | |||||
copy = GuildPermissions.Webhook.Modify(); | |||||
Assert.Equal(GuildPermissions.Webhook.RawValue, copy.RawValue); | |||||
// Get all distinct values (ReadMessages = ViewChannel) | |||||
var enumValues = (Enum.GetValues(typeof(GuildPermission)) as GuildPermission[]) | |||||
.Distinct() | |||||
.ToArray(); | |||||
// test GuildPermissions.All | |||||
ulong sumOfAllGuildPermissions = 0; | |||||
foreach(var v in enumValues) | |||||
{ | |||||
sumOfAllGuildPermissions |= (ulong)v; | |||||
} | |||||
// assert that the raw values match | |||||
Assert.Equal(sumOfAllGuildPermissions, GuildPermissions.All.RawValue); | |||||
Assert.Equal((ulong)0, GuildPermissions.None.RawValue); | |||||
// assert that GuildPermissions.All contains the same number of permissions as the | |||||
// GuildPermissions enum | |||||
Assert.Equal(enumValues.Length, GuildPermissions.All.ToList().Count); | |||||
// assert that webhook has the same raw value | |||||
ulong webHookPermissions = (ulong)( | |||||
GuildPermission.SendMessages | GuildPermission.SendTTSMessages | GuildPermission.EmbedLinks | | |||||
GuildPermission.AttachFiles); | |||||
Assert.Equal(webHookPermissions, GuildPermissions.Webhook.RawValue); | |||||
return Task.CompletedTask; | |||||
} | |||||
[Fact] | |||||
public Task TestGuildPermissionModify() | |||||
{ | |||||
var perm = new GuildPermissions(); | |||||
// tests each of the parameters of Modify one by one | |||||
// test modify with each of the parameters | |||||
// test initially false state | |||||
Assert.False(perm.CreateInstantInvite); | |||||
// ensure that when we modify it the parameter works | |||||
perm = perm.Modify(createInstantInvite: true); | |||||
Assert.True(perm.CreateInstantInvite); | |||||
Assert.Equal((ulong)GuildPermission.CreateInstantInvite, perm.RawValue); | |||||
// set it false again, then move on to the next permission | |||||
perm = perm.Modify(createInstantInvite: false); | |||||
Assert.False(perm.CreateInstantInvite); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(kickMembers: true); | |||||
Assert.True(perm.KickMembers); | |||||
Assert.Equal((ulong)GuildPermission.KickMembers, perm.RawValue); | |||||
perm = perm.Modify(kickMembers: false); | |||||
Assert.False(perm.KickMembers); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(banMembers: true); | |||||
Assert.True(perm.BanMembers); | |||||
Assert.Equal((ulong)GuildPermission.BanMembers, perm.RawValue); | |||||
perm = perm.Modify(banMembers: false); | |||||
Assert.False(perm.BanMembers); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(administrator: true); | |||||
Assert.True(perm.Administrator); | |||||
Assert.Equal((ulong)GuildPermission.Administrator, perm.RawValue); | |||||
perm = perm.Modify(administrator: false); | |||||
Assert.False(perm.Administrator); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(manageChannels: true); | |||||
Assert.True(perm.ManageChannels); | |||||
Assert.Equal((ulong)GuildPermission.ManageChannels, perm.RawValue); | |||||
perm = perm.Modify(manageChannels: false); | |||||
Assert.False(perm.ManageChannels); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(manageGuild: true); | |||||
Assert.True(perm.ManageGuild); | |||||
Assert.Equal((ulong)GuildPermission.ManageGuild, perm.RawValue); | |||||
perm = perm.Modify(manageGuild: false); | |||||
Assert.False(perm.ManageGuild); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(addReactions: true); | |||||
Assert.True(perm.AddReactions); | |||||
Assert.Equal((ulong)GuildPermission.AddReactions, perm.RawValue); | |||||
perm = perm.Modify(addReactions: false); | |||||
Assert.False(perm.AddReactions); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(viewAuditLog: true); | |||||
Assert.True(perm.ViewAuditLog); | |||||
Assert.Equal((ulong)GuildPermission.ViewAuditLog, perm.RawValue); | |||||
perm = perm.Modify(viewAuditLog: false); | |||||
Assert.False(perm.ViewAuditLog); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(viewChannel: true); | |||||
Assert.True(perm.ViewChannel); | |||||
Assert.Equal((ulong)GuildPermission.ViewChannel, perm.RawValue); | |||||
perm = perm.Modify(viewChannel: false); | |||||
Assert.False(perm.ViewChannel); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(sendMessages: true); | |||||
Assert.True(perm.SendMessages); | |||||
Assert.Equal((ulong)GuildPermission.SendMessages, perm.RawValue); | |||||
perm = perm.Modify(sendMessages: false); | |||||
Assert.False(perm.SendMessages); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(embedLinks: true); | |||||
Assert.True(perm.EmbedLinks); | |||||
Assert.Equal((ulong)GuildPermission.EmbedLinks, perm.RawValue); | |||||
perm = perm.Modify(embedLinks: false); | |||||
Assert.False(perm.EmbedLinks); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(attachFiles: true); | |||||
Assert.True(perm.AttachFiles); | |||||
Assert.Equal((ulong)GuildPermission.AttachFiles, perm.RawValue); | |||||
perm = perm.Modify(attachFiles: false); | |||||
Assert.False(perm.AttachFiles); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(readMessageHistory: true); | |||||
Assert.True(perm.ReadMessageHistory); | |||||
Assert.Equal((ulong)GuildPermission.ReadMessageHistory, perm.RawValue); | |||||
perm = perm.Modify(readMessageHistory: false); | |||||
Assert.False(perm.ReadMessageHistory); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(mentionEveryone: true); | |||||
Assert.True(perm.MentionEveryone); | |||||
Assert.Equal((ulong)GuildPermission.MentionEveryone, perm.RawValue); | |||||
perm = perm.Modify(mentionEveryone: false); | |||||
Assert.False(perm.MentionEveryone); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(useExternalEmojis: true); | |||||
Assert.True(perm.UseExternalEmojis); | |||||
Assert.Equal((ulong)GuildPermission.UseExternalEmojis, perm.RawValue); | |||||
perm = perm.Modify(useExternalEmojis: false); | |||||
Assert.False(perm.UseExternalEmojis); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(connect: true); | |||||
Assert.True(perm.Connect); | |||||
Assert.Equal((ulong)GuildPermission.Connect, perm.RawValue); | |||||
perm = perm.Modify(connect: false); | |||||
Assert.False(perm.Connect); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(speak: true); | |||||
Assert.True(perm.Speak); | |||||
Assert.Equal((ulong)GuildPermission.Speak, perm.RawValue); | |||||
perm = perm.Modify(speak: false); | |||||
Assert.False(perm.Speak); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(muteMembers: true); | |||||
Assert.True(perm.MuteMembers); | |||||
Assert.Equal((ulong)GuildPermission.MuteMembers, perm.RawValue); | |||||
perm = perm.Modify(muteMembers: false); | |||||
Assert.False(perm.MuteMembers); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(deafenMembers: true); | |||||
Assert.True(perm.DeafenMembers); | |||||
Assert.Equal((ulong)GuildPermission.DeafenMembers, perm.RawValue); | |||||
perm = perm.Modify(deafenMembers: false); | |||||
Assert.False(perm.DeafenMembers); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(moveMembers: true); | |||||
Assert.True(perm.MoveMembers); | |||||
Assert.Equal((ulong)GuildPermission.MoveMembers, perm.RawValue); | |||||
perm = perm.Modify(moveMembers: false); | |||||
Assert.False(perm.MoveMembers); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(useVoiceActivation: true); | |||||
Assert.True(perm.UseVAD); | |||||
Assert.Equal((ulong)GuildPermission.UseVAD, perm.RawValue); | |||||
perm = perm.Modify(useVoiceActivation: false); | |||||
Assert.False(perm.UseVAD); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(changeNickname: true); | |||||
Assert.True(perm.ChangeNickname); | |||||
Assert.Equal((ulong)GuildPermission.ChangeNickname, perm.RawValue); | |||||
perm = perm.Modify(changeNickname: false); | |||||
Assert.False(perm.ChangeNickname); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(manageNicknames: true); | |||||
Assert.True(perm.ManageNicknames); | |||||
Assert.Equal((ulong)GuildPermission.ManageNicknames, perm.RawValue); | |||||
perm = perm.Modify(manageNicknames: false); | |||||
Assert.False(perm.ManageNicknames); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(manageRoles: true); | |||||
Assert.True(perm.ManageRoles); | |||||
Assert.Equal((ulong)GuildPermission.ManageRoles, perm.RawValue); | |||||
perm = perm.Modify(manageRoles: false); | |||||
Assert.False(perm.ManageRoles); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(manageWebhooks: true); | |||||
Assert.True(perm.ManageWebhooks); | |||||
Assert.Equal((ulong)GuildPermission.ManageWebhooks, perm.RawValue); | |||||
perm = perm.Modify(manageWebhooks: false); | |||||
Assert.False(perm.ManageWebhooks); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
// individual permission test | |||||
perm = perm.Modify(manageEmojis: true); | |||||
Assert.True(perm.ManageEmojis); | |||||
Assert.Equal((ulong)GuildPermission.ManageEmojis, perm.RawValue); | |||||
perm = perm.Modify(manageEmojis: false); | |||||
Assert.False(perm.ManageEmojis); | |||||
Assert.Equal(GuildPermissions.None.RawValue, perm.RawValue); | |||||
return Task.CompletedTask; | |||||
} | |||||
} | |||||
} | |||||
#endif |
@@ -1,73 +0,0 @@ | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
using Discord.Rest; | |||||
#if IXTEST | |||||
namespace Discord | |||||
{ | |||||
public partial class TestsFixture | |||||
{ | |||||
public const uint MigrationCount = 3; | |||||
public async Task MigrateAsync() | |||||
{ | |||||
DiscordRestClient client = null; | |||||
RestGuild guild = null; | |||||
await _cache.LoadInfoAsync(_config.GuildId).ConfigureAwait(false); | |||||
while (_cache.Info.Version != MigrationCount) | |||||
{ | |||||
if (client == null) | |||||
{ | |||||
client = new DiscordRestClient(); | |||||
await client.LoginAsync(TokenType.Bot, _config.Token).ConfigureAwait(false); | |||||
guild = await client.GetGuildAsync(_config.GuildId); | |||||
} | |||||
uint nextVer = _cache.Info.Version + 1; | |||||
try | |||||
{ | |||||
await DoMigrateAsync(client, guild, nextVer).ConfigureAwait(false); | |||||
_cache.Info.Version = nextVer; | |||||
await _cache.SaveInfoAsync().ConfigureAwait(false); | |||||
} | |||||
catch | |||||
{ | |||||
await _cache.ClearAsync().ConfigureAwait(false); | |||||
throw; | |||||
} | |||||
} | |||||
} | |||||
private static Task DoMigrateAsync(DiscordRestClient client, RestGuild guild, uint toVersion) | |||||
{ | |||||
switch (toVersion) | |||||
{ | |||||
case 1: return Migration_WipeGuild(client, guild); | |||||
case 2: return Tests.Migration_CreateTextChannels(client, guild); | |||||
case 3: return Tests.Migration_CreateVoiceChannels(client, guild); | |||||
default: throw new InvalidOperationException("Unknown migration: " + toVersion); | |||||
} | |||||
} | |||||
private static async Task Migration_WipeGuild(DiscordRestClient client, RestGuild guild) | |||||
{ | |||||
var textChannels = await guild.GetTextChannelsAsync(); | |||||
var voiceChannels = await guild.GetVoiceChannelsAsync(); | |||||
var roles = guild.Roles; | |||||
foreach (var channel in textChannels) | |||||
{ | |||||
//if (channel.Id != guild.DefaultChannelId) | |||||
await channel.DeleteAsync(); | |||||
} | |||||
foreach (var channel in voiceChannels) | |||||
await channel.DeleteAsync(); | |||||
foreach (var role in roles) | |||||
{ | |||||
if (role.Id != guild.EveryoneRole.Id) | |||||
await role.DeleteAsync(); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
#endif |
@@ -1,772 +0,0 @@ | |||||
using System.Threading.Tasks; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
public class PermissionsTests | |||||
{ | |||||
private void TestHelper(ChannelPermissions value, ChannelPermission permission, bool expected = false) | |||||
=> TestHelper(value.RawValue, (ulong)permission, expected); | |||||
private void TestHelper(GuildPermissions value, GuildPermission permission, bool expected = false) | |||||
=> TestHelper(value.RawValue, (ulong)permission, expected); | |||||
/// <summary> | |||||
/// Tests the flag of the given permissions value to the expected output | |||||
/// and then tries to toggle the flag on and off | |||||
/// </summary> | |||||
/// <param name="rawValue"></param> | |||||
/// <param name="flagValue"></param> | |||||
/// <param name="expected"></param> | |||||
private void TestHelper(ulong rawValue, ulong flagValue, bool expected) | |||||
{ | |||||
Assert.Equal(expected, Permissions.GetValue(rawValue, flagValue)); | |||||
// check that toggling the bit works | |||||
Permissions.UnsetFlag(ref rawValue, flagValue); | |||||
Assert.False(Permissions.GetValue(rawValue, flagValue)); | |||||
Permissions.SetFlag(ref rawValue, flagValue); | |||||
Assert.True(Permissions.GetValue(rawValue, flagValue)); | |||||
// do the same, but with the SetValue method | |||||
Permissions.SetValue(ref rawValue, true, flagValue); | |||||
Assert.True(Permissions.GetValue(rawValue, flagValue)); | |||||
Permissions.SetValue(ref rawValue, false, flagValue); | |||||
Assert.False(Permissions.GetValue(rawValue, flagValue)); | |||||
} | |||||
/// <summary> | |||||
/// Tests that flag of the given permissions value to be the expected output | |||||
/// and then tries cycling through the states of the allow and deny values | |||||
/// for that flag | |||||
/// </summary> | |||||
/// <param name="value"></param> | |||||
/// <param name="flag"></param> | |||||
/// <param name="expected"></param> | |||||
private void TestHelper(OverwritePermissions value, ChannelPermission flag, PermValue expected) | |||||
{ | |||||
// check that the value matches | |||||
Assert.Equal(expected, Permissions.GetValue(value.AllowValue, value.DenyValue, flag)); | |||||
// check toggling bits for both allow and deny | |||||
// have to make copies to get around read only property | |||||
ulong allow = value.AllowValue; | |||||
ulong deny = value.DenyValue; | |||||
// both unset should be inherit | |||||
Permissions.UnsetFlag(ref allow, (ulong)flag); | |||||
Permissions.UnsetFlag(ref deny, (ulong)flag); | |||||
Assert.Equal(PermValue.Inherit, Permissions.GetValue(allow, deny, flag)); | |||||
// allow set should be allow | |||||
Permissions.SetFlag(ref allow, (ulong)flag); | |||||
Permissions.UnsetFlag(ref deny, (ulong)flag); | |||||
Assert.Equal(PermValue.Allow, Permissions.GetValue(allow, deny, flag)); | |||||
// deny should be deny | |||||
Permissions.UnsetFlag(ref allow, (ulong)flag); | |||||
Permissions.SetFlag(ref deny, (ulong)flag); | |||||
Assert.Equal(PermValue.Deny, Permissions.GetValue(allow, deny, flag)); | |||||
// allow takes precedence | |||||
Permissions.SetFlag(ref allow, (ulong)flag); | |||||
Permissions.SetFlag(ref deny, (ulong)flag); | |||||
Assert.Equal(PermValue.Allow, Permissions.GetValue(allow, deny, flag)); | |||||
} | |||||
/// <summary> | |||||
/// Tests for the <see cref="Discord.Permissions"/> class. | |||||
/// | |||||
/// Tests that text channel permissions get the right value | |||||
/// from the Has method. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestPermissionsHasChannelPermissionText() | |||||
{ | |||||
var value = ChannelPermissions.Text; | |||||
// check that the result of GetValue matches for all properties of text channel | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, true); | |||||
TestHelper(value, ChannelPermission.ManageChannels, true); | |||||
TestHelper(value, ChannelPermission.AddReactions, true); | |||||
TestHelper(value, ChannelPermission.ViewChannel, true); | |||||
TestHelper(value, ChannelPermission.SendMessages, true); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, true); | |||||
TestHelper(value, ChannelPermission.ManageMessages, true); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, true); | |||||
TestHelper(value, ChannelPermission.AttachFiles, true); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, true); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, true); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, true); | |||||
TestHelper(value, ChannelPermission.ManageRoles, true); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, true); | |||||
TestHelper(value, ChannelPermission.Connect, false); | |||||
TestHelper(value, ChannelPermission.Speak, false); | |||||
TestHelper(value, ChannelPermission.MuteMembers, false); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, false); | |||||
TestHelper(value, ChannelPermission.MoveMembers, false); | |||||
TestHelper(value, ChannelPermission.UseVAD, false); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Tests for the <see cref="Discord.Permissions"/> class. | |||||
/// | |||||
/// Tests that no channel permissions get the right value | |||||
/// from the Has method. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestPermissionsHasChannelPermissionNone() | |||||
{ | |||||
// check that none will fail all | |||||
var value = ChannelPermissions.None; | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, false); | |||||
TestHelper(value, ChannelPermission.ManageChannels, false); | |||||
TestHelper(value, ChannelPermission.AddReactions, false); | |||||
TestHelper(value, ChannelPermission.ViewChannel, false); | |||||
TestHelper(value, ChannelPermission.SendMessages, false); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, false); | |||||
TestHelper(value, ChannelPermission.ManageMessages, false); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, false); | |||||
TestHelper(value, ChannelPermission.AttachFiles, false); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, false); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, false); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, false); | |||||
TestHelper(value, ChannelPermission.ManageRoles, false); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, false); | |||||
TestHelper(value, ChannelPermission.Connect, false); | |||||
TestHelper(value, ChannelPermission.Speak, false); | |||||
TestHelper(value, ChannelPermission.MuteMembers, false); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, false); | |||||
TestHelper(value, ChannelPermission.MoveMembers, false); | |||||
TestHelper(value, ChannelPermission.UseVAD, false); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Tests for the <see cref="Discord.Permissions"/> class. | |||||
/// | |||||
/// Tests that the dm channel permissions get the right value | |||||
/// from the Has method. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestPermissionsHasChannelPermissionDM() | |||||
{ | |||||
// check that none will fail all | |||||
var value = ChannelPermissions.DM; | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, false); | |||||
TestHelper(value, ChannelPermission.ManageChannels, false); | |||||
TestHelper(value, ChannelPermission.AddReactions, false); | |||||
TestHelper(value, ChannelPermission.ViewChannel, true); | |||||
TestHelper(value, ChannelPermission.SendMessages, true); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, false); | |||||
TestHelper(value, ChannelPermission.ManageMessages, false); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, true); | |||||
TestHelper(value, ChannelPermission.AttachFiles, true); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, true); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, false); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, true); | |||||
TestHelper(value, ChannelPermission.ManageRoles, false); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, false); | |||||
TestHelper(value, ChannelPermission.Connect, true); | |||||
TestHelper(value, ChannelPermission.Speak, true); | |||||
TestHelper(value, ChannelPermission.MuteMembers, false); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, false); | |||||
TestHelper(value, ChannelPermission.MoveMembers, false); | |||||
TestHelper(value, ChannelPermission.UseVAD, true); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Tests for the <see cref="Discord.Permissions"/> class. | |||||
/// | |||||
/// Tests that the group channel permissions get the right value | |||||
/// from the Has method. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestPermissionsHasChannelPermissionGroup() | |||||
{ | |||||
var value = ChannelPermissions.Group; | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, false); | |||||
TestHelper(value, ChannelPermission.ManageChannels, false); | |||||
TestHelper(value, ChannelPermission.AddReactions, false); | |||||
TestHelper(value, ChannelPermission.ViewChannel, false); | |||||
TestHelper(value, ChannelPermission.SendMessages, true); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, true); | |||||
TestHelper(value, ChannelPermission.ManageMessages, false); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, true); | |||||
TestHelper(value, ChannelPermission.AttachFiles, true); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, false); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, false); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, false); | |||||
TestHelper(value, ChannelPermission.ManageRoles, false); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, false); | |||||
TestHelper(value, ChannelPermission.Connect, true); | |||||
TestHelper(value, ChannelPermission.Speak, true); | |||||
TestHelper(value, ChannelPermission.MuteMembers, false); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, false); | |||||
TestHelper(value, ChannelPermission.MoveMembers, false); | |||||
TestHelper(value, ChannelPermission.UseVAD, true); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Tests for the <see cref="Discord.Permissions"/> class. | |||||
/// | |||||
/// Tests that the voice channel permissions get the right value | |||||
/// from the Has method. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestPermissionsHasChannelPermissionVoice() | |||||
{ | |||||
// make a flag with all possible values for Voice channel permissions | |||||
var value = ChannelPermissions.Voice; | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, true); | |||||
TestHelper(value, ChannelPermission.ManageChannels, true); | |||||
TestHelper(value, ChannelPermission.AddReactions, false); | |||||
TestHelper(value, ChannelPermission.ViewChannel, true); | |||||
TestHelper(value, ChannelPermission.SendMessages, false); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, false); | |||||
TestHelper(value, ChannelPermission.ManageMessages, false); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, false); | |||||
TestHelper(value, ChannelPermission.AttachFiles, false); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, false); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, false); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, false); | |||||
TestHelper(value, ChannelPermission.ManageRoles, true); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, false); | |||||
TestHelper(value, ChannelPermission.Connect, true); | |||||
TestHelper(value, ChannelPermission.Speak, true); | |||||
TestHelper(value, ChannelPermission.MuteMembers, true); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, true); | |||||
TestHelper(value, ChannelPermission.MoveMembers, true); | |||||
TestHelper(value, ChannelPermission.UseVAD, true); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Tests for the <see cref="Discord.Permissions"/> class. | |||||
/// | |||||
/// Test that that the Has method of <see cref="Discord.GuildPermissions"/> | |||||
/// returns the correct value when no permissions are set. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestPermissionsHasGuildPermissionNone() | |||||
{ | |||||
var value = GuildPermissions.None; | |||||
TestHelper(value, GuildPermission.CreateInstantInvite, false); | |||||
TestHelper(value, GuildPermission.KickMembers, false); | |||||
TestHelper(value, GuildPermission.BanMembers, false); | |||||
TestHelper(value, GuildPermission.Administrator, false); | |||||
TestHelper(value, GuildPermission.ManageChannels, false); | |||||
TestHelper(value, GuildPermission.ManageGuild, false); | |||||
TestHelper(value, GuildPermission.AddReactions, false); | |||||
TestHelper(value, GuildPermission.ViewAuditLog, false); | |||||
TestHelper(value, GuildPermission.ViewChannel, false); | |||||
TestHelper(value, GuildPermission.SendMessages, false); | |||||
TestHelper(value, GuildPermission.SendTTSMessages, false); | |||||
TestHelper(value, GuildPermission.ManageMessages, false); | |||||
TestHelper(value, GuildPermission.EmbedLinks, false); | |||||
TestHelper(value, GuildPermission.AttachFiles, false); | |||||
TestHelper(value, GuildPermission.ReadMessageHistory, false); | |||||
TestHelper(value, GuildPermission.MentionEveryone, false); | |||||
TestHelper(value, GuildPermission.UseExternalEmojis, false); | |||||
TestHelper(value, GuildPermission.Connect, false); | |||||
TestHelper(value, GuildPermission.Speak, false); | |||||
TestHelper(value, GuildPermission.MuteMembers, false); | |||||
TestHelper(value, GuildPermission.MoveMembers, false); | |||||
TestHelper(value, GuildPermission.UseVAD, false); | |||||
TestHelper(value, GuildPermission.ChangeNickname, false); | |||||
TestHelper(value, GuildPermission.ManageNicknames, false); | |||||
TestHelper(value, GuildPermission.ManageRoles, false); | |||||
TestHelper(value, GuildPermission.ManageWebhooks, false); | |||||
TestHelper(value, GuildPermission.ManageEmojis, false); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Tests for the <see cref="Discord.Permissions"/> class. | |||||
/// | |||||
/// Test that that the Has method of <see cref="Discord.GuildPermissions"/> | |||||
/// returns the correct value when all permissions are set. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestPermissionsHasGuildPermissionAll() | |||||
{ | |||||
var value = GuildPermissions.All; | |||||
TestHelper(value, GuildPermission.CreateInstantInvite, true); | |||||
TestHelper(value, GuildPermission.KickMembers, true); | |||||
TestHelper(value, GuildPermission.BanMembers, true); | |||||
TestHelper(value, GuildPermission.Administrator, true); | |||||
TestHelper(value, GuildPermission.ManageChannels, true); | |||||
TestHelper(value, GuildPermission.ManageGuild, true); | |||||
TestHelper(value, GuildPermission.AddReactions, true); | |||||
TestHelper(value, GuildPermission.ViewAuditLog, true); | |||||
TestHelper(value, GuildPermission.ViewChannel, true); | |||||
TestHelper(value, GuildPermission.SendMessages, true); | |||||
TestHelper(value, GuildPermission.SendTTSMessages, true); | |||||
TestHelper(value, GuildPermission.ManageMessages, true); | |||||
TestHelper(value, GuildPermission.EmbedLinks, true); | |||||
TestHelper(value, GuildPermission.AttachFiles, true); | |||||
TestHelper(value, GuildPermission.ReadMessageHistory, true); | |||||
TestHelper(value, GuildPermission.MentionEveryone, true); | |||||
TestHelper(value, GuildPermission.UseExternalEmojis, true); | |||||
TestHelper(value, GuildPermission.Connect, true); | |||||
TestHelper(value, GuildPermission.Speak, true); | |||||
TestHelper(value, GuildPermission.MuteMembers, true); | |||||
TestHelper(value, GuildPermission.MoveMembers, true); | |||||
TestHelper(value, GuildPermission.UseVAD, true); | |||||
TestHelper(value, GuildPermission.ChangeNickname, true); | |||||
TestHelper(value, GuildPermission.ManageNicknames, true); | |||||
TestHelper(value, GuildPermission.ManageRoles, true); | |||||
TestHelper(value, GuildPermission.ManageWebhooks, true); | |||||
TestHelper(value, GuildPermission.ManageEmojis, true); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Tests for the <see cref="Discord.Permissions"/> class. | |||||
/// | |||||
/// Test that that the Has method of <see cref="Discord.GuildPermissions"/> | |||||
/// returns the correct value when webhook permissions are set. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestPermissionsHasGuildPermissionWebhook() | |||||
{ | |||||
var value = GuildPermissions.Webhook; | |||||
TestHelper(value, GuildPermission.CreateInstantInvite, false); | |||||
TestHelper(value, GuildPermission.KickMembers, false); | |||||
TestHelper(value, GuildPermission.BanMembers, false); | |||||
TestHelper(value, GuildPermission.Administrator, false); | |||||
TestHelper(value, GuildPermission.ManageChannels, false); | |||||
TestHelper(value, GuildPermission.ManageGuild, false); | |||||
TestHelper(value, GuildPermission.AddReactions, false); | |||||
TestHelper(value, GuildPermission.ViewAuditLog, false); | |||||
TestHelper(value, GuildPermission.ViewChannel, false); | |||||
TestHelper(value, GuildPermission.SendMessages, true); | |||||
TestHelper(value, GuildPermission.SendTTSMessages, true); | |||||
TestHelper(value, GuildPermission.ManageMessages, false); | |||||
TestHelper(value, GuildPermission.EmbedLinks, true); | |||||
TestHelper(value, GuildPermission.AttachFiles, true); | |||||
TestHelper(value, GuildPermission.ReadMessageHistory, false); | |||||
TestHelper(value, GuildPermission.MentionEveryone, false); | |||||
TestHelper(value, GuildPermission.UseExternalEmojis, false); | |||||
TestHelper(value, GuildPermission.Connect, false); | |||||
TestHelper(value, GuildPermission.Speak, false); | |||||
TestHelper(value, GuildPermission.MuteMembers, false); | |||||
TestHelper(value, GuildPermission.MoveMembers, false); | |||||
TestHelper(value, GuildPermission.UseVAD, false); | |||||
TestHelper(value, GuildPermission.ChangeNickname, false); | |||||
TestHelper(value, GuildPermission.ManageNicknames, false); | |||||
TestHelper(value, GuildPermission.ManageRoles, false); | |||||
TestHelper(value, GuildPermission.ManageWebhooks, false); | |||||
TestHelper(value, GuildPermission.ManageEmojis, false); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Test <see cref="Discord.OverwritePermissions"/> | |||||
/// for when all text permissions are allowed and denied | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestOverwritePermissionsText() | |||||
{ | |||||
// allow all for text channel | |||||
var value = new OverwritePermissions(ChannelPermissions.Text.RawValue, ChannelPermissions.None.RawValue); | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Inherit); | |||||
value = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.Text.RawValue); | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Inherit); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Test <see cref="Discord.OverwritePermissions"/> | |||||
/// for when none of the permissions are set. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestOverwritePermissionsNone() | |||||
{ | |||||
// allow all for text channel | |||||
var value = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.None.RawValue); | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Inherit); | |||||
value = new OverwritePermissions(); | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Inherit); | |||||
value = OverwritePermissions.InheritAll; | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Inherit); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Test <see cref="Discord.OverwritePermissions"/> | |||||
/// for when all dm permissions are allowed and denied | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestOverwritePermissionsDM() | |||||
{ | |||||
// allow all for text channel | |||||
var value = new OverwritePermissions(ChannelPermissions.DM.RawValue, ChannelPermissions.None.RawValue); | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Allow); | |||||
value = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.DM.RawValue); | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Deny); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Test <see cref="Discord.OverwritePermissions"/> | |||||
/// for when all group permissions are allowed and denied | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestOverwritePermissionsGroup() | |||||
{ | |||||
// allow all for group channels | |||||
var value = new OverwritePermissions(ChannelPermissions.Group.RawValue, ChannelPermissions.None.RawValue); | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Allow); | |||||
value = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.Group.RawValue); | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Deny); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Test <see cref="Discord.OverwritePermissions"/> | |||||
/// for when all group permissions are allowed and denied | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestOverwritePermissionsVoice() | |||||
{ | |||||
// allow all for group channels | |||||
var value = new OverwritePermissions(ChannelPermissions.Voice.RawValue, ChannelPermissions.None.RawValue); | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Allow); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Allow); | |||||
value = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.Voice.RawValue); | |||||
TestHelper(value, ChannelPermission.CreateInstantInvite, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ManageChannels, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.AddReactions, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ViewChannel, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.SendMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.SendTTSMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageMessages, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.EmbedLinks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.AttachFiles, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ReadMessageHistory, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.MentionEveryone, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.UseExternalEmojis, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.ManageRoles, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.ManageWebhooks, PermValue.Inherit); | |||||
TestHelper(value, ChannelPermission.Connect, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.Speak, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.MuteMembers, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.DeafenMembers, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.MoveMembers, PermValue.Deny); | |||||
TestHelper(value, ChannelPermission.UseVAD, PermValue.Deny); | |||||
return Task.CompletedTask; | |||||
} | |||||
/// <summary> | |||||
/// Tests for the <see cref="OverwritePermissions.Modify(PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?, PermValue?)"/> | |||||
/// method to ensure that the default no-param call does not modify the resulting value | |||||
/// of the OverwritePermissions. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
[Fact] | |||||
public Task TestOverwritePermissionModifyNoParam() | |||||
{ | |||||
// test for all Text allowed, none denied | |||||
var original = new OverwritePermissions(ChannelPermissions.Text.RawValue, ChannelPermissions.None.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
// none allowed, text denied | |||||
original = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.Text.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
// category allowed, none denied | |||||
original = new OverwritePermissions(ChannelPermissions.Category.RawValue, ChannelPermissions.None.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
// none allowed, category denied | |||||
original = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.Category.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
// DM allowed, none denied | |||||
original = new OverwritePermissions(ChannelPermissions.DM.RawValue, ChannelPermissions.None.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
// none allowed, DM denied | |||||
original = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.DM.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
// voice allowed, none denied | |||||
original = new OverwritePermissions(ChannelPermissions.Voice.RawValue, ChannelPermissions.None.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
// none allowed, voice denied | |||||
original = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.Voice.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
// group allowed, none denied | |||||
original = new OverwritePermissions(ChannelPermissions.Group.RawValue, ChannelPermissions.None.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
// none allowed, group denied | |||||
original = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.Group.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
// none allowed, none denied | |||||
original = new OverwritePermissions(ChannelPermissions.None.RawValue, ChannelPermissions.None.RawValue); | |||||
Assert.Equal(original.AllowValue, original.Modify().AllowValue); | |||||
Assert.Equal(original.DenyValue, original.Modify().DenyValue); | |||||
return Task.CompletedTask; | |||||
} | |||||
} | |||||
} |
@@ -1,133 +0,0 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Threading.Tasks; | |||||
using Discord.Commands; | |||||
using Xunit; | |||||
namespace Discord | |||||
{ | |||||
public sealed class TypeReaderTests | |||||
{ | |||||
[Fact] | |||||
public async Task TestNamedArgumentReader() | |||||
{ | |||||
var commands = new CommandService(); | |||||
var module = await commands.AddModuleAsync<TestModule>(null); | |||||
Assert.NotNull(module); | |||||
Assert.NotEmpty(module.Commands); | |||||
var cmd = module.Commands[0]; | |||||
Assert.NotNull(cmd); | |||||
Assert.NotEmpty(cmd.Parameters); | |||||
var param = cmd.Parameters[0]; | |||||
Assert.NotNull(param); | |||||
Assert.True(param.IsRemainder); | |||||
var result = await param.ParseAsync(null, "bar: hello foo: 42"); | |||||
Assert.True(result.IsSuccess); | |||||
var m = result.BestMatch as ArgumentType; | |||||
Assert.NotNull(m); | |||||
Assert.Equal(expected: 42, actual: m.Foo); | |||||
Assert.Equal(expected: "hello", actual: m.Bar); | |||||
} | |||||
[Fact] | |||||
public async Task TestQuotedArgumentValue() | |||||
{ | |||||
var commands = new CommandService(); | |||||
var module = await commands.AddModuleAsync<TestModule>(null); | |||||
Assert.NotNull(module); | |||||
Assert.NotEmpty(module.Commands); | |||||
var cmd = module.Commands[0]; | |||||
Assert.NotNull(cmd); | |||||
Assert.NotEmpty(cmd.Parameters); | |||||
var param = cmd.Parameters[0]; | |||||
Assert.NotNull(param); | |||||
Assert.True(param.IsRemainder); | |||||
var result = await param.ParseAsync(null, "foo: 42 bar: 《hello》"); | |||||
Assert.True(result.IsSuccess); | |||||
var m = result.BestMatch as ArgumentType; | |||||
Assert.NotNull(m); | |||||
Assert.Equal(expected: 42, actual: m.Foo); | |||||
Assert.Equal(expected: "hello", actual: m.Bar); | |||||
} | |||||
[Fact] | |||||
public async Task TestNonPatternInput() | |||||
{ | |||||
var commands = new CommandService(); | |||||
var module = await commands.AddModuleAsync<TestModule>(null); | |||||
Assert.NotNull(module); | |||||
Assert.NotEmpty(module.Commands); | |||||
var cmd = module.Commands[0]; | |||||
Assert.NotNull(cmd); | |||||
Assert.NotEmpty(cmd.Parameters); | |||||
var param = cmd.Parameters[0]; | |||||
Assert.NotNull(param); | |||||
Assert.True(param.IsRemainder); | |||||
var result = await param.ParseAsync(null, "foobar"); | |||||
Assert.False(result.IsSuccess); | |||||
Assert.Equal(expected: CommandError.Exception, actual: result.Error); | |||||
} | |||||
[Fact] | |||||
public async Task TestMultiple() | |||||
{ | |||||
var commands = new CommandService(); | |||||
var module = await commands.AddModuleAsync<TestModule>(null); | |||||
Assert.NotNull(module); | |||||
Assert.NotEmpty(module.Commands); | |||||
var cmd = module.Commands[0]; | |||||
Assert.NotNull(cmd); | |||||
Assert.NotEmpty(cmd.Parameters); | |||||
var param = cmd.Parameters[0]; | |||||
Assert.NotNull(param); | |||||
Assert.True(param.IsRemainder); | |||||
var result = await param.ParseAsync(null, "manyints: \"1, 2, 3, 4, 5, 6, 7\""); | |||||
Assert.True(result.IsSuccess); | |||||
var m = result.BestMatch as ArgumentType; | |||||
Assert.NotNull(m); | |||||
Assert.Equal(expected: new int[] { 1, 2, 3, 4, 5, 6, 7 }, actual: m.ManyInts); | |||||
} | |||||
} | |||||
[NamedArgumentType] | |||||
public sealed class ArgumentType | |||||
{ | |||||
public int Foo { get; set; } | |||||
[OverrideTypeReader(typeof(CustomTypeReader))] | |||||
public string Bar { get; set; } | |||||
public IEnumerable<int> ManyInts { get; set; } | |||||
} | |||||
public sealed class CustomTypeReader : TypeReader | |||||
{ | |||||
public override Task<TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) | |||||
=> Task.FromResult(TypeReaderResult.FromSuccess(input)); | |||||
} | |||||
public sealed class TestModule : ModuleBase | |||||
{ | |||||
[Command("test")] | |||||
public Task TestCommand(ArgumentType arg) => Task.Delay(0); | |||||
} | |||||
} |
@@ -1,55 +0,0 @@ | |||||
using System; | |||||
using Discord.Net; | |||||
using Discord.Rest; | |||||
using Xunit; | |||||
// TODO: re-enable ix testing at a later date | |||||
#if IXTEST | |||||
namespace Discord | |||||
{ | |||||
public partial class TestsFixture : IDisposable | |||||
{ | |||||
private readonly TestConfig _config; | |||||
private readonly CachedRestClient _cache; | |||||
internal readonly DiscordRestClient _client; | |||||
internal readonly RestGuild _guild; | |||||
public TestsFixture() | |||||
{ | |||||
_cache = new CachedRestClient(); | |||||
_config = TestConfig.LoadFile("./config.json"); | |||||
var config = new DiscordRestConfig | |||||
{ | |||||
RestClientProvider = url => | |||||
{ | |||||
_cache.SetUrl(url); | |||||
return _cache; | |||||
} | |||||
}; | |||||
_client = new DiscordRestClient(config); | |||||
_client.LoginAsync(TokenType.Bot, _config.Token).Wait(); | |||||
MigrateAsync().Wait(); | |||||
_guild = _client.GetGuildAsync(_config.GuildId).Result; | |||||
} | |||||
public void Dispose() | |||||
{ | |||||
_client.Dispose(); | |||||
_cache.Dispose(); | |||||
} | |||||
} | |||||
public partial class Tests : IClassFixture<TestsFixture> | |||||
{ | |||||
private DiscordRestClient _client; | |||||
private RestGuild _guild; | |||||
public Tests(TestsFixture fixture) | |||||
{ | |||||
_client = fixture._client; | |||||
_guild = fixture._guild; | |||||
} | |||||
} | |||||
} | |||||
#endif |
@@ -1,4 +0,0 @@ | |||||
{ | |||||
"token": "AAA.BBB.CCC", | |||||
"guild_id": 1234567890 | |||||
} |
@@ -1,4 +0,0 @@ | |||||
{ | |||||
"diagnosticMessages": true, | |||||
"methodDisplay": "classAndMethod" | |||||
} |