using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
namespace Discord
{
///
/// Tests for the methods.
///
public class TokenUtilsTests
{
///
/// Tests the usage of
/// to see that when a null, empty or whitespace-only string is passed as the token,
/// it will throw an ArgumentNullException.
///
[Theory]
[InlineData(null)]
[InlineData("")] // string.Empty isn't a constant type
[InlineData(" ")]
[InlineData(" ")]
[InlineData("\t")]
public void NullOrWhitespaceToken(string token)
{
// an ArgumentNullException should be thrown, regardless of the TokenType
Assert.Throws(() => TokenUtils.ValidateToken(TokenType.Bearer, token));
Assert.Throws(() => TokenUtils.ValidateToken(TokenType.Bot, token));
Assert.Throws(() => TokenUtils.ValidateToken(TokenType.Webhook, token));
}
///
/// Tests the behavior of
/// to see that valid Webhook tokens do not throw Exceptions.
///
///
[Theory]
[InlineData("123123123")]
// bot token
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")]
// bearer token taken from discord docs
[InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")]
// client secret
[InlineData("937it3ow87i4ery69876wqire")]
public void WebhookTokenDoesNotThrowExceptions(string token)
{
TokenUtils.ValidateToken(TokenType.Webhook, token);
}
// No tests for invalid webhook token behavior, because there is nothing there yet.
///
/// Tests the behavior of
/// to see that valid Webhook tokens do not throw Exceptions.
///
///
[Theory]
[InlineData("123123123")]
// bot token
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")]
// bearer token taken from discord docs
[InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")]
// client secret
[InlineData("937it3ow87i4ery69876wqire")]
public void BearerTokenDoesNotThrowExceptions(string token)
{
TokenUtils.ValidateToken(TokenType.Bearer, token);
}
// No tests for invalid bearer token behavior, because there is nothing there yet.
///
/// Tests the behavior of
/// to see that valid Bot tokens do not throw Exceptions.
/// Valid Bot tokens can be strings of length 58 or above.
///
[Theory]
// missing a single character from the end, 58 char. still should be valid
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKW")]
// 59 char token
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWss")]
public void BotTokenDoesNotThrowExceptions(string token)
{
// This example token is pulled from the Discord Docs
// https://discord.com/developers/docs/reference#authentication-example-bot-token-authorization-header
// should not throw any exception
TokenUtils.ValidateToken(TokenType.Bot, token);
}
///
/// Tests the usage of with
/// a Bot token that is invalid.
///
[Theory]
[InlineData("This is invalid")]
// bearer token
[InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")]
// client secret
[InlineData("937it3ow87i4ery69876wqire")]
// 57 char bot token
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kK")]
// ends with invalid characters
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k ")]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k\n")]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k\t")]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k\r\n")]
// starts with invalid characters
[InlineData(" MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k")]
[InlineData("\nMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k")]
[InlineData("\tMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k")]
[InlineData("\r\nMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7k")]
[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 BotTokenInvalidThrowsArgumentException(string token)
{
Assert.Throws(() => TokenUtils.ValidateToken(TokenType.Bot, token));
}
///
/// Tests the behavior of
/// to see that an is thrown when an invalid
/// is supplied as a parameter.
///
///
/// The type is treated as an invalid .
///
[Theory]
// out of range TokenType
[InlineData(-1)]
[InlineData(4)]
[InlineData(7)]
public void UnrecognizedTokenType(int type)
{
Assert.Throws(() =>
TokenUtils.ValidateToken((TokenType)type, "MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs"));
}
///
/// Checks the method for expected output.
///
/// The Bot Token to test.
/// The expected result.
[Theory]
// this method only checks the first part of the JWT
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4..", true)]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kK", true)]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4. this part is invalid. this part is also invalid", true)]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.", false)]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4", false)]
[InlineData("NDI4NDc3OTQ0MDA5MTk1NTIw.xxxx.xxxxx", true)]
// should not throw an unexpected exception
[InlineData("", false)]
[InlineData(null, false)]
public void CheckBotTokenValidity(string token, bool expected)
{
Assert.Equal(expected, TokenUtils.CheckBotTokenValidity(token));
}
[Theory]
// 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)]
// 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 DecodeBase64UserId(string encodedUserId, bool isNull, ulong expectedUserId)
{
var result = TokenUtils.DecodeBase64UserId(encodedUserId);
if (isNull)
Assert.Null(result);
else
Assert.Equal(expectedUserId, result);
}
}
}