diff --git a/Source/Lib/TraktApiSharp/Objects/Authentication/Implementations/TraktAuthorization.cs b/Source/Lib/TraktApiSharp/Objects/Authentication/Implementations/TraktAuthorization.cs index f634a5a62..194d3792b 100644 --- a/Source/Lib/TraktApiSharp/Objects/Authentication/Implementations/TraktAuthorization.cs +++ b/Source/Lib/TraktApiSharp/Objects/Authentication/Implementations/TraktAuthorization.cs @@ -26,6 +26,8 @@ /// public class TraktAuthorization : ITraktAuthorization { + private const uint DEFAULT_EXPIRES_IN_SECONDS = 7776000; + /// Gets or sets the access token. [JsonProperty(PropertyName = "access_token")] public string AccessToken { get; set; } @@ -57,7 +59,7 @@ public class TraktAuthorization : ITraktAuthorization /// /// [JsonIgnore] - public bool IsExpired => !IsValid || (IgnoreExpiration ? false : CreatedAt.AddSeconds(ExpiresInSeconds) <= DateTime.UtcNow); + public bool IsExpired => !IsValid || (!IgnoreExpiration && CreatedAt.AddSeconds(ExpiresInSeconds) <= DateTime.UtcNow); /// /// Returns, whether this authorization information is valid. @@ -79,25 +81,41 @@ public class TraktAuthorization : ITraktAuthorization /// Returns the UTC DateTime, when this authorization information was created. [JsonIgnore] - public DateTime CreatedAt - => CreatedAtTimestamp > 0 ? new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(CreatedAtTimestamp) : default(DateTime); + public DateTime CreatedAt => CreatedAtTimestamp > 0 ? new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(CreatedAtTimestamp) : default(DateTime); [JsonIgnore] internal bool IgnoreExpiration { get; set; } + public override string ToString() + { + string value = IsValid ? $"{AccessToken}" : "no valid access token"; + value += IsExpired ? " (expired)" : $" (valid until {CreatedAt.AddSeconds(ExpiresInSeconds)})"; + return value; + } + + public bool Equals(ITraktAuthorization other) + => other != null + && other.IsValid == IsValid + && other.IsExpired == IsExpired + && other.IsRefreshPossible == IsRefreshPossible + && other.ExpiresInSeconds == ExpiresInSeconds + && other.CreatedAtTimestamp == CreatedAtTimestamp + && other.CreatedAt == CreatedAt + && other.AccessToken == AccessToken + && other.RefreshToken == RefreshToken + && other.Scope == Scope + && other.TokenType == TokenType; + /// Creates a new instance with the given values. /// The access token for the new instance. /// The optional refresh token for the new instance. /// A new instance with the given values. public static TraktAuthorization CreateWith(string accessToken, string refreshToken = null) - => new TraktAuthorization - { - Scope = TraktAccessScope.Public, - TokenType = TraktAccessTokenType.Bearer, - AccessToken = accessToken ?? string.Empty, - RefreshToken = refreshToken ?? string.Empty, - IgnoreExpiration = true - }; + { + TraktAuthorization traktAuthorization = CreateWith(DateTime.UtcNow, accessToken, refreshToken); + traktAuthorization.IgnoreExpiration = true; + return traktAuthorization; + } /// Creates a new instance with the given values. /// The seconds, after which the given access token will expire. @@ -105,14 +123,7 @@ public static TraktAuthorization CreateWith(string accessToken, string refreshTo /// The optional refresh token for the new instance. /// A new instance with the given values. public static TraktAuthorization CreateWith(uint expiresInSeconds, string accessToken, string refreshToken = null) - => new TraktAuthorization - { - ExpiresInSeconds = expiresInSeconds, - Scope = TraktAccessScope.Public, - TokenType = TraktAccessTokenType.Bearer, - AccessToken = accessToken ?? string.Empty, - RefreshToken = refreshToken ?? string.Empty - }; + => CreateWith(DateTime.UtcNow, expiresInSeconds, accessToken, refreshToken); /// /// Creates a new instance with the given values. @@ -124,7 +135,11 @@ public static TraktAuthorization CreateWith(uint expiresInSeconds, string access /// The optional refresh token for the new instance. /// A new instance with the given values. public static TraktAuthorization CreateWith(DateTime createdAt, string accessToken, string refreshToken = null) - => CreateWith(createdAt, 7776000, accessToken, refreshToken); + { + TraktAuthorization traktAuthorization = CreateWith(createdAt, DEFAULT_EXPIRES_IN_SECONDS, accessToken, refreshToken); + traktAuthorization.IgnoreExpiration = true; + return traktAuthorization; + } /// Creates a new instance with the given values. /// The datetime, when the given access token was created. Will be converted to UTC datetime. @@ -136,39 +151,23 @@ public static TraktAuthorization CreateWith(DateTime createdAt, uint expiresInSe string accessToken, string refreshToken = null) => new TraktAuthorization { - CreatedAtTimestamp = (ulong)createdAt.ToUniversalTime().Ticks, - ExpiresInSeconds = expiresInSeconds, + AccessToken = accessToken ?? string.Empty, + RefreshToken = refreshToken ?? string.Empty, Scope = TraktAccessScope.Public, TokenType = TraktAccessTokenType.Bearer, - AccessToken = accessToken ?? string.Empty, - RefreshToken = refreshToken ?? string.Empty + ExpiresInSeconds = expiresInSeconds, + CreatedAtTimestamp = CalculateTimestamp(createdAt) }; - public override string ToString() + private static ulong CalculateTimestamp(DateTime createdAt) { - var validUntil = CreatedAt.AddSeconds(ExpiresInSeconds); - var strIsExpired = IsExpired ? "(expired)" : $"(valid until {validUntil})"; - return IsValid ? $"{AccessToken} {strIsExpired}" : $"no valid access token {strIsExpired}"; - } - - public bool Equals(ITraktAuthorization other) - { - if (other == null || other.IsValid != IsValid - || other.IsExpired != IsExpired - || other.IsRefreshPossible != IsRefreshPossible - || ((TraktAuthorization)other).IgnoreExpiration != IgnoreExpiration - || other.ExpiresInSeconds != ExpiresInSeconds - || other.CreatedAtTimestamp != CreatedAtTimestamp - || other.CreatedAt != CreatedAt - || other.AccessToken != AccessToken - || other.RefreshToken != RefreshToken - || other.Scope != Scope - || other.TokenType != TokenType) - { - return false; - } - - return true; + const long ticksPerMilliseconds = TimeSpan.TicksPerMillisecond; + var origin = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + long originMilliseconds = origin.Ticks / ticksPerMilliseconds; + DateTime utcCreatedAt = createdAt.ToUniversalTime(); + long utcCreatedAtMilliseconds = utcCreatedAt.Ticks / ticksPerMilliseconds; + long differenceInMilliseconds = utcCreatedAtMilliseconds - originMilliseconds; + return (ulong) (differenceInMilliseconds / 1000); } } } diff --git a/Source/Tests/TraktApiSharp.PreNextVersion.Tests/Authentication/TraktAuthorizationTests.cs b/Source/Tests/TraktApiSharp.PreNextVersion.Tests/Authentication/TraktAuthorizationTests.cs deleted file mode 100644 index 1030c7b81..000000000 --- a/Source/Tests/TraktApiSharp.PreNextVersion.Tests/Authentication/TraktAuthorizationTests.cs +++ /dev/null @@ -1,339 +0,0 @@ -namespace TraktApiSharp.Tests.Authentication -{ - using FluentAssertions; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Newtonsoft.Json; - using System; - using TraktApiSharp.Enums; - using TraktApiSharp.Objects.Authentication.Implementations; - using Utils; - - [TestClass] - public class TraktAuthorizationTests - { - [TestMethod] - public void TestTraktAuthorizationDefaultConstructor() - { - var dtNowUtc = DateTime.UtcNow; - - var token = new TraktAuthorization(); - - token.AccessToken.Should().BeNullOrEmpty(); - token.Scope.Should().BeNull(); - token.TokenType.Should().BeNull(); - token.ExpiresInSeconds.Should().Be(0); - token.RefreshToken.Should().BeNullOrEmpty(); - token.IsValid.Should().BeFalse(); - token.IsRefreshPossible.Should().BeFalse(); - token.IsExpired.Should().BeTrue(); - token.CreatedAt.Should().BeCloseTo(dtNowUtc); - token.IgnoreExpiration.Should().BeFalse(); - } - - [TestMethod] - public void TestTraktAuthorizationReadFromJson() - { - var jsonFile = TestUtility.ReadFileContents(@"Authentication\AccessToken.json"); - - jsonFile.Should().NotBeNullOrEmpty(); - - var token = JsonConvert.DeserializeObject(jsonFile); - - token.Should().NotBeNull(); - token.AccessToken.Should().Be("dbaf9757982a9e738f05d249b7b5b4a266b3a139049317c4909f2f263572c781"); - token.TokenType.Should().Be(TraktAccessTokenType.Bearer); - token.ExpiresInSeconds.Should().Be(7200); - token.RefreshToken.Should().Be("76ba4c5c75c96f6087f58a4de10be6c00b29ea1ddc3b2022ee2016d1363e3a7c"); - token.Scope.Should().Be(TraktAccessScope.Public); - token.IsExpired.Should().BeFalse(); - token.IsValid.Should().BeTrue(); - token.IsRefreshPossible.Should().BeTrue(); - token.IgnoreExpiration.Should().BeFalse(); - } - - [TestMethod] - public void TestTraktAuthorizationIsValid() - { - var token = new TraktAuthorization(); - token.IsValid.Should().BeFalse(); - - token.AccessToken = string.Empty; - token.IsValid.Should().BeFalse(); - - token.AccessToken = "access token"; - token.IsValid.Should().BeFalse(); - - token.AccessToken = "accessToken"; - token.IsValid.Should().BeTrue(); - } - - [TestMethod] - public void TestTraktAuthorizationIsRefreshPossible() - { - var token = new TraktAuthorization(); - token.IsRefreshPossible.Should().BeFalse(); - - token.RefreshToken = string.Empty; - token.IsRefreshPossible.Should().BeFalse(); - - token.RefreshToken = "refresh token"; - token.IsRefreshPossible.Should().BeFalse(); - - token.RefreshToken = "refreshToken"; - token.IsRefreshPossible.Should().BeTrue(); - } - - [TestMethod] - public void TestTraktAuthorizationIsExpired() - { - var token = new TraktAuthorization(); - token.IsExpired.Should().BeTrue(); - - token.AccessToken = string.Empty; - token.IsExpired.Should().BeTrue(); - - token.AccessToken = "access token"; - token.IsExpired.Should().BeTrue(); - - token.AccessToken = "accessToken"; - token.IsExpired.Should().BeTrue(); - - token.ExpiresInSeconds = 1; - token.IsExpired.Should().BeFalse(); - } - - [TestMethod] - public void TestTraktAuthorizationIsExpiredWithIgnoreExpiration() - { - var token = new TraktAuthorization(); - token.IgnoreExpiration = true; - token.ExpiresInSeconds = 0; - - token.IsExpired.Should().BeTrue(); - - token.AccessToken = string.Empty; - token.IsExpired.Should().BeTrue(); - - token.AccessToken = "access token"; - token.IsExpired.Should().BeTrue(); - - token.AccessToken = "accessToken"; - token.IsExpired.Should().BeFalse(); - } - - [TestMethod] - public void TestTraktAuthorizationCreateWithAccessToken() - { - var accessToken = "accessToken"; - - var authorization = TraktAuthorization.CreateWith(accessToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); - authorization.Scope.Should().Be(TraktAccessScope.Public); - authorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); - authorization.IgnoreExpiration.Should().BeTrue(); - authorization.ExpiresInSeconds.Should().Be(0); - } - - [TestMethod] - public void TestTraktAuthorizationCreateWithAccessTokenAndRefreshToken() - { - var accessToken = "accessToken"; - var refreshToken = "refreshToken"; - - var authorization = TraktAuthorization.CreateWith(accessToken, refreshToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().Be(refreshToken); - authorization.Scope.Should().Be(TraktAccessScope.Public); - authorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); - authorization.IgnoreExpiration.Should().BeTrue(); - authorization.ExpiresInSeconds.Should().Be(0); - } - - [TestMethod] - public void TestTraktAuthorizationCreateWithExpiresInAndAccessToken() - { - uint expiresIn = 3600 * 24 * 90; - var accessToken = "accessToken"; - - var authorization = TraktAuthorization.CreateWith(expiresIn, accessToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); - authorization.Scope.Should().Be(TraktAccessScope.Public); - authorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); - authorization.IgnoreExpiration.Should().BeFalse(); - authorization.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, 1800 * 1000); - authorization.ExpiresInSeconds.Should().Be(expiresIn); - } - - [TestMethod] - public void TestTraktAuthorizationCreateWithExpiresInAndAccessTokenAndRefreshToken() - { - uint expiresIn = 3600 * 24 * 90; - - var accessToken = "accessToken"; - var refreshToken = "refreshToken"; - - var authorization = TraktAuthorization.CreateWith(expiresIn, accessToken, refreshToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().Be(refreshToken); - authorization.Scope.Should().Be(TraktAccessScope.Public); - authorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); - authorization.IgnoreExpiration.Should().BeFalse(); - authorization.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, 1800 * 1000); - authorization.ExpiresInSeconds.Should().Be(expiresIn); - } - - [TestMethod] - public void TestTraktAuthorizationCreateWithCreatedAtAndAccessToken() - { - var createdAt = DateTime.Now; - uint expiresIn = 3600 * 24 * 90; - var accessToken = "accessToken"; - - var authorization = TraktAuthorization.CreateWith(createdAt, accessToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); - authorization.Scope.Should().Be(TraktAccessScope.Public); - authorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); - authorization.IgnoreExpiration.Should().BeFalse(); - authorization.CreatedAt.Should().Be(createdAt.ToUniversalTime()); - authorization.ExpiresInSeconds.Should().Be(expiresIn); - } - - [TestMethod] - public void TestTraktAuthorizationCreateWithCreatedAtAndAccessTokenAndRefreshToken() - { - var createdAt = DateTime.Now; - uint expiresIn = 3600 * 24 * 90; - - var accessToken = "accessToken"; - var refreshToken = "refreshToken"; - - var authorization = TraktAuthorization.CreateWith(createdAt, accessToken, refreshToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().Be(refreshToken); - authorization.Scope.Should().Be(TraktAccessScope.Public); - authorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); - authorization.IgnoreExpiration.Should().BeFalse(); - authorization.CreatedAt.Should().Be(createdAt.ToUniversalTime()); - authorization.ExpiresInSeconds.Should().Be(expiresIn); - } - - [TestMethod] - public void TestTraktAuthorizationCreateWithCreatedAtAndExpiresInAndAccessToken() - { - var createdAt = DateTime.Now; - uint expiresIn = 3600 * 24 * 90; - var accessToken = "accessToken"; - - var authorization = TraktAuthorization.CreateWith(createdAt, expiresIn, accessToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); - authorization.Scope.Should().Be(TraktAccessScope.Public); - authorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); - authorization.IgnoreExpiration.Should().BeFalse(); - authorization.CreatedAt.Should().Be(createdAt.ToUniversalTime()); - authorization.ExpiresInSeconds.Should().Be(expiresIn); - } - - [TestMethod] - public void TestTraktAuthorizationCreateWithCreatedAtAndExpiresInAndAccessTokenAndRefreshToken() - { - var createdAt = DateTime.Now; - uint expiresIn = 3600 * 24 * 90; - - var accessToken = "accessToken"; - var refreshToken = "refreshToken"; - - var authorization = TraktAuthorization.CreateWith(createdAt, expiresIn, accessToken, refreshToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().Be(refreshToken); - authorization.Scope.Should().Be(TraktAccessScope.Public); - authorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); - authorization.IgnoreExpiration.Should().BeFalse(); - authorization.CreatedAt.Should().Be(createdAt.ToUniversalTime()); - authorization.ExpiresInSeconds.Should().Be(expiresIn); - } - - [TestMethod] - public void TestTraktAuthorizationCreateWithNullValues() - { - var createdAt = DateTime.Now; - uint expiresIn = 3600 * 24 * 90; - - var accessToken = "accessToken"; - var refreshToken = "refreshToken"; - - var authorization = TraktAuthorization.CreateWith(null, refreshToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().NotBeNull().And.BeEmpty(); - authorization.RefreshToken.Should().Be(refreshToken); - - authorization = TraktAuthorization.CreateWith(accessToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); - - // ------------------------------------------------------ - - authorization = TraktAuthorization.CreateWith(expiresIn, null, refreshToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().NotBeNull().And.BeEmpty(); - authorization.RefreshToken.Should().Be(refreshToken); - - authorization = TraktAuthorization.CreateWith(expiresIn, accessToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); - - // ------------------------------------------------------ - - authorization = TraktAuthorization.CreateWith(createdAt, null, refreshToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().NotBeNull().And.BeEmpty(); - authorization.RefreshToken.Should().Be(refreshToken); - - authorization = TraktAuthorization.CreateWith(createdAt, accessToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); - - // ------------------------------------------------------ - - authorization = TraktAuthorization.CreateWith(createdAt, expiresIn, null, refreshToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().NotBeNull().And.BeEmpty(); - authorization.RefreshToken.Should().Be(refreshToken); - - authorization = TraktAuthorization.CreateWith(createdAt, expiresIn, accessToken); - - authorization.Should().NotBeNull(); - authorization.AccessToken.Should().Be(accessToken); - authorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); - } - } -} diff --git a/Source/Tests/TraktApiSharp.PreNextVersion.Tests/TraktApiSharp.PreNextVersion.Tests.csproj b/Source/Tests/TraktApiSharp.PreNextVersion.Tests/TraktApiSharp.PreNextVersion.Tests.csproj index 2acb8794f..a4057fd72 100644 --- a/Source/Tests/TraktApiSharp.PreNextVersion.Tests/TraktApiSharp.PreNextVersion.Tests.csproj +++ b/Source/Tests/TraktApiSharp.PreNextVersion.Tests/TraktApiSharp.PreNextVersion.Tests.csproj @@ -93,7 +93,6 @@ - diff --git a/Source/Tests/TraktApiSharp.Tests/Objects/Authentication/Implementations/TraktAuthorization_Tests.cs b/Source/Tests/TraktApiSharp.Tests/Objects/Authentication/Implementations/TraktAuthorization_Tests.cs index 876d6911d..f8c4d226c 100644 --- a/Source/Tests/TraktApiSharp.Tests/Objects/Authentication/Implementations/TraktAuthorization_Tests.cs +++ b/Source/Tests/TraktApiSharp.Tests/Objects/Authentication/Implementations/TraktAuthorization_Tests.cs @@ -2,14 +2,24 @@ { using FluentAssertions; using System; + using System.Threading.Tasks; using Traits; + using TraktApiSharp.Enums; using TraktApiSharp.Objects.Authentication; using TraktApiSharp.Objects.Authentication.Implementations; + using TraktApiSharp.Objects.Authentication.JsonReader; using Xunit; [Category("Objects.Authentication.Implementations")] public class TraktAuthorization_Tests { + private static readonly DateTime s_timestampOriginPlusCurrent = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(1506271312); + private const string ACCESS_TOKEN = "accessToken"; + private const string REFRESH_TOKEN = "refreshToken"; + private const uint EXPIRES_IN_SECONDS = 7776000; + private static readonly DateTime s_createdAt = DateTime.UtcNow; + private static readonly ulong s_createdAtTimestamp = CalculateTimestamp(s_createdAt); + [Fact] public void Test_TraktAuthorization_Implements_ITraktCastAndCrew_Interface() { @@ -33,5 +43,528 @@ public void Test_TraktAuthorization_Default_Constructor() traktAuthorization.CreatedAt.Should().Be(default(DateTime)); traktAuthorization.IgnoreExpiration.Should().BeFalse(); } + + [Fact] + public async Task Test_TraktAuthorization_From_Json() + { + var jsonReader = new AuthorizationObjectJsonReader(); + TraktAuthorization traktAuthorization = await jsonReader.ReadObjectAsync(JSON); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be("dbaf9757982a9e738f05d249b7b5b4a266b3a139049317c4909f2f263572c781"); + traktAuthorization.RefreshToken.Should().Be("76ba4c5c75c96f6087f58a4de10be6c00b29ea1ddc3b2022ee2016d1363e3a7c"); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(7776000U); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.CreatedAtTimestamp.Should().Be(1506271312UL); + traktAuthorization.CreatedAt.Should().Be(s_timestampOriginPlusCurrent); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeTrue(); + traktAuthorization.IgnoreExpiration.Should().BeFalse(); + } + + [Fact] + public void Test_TraktAuthorization_IsValid() + { + var traktAuthorization = new TraktAuthorization(); + + traktAuthorization.IsValid.Should().BeFalse(); + + traktAuthorization.AccessToken = string.Empty; + traktAuthorization.IsValid.Should().BeFalse(); + + traktAuthorization.AccessToken = "access token"; + traktAuthorization.IsValid.Should().BeFalse(); + + traktAuthorization.AccessToken = "accessToken"; + traktAuthorization.IsValid.Should().BeTrue(); + } + + [Fact] + public void Test_TraktAuthorization_IsRefreshPossible() + { + var traktAuthorization = new TraktAuthorization(); + + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + + traktAuthorization.RefreshToken = string.Empty; + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + + traktAuthorization.RefreshToken = "refresh token"; + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + + traktAuthorization.RefreshToken = "refreshToken"; + traktAuthorization.IsRefreshPossible.Should().BeTrue(); + } + + [Fact] + public void Test_TraktAuthorization_IsExpired() + { + var origin = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + DateTime utcNow = DateTime.UtcNow; + const long ticksPerSecond = TimeSpan.TicksPerSecond; + long utcNowSeconds = utcNow.Ticks / ticksPerSecond; + long originSeconds = origin.Ticks / ticksPerSecond; + long differenceSeconds = utcNowSeconds - originSeconds; + + var traktAuthorization = new TraktAuthorization + { + CreatedAtTimestamp = (ulong)differenceSeconds + }; + + traktAuthorization.IsExpired.Should().BeTrue(); + + traktAuthorization.AccessToken = string.Empty; + traktAuthorization.IsExpired.Should().BeTrue(); + + traktAuthorization.AccessToken = "access token"; + traktAuthorization.IsExpired.Should().BeTrue(); + + traktAuthorization.AccessToken = "accessToken"; + traktAuthorization.IsExpired.Should().BeTrue(); + + traktAuthorization.ExpiresInSeconds = 1; + traktAuthorization.IsExpired.Should().BeFalse(); + } + + [Fact] + public void Test_TraktAuthorization_IsExpired_With_IgnoreExpiration() + { + var traktAuthorization = new TraktAuthorization + { + IgnoreExpiration = true, + ExpiresInSeconds = 0 + }; + + traktAuthorization.IsExpired.Should().BeTrue(); + + traktAuthorization.AccessToken = string.Empty; + traktAuthorization.IsExpired.Should().BeTrue(); + + traktAuthorization.AccessToken = "access token"; + traktAuthorization.IsExpired.Should().BeTrue(); + + traktAuthorization.AccessToken = "accessToken"; + traktAuthorization.IsExpired.Should().BeFalse(); + } + + [Fact] + public void Test_TraktAuthorization_CreatedAt() + { + var traktAuthorization = new TraktAuthorization(); + + traktAuthorization.CreatedAt.Should().Be(default(DateTime)); + + traktAuthorization.CreatedAtTimestamp = 1506271312; + traktAuthorization.CreatedAt.Should().Be(s_timestampOriginPlusCurrent); + } + + [Fact] + public void Test_TraktAuthorization_ToString() + { + var origin = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + DateTime utcNow = DateTime.UtcNow; + const long ticksPerSecond = TimeSpan.TicksPerSecond; + long utcNowSeconds = utcNow.Ticks / ticksPerSecond; + long originSeconds = origin.Ticks / ticksPerSecond; + long differenceSeconds = utcNowSeconds - originSeconds; + + var traktAuthorization = new TraktAuthorization(); + + traktAuthorization.ToString().Should().Be("no valid access token (expired)"); + + traktAuthorization.AccessToken = "accessToken"; + traktAuthorization.ToString().Should().Be($"{traktAuthorization.AccessToken} (expired)"); + + traktAuthorization.CreatedAtTimestamp = (ulong)differenceSeconds; + traktAuthorization.CreatedAt.Should().Be(origin.AddSeconds(differenceSeconds)); + traktAuthorization.ExpiresInSeconds = 600; + traktAuthorization.ToString().Should().Be($"{traktAuthorization.AccessToken} (valid until {traktAuthorization.CreatedAt.AddSeconds(traktAuthorization.ExpiresInSeconds)})"); + } + + [Fact] + public async Task Test_TraktAuthorization_Equals() + { + var traktAuthorization1 = new TraktAuthorization(); + var traktAuthorization2 = new TraktAuthorization(); + + traktAuthorization1.Equals(traktAuthorization2).Should().BeTrue(); + + var jsonReader = new AuthorizationObjectJsonReader(); + TraktAuthorization traktAuthorizationFromJson = await jsonReader.ReadObjectAsync(JSON); + + traktAuthorization1 = CopyTraktAuthorization(traktAuthorizationFromJson); + traktAuthorization2 = CopyTraktAuthorization(traktAuthorizationFromJson); + + traktAuthorization2.Equals(traktAuthorization1).Should().BeTrue(); + + traktAuthorization1 = CopyTraktAuthorization(traktAuthorizationFromJson); + traktAuthorization1.AccessToken = null; + traktAuthorization2.Equals(traktAuthorization1).Should().BeFalse(); + + traktAuthorization1 = CopyTraktAuthorization(traktAuthorizationFromJson); + traktAuthorization1.RefreshToken = null; + traktAuthorization2.Equals(traktAuthorization1).Should().BeFalse(); + + traktAuthorization1 = CopyTraktAuthorization(traktAuthorizationFromJson); + traktAuthorization1.ExpiresInSeconds = 0; + traktAuthorization2.Equals(traktAuthorization1).Should().BeFalse(); + + traktAuthorization1 = CopyTraktAuthorization(traktAuthorizationFromJson); + traktAuthorization1.ExpiresInSeconds = 0; + traktAuthorization2.Equals(traktAuthorization1).Should().BeFalse(); + + traktAuthorization1 = CopyTraktAuthorization(traktAuthorizationFromJson); + traktAuthorization1.Scope = null; + traktAuthorization2.Equals(traktAuthorization1).Should().BeFalse(); + + traktAuthorization1 = CopyTraktAuthorization(traktAuthorizationFromJson); + traktAuthorization1.TokenType = null; + traktAuthorization2.Equals(traktAuthorization1).Should().BeFalse(); + + traktAuthorization1 = CopyTraktAuthorization(traktAuthorizationFromJson); + traktAuthorization1.CreatedAtTimestamp = 0; + traktAuthorization2.Equals(traktAuthorization1).Should().BeFalse(); + } + + [Fact] + public void Test_TraktAuthorization_CreateWith_AccessToken() + { + DateTime createdAtUtcNow = DateTime.UtcNow; + ulong createdAtUtcNowTimestamp = CalculateTimestamp(createdAtUtcNow); + + TraktAuthorization traktAuthorization = TraktAuthorization.CreateWith(ACCESS_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().BeInRange(createdAtUtcNowTimestamp - 2, createdAtUtcNowTimestamp + 2); + traktAuthorization.CreatedAt.Should().BeCloseTo(createdAtUtcNow, 1000); + traktAuthorization.IgnoreExpiration.Should().BeTrue(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + } + + [Fact] + public void Test_TraktAuthorization_CreateWith_AccessToken_And_RefreshToken() + { + DateTime createdAtUtcNow = DateTime.UtcNow; + ulong createdAtUtcNowTimestamp = CalculateTimestamp(createdAtUtcNow); + + TraktAuthorization traktAuthorization = TraktAuthorization.CreateWith(ACCESS_TOKEN, REFRESH_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().Be(REFRESH_TOKEN); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().BeInRange(createdAtUtcNowTimestamp - 2, createdAtUtcNowTimestamp + 2); + traktAuthorization.CreatedAt.Should().BeCloseTo(createdAtUtcNow, 1000); + traktAuthorization.IgnoreExpiration.Should().BeTrue(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeTrue(); + } + + [Fact] + public void Test_TraktAuthorization_CreateWith_ExpiresIn_And_AccessToken() + { + DateTime createdAtUtcNow = DateTime.UtcNow; + ulong createdAtUtcNowTimestamp = CalculateTimestamp(createdAtUtcNow); + + TraktAuthorization traktAuthorization = TraktAuthorization.CreateWith(EXPIRES_IN_SECONDS, ACCESS_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().BeInRange(createdAtUtcNowTimestamp - 2, createdAtUtcNowTimestamp + 2); + traktAuthorization.CreatedAt.Should().BeCloseTo(createdAtUtcNow, 1000); + traktAuthorization.IgnoreExpiration.Should().BeFalse(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + } + + [Fact] + public void Test_TraktAuthorization_CreateWith_ExpiresIn_And_AccessToken_And_RefreshToken() + { + DateTime createdAtUtcNow = DateTime.UtcNow; + ulong createdAtUtcNowTimestamp = CalculateTimestamp(createdAtUtcNow); + + TraktAuthorization traktAuthorization = TraktAuthorization.CreateWith(EXPIRES_IN_SECONDS, ACCESS_TOKEN, REFRESH_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().Be(REFRESH_TOKEN); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().BeInRange(createdAtUtcNowTimestamp - 2, createdAtUtcNowTimestamp + 2); + traktAuthorization.CreatedAt.Should().BeCloseTo(createdAtUtcNow, 1000); + traktAuthorization.IgnoreExpiration.Should().BeFalse(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeTrue(); + } + + [Fact] + public void Test_TraktAuthorization_CreateWith_CreatedAt_And_AccessToken() + { + TraktAuthorization traktAuthorization = TraktAuthorization.CreateWith(s_createdAt, ACCESS_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().Be(s_createdAtTimestamp); + traktAuthorization.CreatedAt.Should().BeCloseTo(s_createdAt, 1000); + traktAuthorization.IgnoreExpiration.Should().BeTrue(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + } + + [Fact] + public void Test_TraktAuthorization_CreateWith_CreatedAt_And_AccessToken_And_RefreshToken() + { + TraktAuthorization traktAuthorization = TraktAuthorization.CreateWith(s_createdAt, ACCESS_TOKEN, REFRESH_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().Be(REFRESH_TOKEN); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().Be(s_createdAtTimestamp); + traktAuthorization.CreatedAt.Should().BeCloseTo(s_createdAt, 1000); + traktAuthorization.IgnoreExpiration.Should().BeTrue(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeTrue(); + } + + [Fact] + public void Test_TraktAuthorization_CreateWith_CreatedAt_And_ExpiresIn_And_AccessToken() + { + TraktAuthorization traktAuthorization = TraktAuthorization.CreateWith(s_createdAt, EXPIRES_IN_SECONDS, ACCESS_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().Be(s_createdAtTimestamp); + traktAuthorization.CreatedAt.Should().BeCloseTo(s_createdAt, 1000); + traktAuthorization.IgnoreExpiration.Should().BeFalse(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + } + + [Fact] + public void Test_TraktAuthorization_CreateWith_CreatedAt_And_ExpiresIn_And_AccessToken_And_RefreshToken() + { + TraktAuthorization traktAuthorization = TraktAuthorization.CreateWith(s_createdAt, EXPIRES_IN_SECONDS, ACCESS_TOKEN, REFRESH_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().Be(REFRESH_TOKEN); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().Be(s_createdAtTimestamp); + traktAuthorization.CreatedAt.Should().BeCloseTo(s_createdAt, 1000); + traktAuthorization.IgnoreExpiration.Should().BeFalse(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeTrue(); + } + + [Fact] + public void Test_TraktAuthorization_CreateWith_Null_Values() + { + DateTime createdAtUtcNow = DateTime.UtcNow; + ulong createdAtUtcNowTimestamp = CalculateTimestamp(createdAtUtcNow); + + TraktAuthorization traktAuthorization = TraktAuthorization.CreateWith(null, REFRESH_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.RefreshToken.Should().Be(REFRESH_TOKEN); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().BeInRange(createdAtUtcNowTimestamp - 2, createdAtUtcNowTimestamp + 2); + traktAuthorization.CreatedAt.Should().BeCloseTo(createdAtUtcNow, 1000); + traktAuthorization.IgnoreExpiration.Should().BeTrue(); + traktAuthorization.IsExpired.Should().BeTrue(); + traktAuthorization.IsValid.Should().BeFalse(); + traktAuthorization.IsRefreshPossible.Should().BeTrue(); + + // ------------------------------------------------------ + + traktAuthorization = TraktAuthorization.CreateWith(ACCESS_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().BeInRange(createdAtUtcNowTimestamp - 2, createdAtUtcNowTimestamp + 2); + traktAuthorization.CreatedAt.Should().BeCloseTo(createdAtUtcNow, 1000); + traktAuthorization.IgnoreExpiration.Should().BeTrue(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + + // ------------------------------------------------------ + // ------------------------------------------------------ + + traktAuthorization = TraktAuthorization.CreateWith(EXPIRES_IN_SECONDS, null, REFRESH_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.RefreshToken.Should().Be(REFRESH_TOKEN); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().BeInRange(createdAtUtcNowTimestamp - 2, createdAtUtcNowTimestamp + 2); + traktAuthorization.CreatedAt.Should().BeCloseTo(createdAtUtcNow, 1000); + traktAuthorization.IgnoreExpiration.Should().BeFalse(); + traktAuthorization.IsExpired.Should().BeTrue(); + traktAuthorization.IsValid.Should().BeFalse(); + traktAuthorization.IsRefreshPossible.Should().BeTrue(); + + // ------------------------------------------------------ + + traktAuthorization = TraktAuthorization.CreateWith(EXPIRES_IN_SECONDS, ACCESS_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().BeInRange(createdAtUtcNowTimestamp - 2, createdAtUtcNowTimestamp + 2); + traktAuthorization.CreatedAt.Should().BeCloseTo(createdAtUtcNow, 1000); + traktAuthorization.IgnoreExpiration.Should().BeFalse(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + + // ------------------------------------------------------ + // ------------------------------------------------------ + + traktAuthorization = TraktAuthorization.CreateWith(s_createdAt, null, REFRESH_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.RefreshToken.Should().Be(REFRESH_TOKEN); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().Be(s_createdAtTimestamp); + traktAuthorization.CreatedAt.Should().BeCloseTo(s_createdAt, 1000); + traktAuthorization.IgnoreExpiration.Should().BeTrue(); + traktAuthorization.IsExpired.Should().BeTrue(); + traktAuthorization.IsValid.Should().BeFalse(); + traktAuthorization.IsRefreshPossible.Should().BeTrue(); + + // ------------------------------------------------------ + + traktAuthorization = TraktAuthorization.CreateWith(s_createdAt, ACCESS_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().Be(s_createdAtTimestamp); + traktAuthorization.CreatedAt.Should().BeCloseTo(s_createdAt, 1000); + traktAuthorization.IgnoreExpiration.Should().BeTrue(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + + // ------------------------------------------------------ + + traktAuthorization = TraktAuthorization.CreateWith(s_createdAt, EXPIRES_IN_SECONDS, null, REFRESH_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.RefreshToken.Should().Be(REFRESH_TOKEN); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().Be(s_createdAtTimestamp); + traktAuthorization.CreatedAt.Should().BeCloseTo(s_createdAt, 1000); + traktAuthorization.IgnoreExpiration.Should().BeFalse(); + traktAuthorization.IsExpired.Should().BeTrue(); + traktAuthorization.IsValid.Should().BeFalse(); + traktAuthorization.IsRefreshPossible.Should().BeTrue(); + + // ------------------------------------------------------ + + traktAuthorization = TraktAuthorization.CreateWith(s_createdAt, EXPIRES_IN_SECONDS, ACCESS_TOKEN); + + traktAuthorization.Should().NotBeNull(); + traktAuthorization.AccessToken.Should().Be(ACCESS_TOKEN); + traktAuthorization.RefreshToken.Should().NotBeNull().And.BeEmpty(); + traktAuthorization.Scope.Should().Be(TraktAccessScope.Public); + traktAuthorization.TokenType.Should().Be(TraktAccessTokenType.Bearer); + traktAuthorization.ExpiresInSeconds.Should().Be(EXPIRES_IN_SECONDS); + traktAuthorization.CreatedAtTimestamp.Should().Be(s_createdAtTimestamp); + traktAuthorization.CreatedAt.Should().BeCloseTo(s_createdAt, 1000); + traktAuthorization.IgnoreExpiration.Should().BeFalse(); + traktAuthorization.IsExpired.Should().BeFalse(); + traktAuthorization.IsValid.Should().BeTrue(); + traktAuthorization.IsRefreshPossible.Should().BeFalse(); + } + + private static TraktAuthorization CopyTraktAuthorization(ITraktAuthorization traktAuthorization) + { + return new TraktAuthorization + { + AccessToken = traktAuthorization.AccessToken, + RefreshToken = traktAuthorization.RefreshToken, + Scope = traktAuthorization.Scope, + TokenType = traktAuthorization.TokenType, + ExpiresInSeconds = traktAuthorization.ExpiresInSeconds, + CreatedAtTimestamp = traktAuthorization.CreatedAtTimestamp + }; + } + + private static ulong CalculateTimestamp(DateTime createdAt) + { + var origin = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + long originSeconds = origin.Ticks / TimeSpan.TicksPerSecond; + DateTime utcCreatedAt = createdAt.ToUniversalTime(); + long utcCreatedAtSeconds = utcCreatedAt.Ticks / TimeSpan.TicksPerSecond; + return (ulong)(utcCreatedAtSeconds - originSeconds); + } + + private const string JSON = + @"{ + ""access_token"": ""dbaf9757982a9e738f05d249b7b5b4a266b3a139049317c4909f2f263572c781"", + ""refresh_token"": ""76ba4c5c75c96f6087f58a4de10be6c00b29ea1ddc3b2022ee2016d1363e3a7c"", + ""token_type"": ""bearer"", + ""expires_in"": 7776000, + ""scope"": ""public"", + ""created_at"": 1506271312 + }"; } }