diff --git a/Source/HaloSharp.Test/Config/Halo5Config.cs b/Source/HaloSharp.Test/Config/Halo5Config.cs index 71729d9..2bc0b2b 100644 --- a/Source/HaloSharp.Test/Config/Halo5Config.cs +++ b/Source/HaloSharp.Test/Config/Halo5Config.cs @@ -44,6 +44,9 @@ public static class Halo5Config public const string WeaponsJsonPath = "JSON/Halo5/Metadata/weapons.json"; public const string WeaponsJsonSchemaPath = "JSON/Halo5/Metadata/weapons.schema.json"; + public const string PlayerAppearancePath = "JSON/Halo5/Profile/player-appearance.json"; + public const string PlayerAppearanceSchemaPath = "JSON/Halo5/Profile/player-appearance.schema.json"; + public const string ArenaMatchJsonPath = "JSON/Halo5/Stats/CarnageReport/arena-match.json"; public const string ArenaMatchJsonSchemaPath = "JSON/Halo5/Stats/CarnageReport/arena-match.schema.json"; public const string CampaignMatchJsonPath = "JSON/Halo5/Stats/CarnageReport/campaign-match.json"; diff --git a/Source/HaloSharp.Test/HaloSharp.Test.csproj b/Source/HaloSharp.Test/HaloSharp.Test.csproj index f6a9592..bbe4857 100644 --- a/Source/HaloSharp.Test/HaloSharp.Test.csproj +++ b/Source/HaloSharp.Test/HaloSharp.Test.csproj @@ -86,6 +86,7 @@ + @@ -270,6 +271,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -623,6 +630,9 @@ HaloSharp + + + diff --git a/Source/HaloSharp.Test/JSON/Halo5/Profile/player-appearance.json b/Source/HaloSharp.Test/JSON/Halo5/Profile/player-appearance.json new file mode 100644 index 0000000..1bf5dcb --- /dev/null +++ b/Source/HaloSharp.Test/JSON/Halo5/Profile/player-appearance.json @@ -0,0 +1,14 @@ +{ + "Gamertag": "Furiousn00b", + "LastModifiedUtc": { + "ISO8601Date": "2016-07-03T00:00:00Z" + }, + "FirstModifiedUtc": { + "ISO8601Date": "2015-10-19T00:00:00Z" + }, + "ServiceTag": "FURI", + "Company": { + "Id": "a2f47e59-5cc0-44f8-a542-77c162fe69e8", + "Name": "Section 3" + } +} \ No newline at end of file diff --git a/Source/HaloSharp.Test/JSON/Halo5/Profile/player-appearance.schema.json b/Source/HaloSharp.Test/JSON/Halo5/Profile/player-appearance.schema.json new file mode 100644 index 0000000..11c38a2 --- /dev/null +++ b/Source/HaloSharp.Test/JSON/Halo5/Profile/player-appearance.schema.json @@ -0,0 +1,47 @@ +{ + "definitions": { + "Player-Appearance": { + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "additionalProperties": false, + "properties": { + "Gamertag": { + "type": "string" + }, + "LastModifiedUTC": { + "$ref": "../../common/iso-8061.schema.json" + }, + "FirstModifiedUTC": { + "$ref": "../../common/iso-8061.schema.json" + }, + "ServiceTag": { + "type": "string" + }, + "Company": { + "type": [ "array", "null" ], + "items": { + "Id": { + "type": "guid" + }, + "Name": { + "type": "string" + } + } + } + }, + "required": [ + "Gamertag", + "LastModifiedUTC", + "FirstModifiedUTC", + "ServiceTag", + "Company" + ] + } + }, + + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "array", + "items": { + "$ref": "#/definitions/Player-Appearance" + } +} \ No newline at end of file diff --git a/Source/HaloSharp.Test/Query/Halo5/Profile/GetPlayerAppearanceTests.cs b/Source/HaloSharp.Test/Query/Halo5/Profile/GetPlayerAppearanceTests.cs new file mode 100644 index 0000000..0d898b3 --- /dev/null +++ b/Source/HaloSharp.Test/Query/Halo5/Profile/GetPlayerAppearanceTests.cs @@ -0,0 +1,144 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using HaloSharp.Exception; +using HaloSharp.Extension; +using HaloSharp.Model; +using HaloSharp.Model.Common; +using HaloSharp.Model.Halo5.Profile; +using HaloSharp.Query.Halo5.Profile; +using HaloSharp.Test.Config; +using HaloSharp.Test.Utility; +using Moq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; +using NUnit.Framework; + +namespace HaloSharp.Test.Query.Halo5.Profile +{ + [TestFixture] + public class GetPlayerAppearanceTests + { + + private IHaloSession _mockSession; + private PlayerAppearance _playerAppearance; + + [SetUp] + public void Setup() + { + _playerAppearance = JsonConvert.DeserializeObject(File.ReadAllText(Halo5Config.PlayerAppearancePath)); + + var mock = new Mock(); + mock.Setup(m => m.Get(It.IsAny())) + .ReturnsAsync(_playerAppearance); + + _mockSession = mock.Object; + } + + [Test] + [TestCase("Sn1p3r C")] + [TestCase("Furiousn00b")] + public void Uri_MatchesExpected(string gamertag) + { + var query = new GetPlayerAppearance(gamertag); + + Assert.AreEqual($"https://www.haloapi.com/profile/h5/profiles/{gamertag}/appearance", query.Uri); + } + + [Test] + [TestCase("Furiousn00b")] + public async Task Query_DoesNotThrow(string gamertag) + { + var query = new GetPlayerAppearance(gamertag) + .SkipCache(); + + var result = await _mockSession.Query(query); + + Assert.IsInstanceOf(typeof(PlayerAppearance), result); + Assert.AreEqual(_playerAppearance, result); + } + + [Test] + [TestCase("Greenskull")] + [TestCase("Furiousn00b")] + public async Task GetPlayerAppearance_DoesNotThrow(string gamertag) + { + var query = new GetPlayerAppearance(gamertag) + .SkipCache(); + + var result = await Global.Session.Query(query); + + Assert.IsInstanceOf(typeof(PlayerAppearance), result); + } + + [Test] + [TestCase("Greenskull")] + [TestCase("Furiousn00b")] + public async Task GetPlayerAppearance_SchemaIsValid(string gamertag) + { + var playerAppearanceSchema = JSchema.Parse(File.ReadAllText(Halo5Config.PlayerAppearancePath), new JSchemaReaderSettings + { + Resolver = new JSchemaUrlResolver(), + BaseUri = new Uri(Path.GetFullPath(Halo5Config.PlayerAppearanceSchemaPath)) + }); + + var query = new GetPlayerAppearance(gamertag) + .SkipCache(); + + var jArray = await Global.Session.Get(query.Uri); + + SchemaUtility.AssertSchemaIsValid(playerAppearanceSchema, jArray); + } + + [Test] + [TestCase("Greenskull")] + [TestCase("Furiousn00b")] + public async Task GetPlayerAppearance_ModelMatchesSchema(string gamertag) + { + + var schema = JSchema.Parse(File.ReadAllText(Halo5Config.PlayerAppearancePath), new JSchemaReaderSettings + { + Resolver = new JSchemaUrlResolver(), + BaseUri = new Uri(Path.GetFullPath(Halo5Config.PlayerAppearanceSchemaPath)) + }); + + var query = new GetPlayerAppearance(gamertag) + .SkipCache(); + + var result = await Global.Session.Query(query); + + var json = JsonConvert.SerializeObject(result); + var jContainer = JsonConvert.DeserializeObject(json); + + SchemaUtility.AssertSchemaIsValid(schema, jContainer); + } + + [Test] + [TestCase("Greenskull")] + [TestCase("Furiousn00b")] + public async Task GetPlayerAppearance_IsSerializable(string gamertag) + { + var query = new GetPlayerAppearance(gamertag) + .SkipCache(); + + var result = await Global.Session.Query(query); + + SerializationUtility.AssertRoundTripSerializationIsPossible(result); + } + + [Test] + [TestCase("00000000000000017")] + [TestCase("!$%")] + [ExpectedException(typeof(ValidationException))] + public async Task GetPlayerAppearance_InvalidGamertag(string gamertag) + { + var query = new GetPlayerAppearance(gamertag); + + await Global.Session.Query(query); + Assert.Fail("An exception should have been thrown"); + } + + + } +} diff --git a/Source/HaloSharp/HaloSharp.csproj b/Source/HaloSharp/HaloSharp.csproj index d9387ac..00972b6 100644 --- a/Source/HaloSharp/HaloSharp.csproj +++ b/Source/HaloSharp/HaloSharp.csproj @@ -91,6 +91,7 @@ + @@ -262,6 +263,7 @@ + diff --git a/Source/HaloSharp/Model/Halo5/Profile/PlayerAppearance.cs b/Source/HaloSharp/Model/Halo5/Profile/PlayerAppearance.cs new file mode 100644 index 0000000..96c86b0 --- /dev/null +++ b/Source/HaloSharp/Model/Halo5/Profile/PlayerAppearance.cs @@ -0,0 +1,77 @@ +using System; +using Newtonsoft.Json; +using HaloSharp.Model.Common; + +namespace HaloSharp.Model.Halo5.Profile +{ + [Serializable] + public class PlayerAppearance : IEquatable + { + [JsonProperty(PropertyName = "gamertag")] + public string Gamertag { get; set; } + + [JsonProperty(PropertyName = "LastModifiedUtc")] + public ISO8601 LastModifiedUtc { get; set; } + + [JsonProperty(PropertyName = "FirstModifiedUtc")] + public ISO8601 FirstModifiedUtc { get; set; } + + [JsonProperty(PropertyName = "serviceTag")] + public string ServiceTag { get; set; } + + [JsonProperty(PropertyName = "Company")] + public Company company { get; set; } + + public bool Equals(PlayerAppearance other) + { + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return company.Equals(other.company) + && Gamertag == other.Gamertag + && LastModifiedUtc == other.LastModifiedUtc + && FirstModifiedUtc == other.FirstModifiedUtc + && ServiceTag == other.ServiceTag; + } + } + + [Serializable] + public class Company : IEquatable + { + [JsonProperty(PropertyName = "id")] + public Guid Id { get; set; } + + [JsonProperty(PropertyName = "name")] + public string Name { get; set; } + + + public bool Equals(Company other) + { + + if (ReferenceEquals(null, other)) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return Id == other.Id + && Name == other.Name; + } + + } + + + + +} diff --git a/Source/HaloSharp/Query/Halo5/Profile/GetPlayerAppearance.cs b/Source/HaloSharp/Query/Halo5/Profile/GetPlayerAppearance.cs new file mode 100644 index 0000000..54757ae --- /dev/null +++ b/Source/HaloSharp/Query/Halo5/Profile/GetPlayerAppearance.cs @@ -0,0 +1,37 @@ +using HaloSharp.Exception; +using HaloSharp.Model; +using HaloSharp.Model.Halo5.Profile; +using HaloSharp.Validation.Common; + +namespace HaloSharp.Query.Halo5.Profile +{ + public class GetPlayerAppearance : Query + { + protected virtual string Path => $"profile/h5/profiles/{_player}/appearance"; + + public override string Uri => HaloUriBuilder.Build(Path); + + private readonly string _player; + + public GetPlayerAppearance(string gamertag) + { + _player = gamertag; + } + + protected override void Validate() + { + var validationResult = new ValidationResult(); + + if(!_player.IsValidGamertag()) + { + validationResult.Messages.Add("GetPlayerAppearance query requires a valid Gamertag (Player) to be set."); + } + + if (!validationResult.Success) + { + throw new ValidationException(validationResult.Messages); + } + } + + } +}