@@ -1,5 +1,23 @@ | |||
# 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 | |||
### Added | |||
- #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 | |||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}" | |||
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}" | |||
EndProject | |||
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 | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03_sharded_client", "samples\03_sharded_client\03_sharded_client.csproj", "{9B4C4AFB-3D15-44C6-9E36-12ED625AAA26}" | |||
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 | |||
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 | |||
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 | |||
Global | |||
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|x86.ActiveCfg = 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.Build.0 = 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|x86.ActiveCfg = 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 | |||
GlobalSection(SolutionProperties) = preSolution | |||
HideSolutionNode = FALSE | |||
@@ -218,8 +218,9 @@ Global | |||
{F2FF84FB-F6AD-47E5-9EE5-18206CAE136E} = {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} | |||
{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 | |||
GlobalSection(ExtensibilityGlobals) = postSolution | |||
SolutionGuid = {D2404771-EEC8-45F2-9D71-F3373F6C1495} | |||
@@ -1,6 +1,6 @@ | |||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<PropertyGroup> | |||
<VersionPrefix>2.1.1</VersionPrefix> | |||
<VersionPrefix>2.2.0</VersionPrefix> | |||
<VersionSuffix>dev</VersionSuffix> | |||
<Authors>RogueException</Authors> | |||
<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) | |||
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 | |||
displayName: Publish test results | |||
@@ -53,6 +53,13 @@ namespace Discord.Commands | |||
else | |||
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 (isEscaping) | |||
{ | |||
@@ -79,13 +86,6 @@ namespace Discord.Commands | |||
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 (curPart == ParserPart.None) | |||
{ | |||
@@ -10,7 +10,7 @@ | |||
<ItemGroup> | |||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> | |||
<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"> | |||
<PrivateAssets>all</PrivateAssets> | |||
</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; } | |||
/// <inheritdoc/> | |||
public ActivityType Type { get; internal set; } | |||
/// <inheritdoc/> | |||
public ActivityProperties Flags { get; internal set; } | |||
/// <inheritdoc/> | |||
public string Details { get; internal set; } | |||
internal Game() { } | |||
/// <summary> | |||
@@ -19,10 +23,12 @@ namespace Discord | |||
/// </summary> | |||
/// <param name="name">The name of the game.</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; | |||
Type = type; | |||
Flags = flags; | |||
Details = details; | |||
} | |||
/// <summary> Returns the name of the <see cref="Game"/>. </summary> | |||
@@ -19,5 +19,22 @@ namespace Discord | |||
/// The type of activity. | |||
/// </returns> | |||
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() { } | |||
/// <summary> | |||
/// Gets what the player is currently doing. | |||
/// </summary> | |||
public string Details { get; internal set; } | |||
/// <summary> | |||
/// Gets the user's current party status. | |||
/// </summary> | |||
@@ -36,7 +36,7 @@ namespace Discord | |||
/// <see cref="ChannelPermission.ManageChannels"/> will be exempt from slow-mode. | |||
/// </note> | |||
/// </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; } | |||
} | |||
} |
@@ -55,12 +55,7 @@ namespace Discord | |||
/// <inheritdoc /> | |||
public override int GetHashCode() | |||
{ | |||
unchecked | |||
{ | |||
return (Name.GetHashCode() * 397) ^ Id.GetHashCode(); | |||
} | |||
} | |||
=> Id.GetHashCode(); | |||
/// <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> | |||
@@ -486,7 +486,7 @@ namespace Discord | |||
set | |||
{ | |||
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)); | |||
_value = stringValue; | |||
} | |||
@@ -59,18 +59,19 @@ namespace Discord | |||
/// </remarks> | |||
public Optional<IEnumerable<ulong>> RoleIds { get; set; } | |||
/// <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> | |||
/// <remarks> | |||
/// 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> | |||
public Optional<IVoiceChannel> Channel { get; set; } | |||
/// <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> | |||
/// <remarks> | |||
/// This user MUST already be in a <see cref="IVoiceChannel"/> for this to work. | |||
/// </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. | |||
/// </returns> | |||
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> | |||
/// 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 Newtonsoft.Json; | |||
using Newtonsoft.Json.Converters; | |||
using Discord.Net.Converters; | |||
namespace Discord.API | |||
{ | |||
@@ -15,7 +15,7 @@ namespace Discord.API | |||
public string Url { get; set; } | |||
[JsonProperty("color")] | |||
public uint? Color { get; set; } | |||
[JsonProperty("type"), JsonConverter(typeof(StringEnumConverter))] | |||
[JsonProperty("type"), JsonConverter(typeof(EmbedTypeConverter))] | |||
public EmbedType Type { get; set; } | |||
[JsonProperty("timestamp")] | |||
public DateTimeOffset? Timestamp { get; set; } | |||
@@ -33,6 +33,8 @@ namespace Discord.API | |||
public Optional<string> SyncId { get; set; } | |||
[JsonProperty("session_id")] | |||
public Optional<string> SessionId { get; set; } | |||
[JsonProperty("Flags")] | |||
public Optional<ActivityProperties> Flags { get; set; } | |||
[OnError] | |||
internal void OnError(StreamingContext context, ErrorContext errorContext) | |||
@@ -1,4 +1,4 @@ | |||
#pragma warning disable CS1591 | |||
#pragma warning disable CS1591 | |||
using Newtonsoft.Json; | |||
namespace Discord.API | |||
@@ -23,5 +23,11 @@ namespace Discord.API | |||
public Optional<string> Email { get; set; } | |||
[JsonProperty("mfa_enabled")] | |||
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; | |||
namespace Discord.API.Rest | |||
@@ -15,6 +15,6 @@ namespace Discord.API.Rest | |||
[JsonProperty("roles")] | |||
public Optional<ulong[]> RoleIds { get; set; } | |||
[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.NotNullOrEmpty(args.Name, nameof(args.Name)); | |||
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); | |||
var ids = new BucketIds(channelId: channelId); | |||
@@ -17,6 +17,12 @@ namespace Discord.Rest | |||
public bool IsVerified { get; private set; } | |||
/// <inheritdoc /> | |||
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) | |||
: base(discord, id) | |||
@@ -39,6 +45,12 @@ namespace Discord.Rest | |||
IsVerified = model.Verified.Value; | |||
if (model.MfaEnabled.IsSpecified) | |||
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 /> | |||
@@ -1,4 +1,4 @@ | |||
using Discord.API.Rest; | |||
using Discord.API.Rest; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Threading.Tasks; | |||
@@ -39,7 +39,7 @@ namespace Discord.Rest | |||
}; | |||
if (args.Channel.IsSpecified) | |||
apiArgs.ChannelId = args.Channel.Value.Id; | |||
apiArgs.ChannelId = args.Channel.Value?.Id; | |||
else if (args.ChannelId.IsSpecified) | |||
apiArgs.ChannelId = args.ChannelId.Value; | |||
@@ -77,6 +77,8 @@ namespace Discord.Net.Converters | |||
return PermissionTargetConverter.Instance; | |||
if (type == typeof(UserStatus)) | |||
return UserStatusConverter.Instance; | |||
if (type == typeof(EmbedType)) | |||
return EmbedTypeConverter.Instance; | |||
//Special | |||
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; | |||
bool isCached = cachedMsg != null; | |||
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); | |||
cachedMsg?.AddReaction(reaction); | |||
@@ -1319,7 +1328,16 @@ namespace Discord.WebSocket | |||
var cachedMsg = channel.GetCachedMessage(data.MessageId) as SocketUserMessage; | |||
bool isCached = cachedMsg != null; | |||
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); | |||
cachedMsg?.RemoveReaction(reaction); | |||
@@ -30,6 +30,12 @@ namespace Discord.WebSocket | |||
public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } | |||
/// <inheritdoc /> | |||
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 /> | |||
public override bool IsWebhook => false; | |||
@@ -63,6 +69,21 @@ namespace Discord.WebSocket | |||
IsMfaEnabled = model.MfaEnabled.Value; | |||
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; | |||
} | |||
@@ -25,7 +25,8 @@ namespace Discord.WebSocket | |||
Artists = model.State.GetValueOrDefault()?.Split(';').Select(x=>x?.Trim()).ToImmutableArray(), | |||
Duration = timestamps?.End - timestamps?.Start, | |||
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], | |||
Party = model.Party.IsSpecified ? model.Party.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 | |||
if (model.StreamUrl.IsSpecified) | |||
{ | |||
return new StreamingGame( | |||
model.Name, | |||
model.StreamUrl.Value); | |||
model.Name, | |||
model.StreamUrl.Value) | |||
{ | |||
Flags = model.Flags.GetValueOrDefault(), | |||
Details = model.Details.GetValueOrDefault() | |||
}; | |||
} | |||
// 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) | |||
@@ -2,7 +2,7 @@ | |||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> | |||
<metadata> | |||
<id>Discord.Net</id> | |||
<version>2.1.1-dev$suffix$</version> | |||
<version>2.2.0-dev$suffix$</version> | |||
<title>Discord.Net</title> | |||
<authors>Discord.Net Contributors</authors> | |||
<owners>RogueException</owners> | |||
@@ -14,25 +14,25 @@ | |||
<iconUrl>https://github.com/RogueException/Discord.Net/raw/dev/docs/marketing/logo/PackageLogo.png</iconUrl> | |||
<dependencies> | |||
<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 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 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> | |||
</dependencies> | |||
</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.Collections.Generic; | |||
using System.Text; | |||
using Xunit; | |||
namespace Discord | |||
{ | |||
/// <summary> | |||
/// Tests for the <see cref="Discord.Color"/> type. | |||
/// </summary> | |||
public class ColorTests | |||
{ | |||
[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.Collections.Generic; | |||
using System.Text; | |||
using Xunit; | |||
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 | |||
{ | |||
/// <summary> | |||
/// Tests for the <see cref="Discord.TokenUtils"/> methods. | |||
/// </summary> | |||
public class TokenUtilsTests | |||
{ | |||
/// <summary> | |||
@@ -18,14 +21,14 @@ namespace Discord | |||
[InlineData(" ")] | |||
[InlineData(" ")] | |||
[InlineData("\t")] | |||
public void TestNullOrWhitespaceToken(string token) | |||
public void NullOrWhitespaceToken(string token) | |||
{ | |||
// an ArgumentNullException should be thrown, regardless of the TokenType | |||
Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Bearer, token)); | |||
Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Bot, token)); | |||
Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Webhook, token)); | |||
} | |||
/// <summary> | |||
/// Tests the behavior of <see cref="TokenUtils.ValidateToken(TokenType, string)"/> | |||
/// to see that valid Webhook tokens do not throw Exceptions. | |||
@@ -39,7 +42,7 @@ namespace Discord | |||
[InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")] | |||
// client secret | |||
[InlineData("937it3ow87i4ery69876wqire")] | |||
public void TestWebhookTokenDoesNotThrowExceptions(string token) | |||
public void WebhookTokenDoesNotThrowExceptions(string token) | |||
{ | |||
TokenUtils.ValidateToken(TokenType.Webhook, token); | |||
} | |||
@@ -59,7 +62,7 @@ namespace Discord | |||
[InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")] | |||
// client secret | |||
[InlineData("937it3ow87i4ery69876wqire")] | |||
public void TestBearerTokenDoesNotThrowExceptions(string token) | |||
public void BearerTokenDoesNotThrowExceptions(string token) | |||
{ | |||
TokenUtils.ValidateToken(TokenType.Bearer, token); | |||
} | |||
@@ -77,9 +80,7 @@ namespace Discord | |||
// 59 char token | |||
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] | |||
[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 | |||
// 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.")] | |||
// valid token, but passed in twice | |||
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWsMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")] | |||
public void TestBotTokenInvalidThrowsArgumentException(string token) | |||
public void BotTokenInvalidThrowsArgumentException(string token) | |||
{ | |||
Assert.Throws<ArgumentException>(() => TokenUtils.ValidateToken(TokenType.Bot, token)); | |||
} | |||
@@ -132,7 +133,7 @@ namespace Discord | |||
[InlineData(-1)] | |||
[InlineData(4)] | |||
[InlineData(7)] | |||
public void TestUnrecognizedTokenType(int type) | |||
public void UnrecognizedTokenType(int type) | |||
{ | |||
Assert.Throws<ArgumentException>(() => | |||
TokenUtils.ValidateToken((TokenType)type, "MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")); | |||
@@ -154,7 +155,7 @@ namespace Discord | |||
// should not throw an unexpected exception | |||
[InlineData("", false)] | |||
[InlineData(null, false)] | |||
public void TestCheckBotTokenValidity(string token, bool expected) | |||
public void CheckBotTokenValidity(string token, bool expected) | |||
{ | |||
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 | |||
// indicating if a value is null | |||
[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 | |||
[InlineData("", true, 0)] | |||
[InlineData(" ", true, 0)] | |||
[InlineData(null, 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); | |||
if (isNull) | |||
@@ -180,37 +177,5 @@ namespace Discord | |||
else | |||
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" | |||
} |