Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions HDTTests/Controls/Overlay/Arena/ArenaPickApiTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
using Hearthstone_Deck_Tracker.Controls.Overlay.Arena;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;

namespace HDTTests.Controls.Overlay.Arena
{
[TestClass]
public class ArenaPickApiTests
{
#region MessageTypeConverter.ReadJson

[DataTestMethod]
[DataRow("\"ENHANCED_BY\"", MessageType.EnhancedBy)]
[DataRow("\"CARDS_ENABLED\"", MessageType.CardsEnabled)]
[DataRow("\"OFFERED_COPY\"", MessageType.OfferedCopy)]
[DataRow("\"LOW_SYNERGY\"", MessageType.LowSynergy)]
[DataRow("\"HIGHLANDER\"", MessageType.Highlander)]
[DataRow("\"SOFT_HIGHLANDER\"", MessageType.SoftHighlander)]
[DataRow("\"HIGHLANDER_CHANCES\"", MessageType.HighlanderChances)]
[DataRow("\"VERY_RARE\"", MessageType.VeryRare)]
[DataRow("\"SCORE_BOOST\"", MessageType.ScoreBoost)]
[DataRow("\"QUEST_HELPS\"", MessageType.QuestHelps)]
[DataRow("\"QUEST_NUM_REQ\"", MessageType.QuestNumReq)]
[DataRow("\"INVALID\"", MessageType.Invalid)]
public void ReadJson_KnownStrings_MapToExpectedType(string json, MessageType expected)
{
Assert.AreEqual(expected, JsonConvert.DeserializeObject<MessageType>(json));
}

[TestMethod]
public void ReadJson_IsCaseInsensitiveAndTrimsWhitespace()
{
Assert.AreEqual(MessageType.EnhancedBy, JsonConvert.DeserializeObject<MessageType>("\" enhanced_by \""));
Assert.AreEqual(MessageType.VeryRare, JsonConvert.DeserializeObject<MessageType>("\"Very_Rare\""));
}

[TestMethod]
public void ReadJson_UnknownString_ReturnsInvalid()
{
Assert.AreEqual(MessageType.Invalid, JsonConvert.DeserializeObject<MessageType>("\"SOMETHING_ELSE\""));
}

[DataTestMethod]
[DataRow("\"\"")]
[DataRow("\" \"")]
public void ReadJson_EmptyOrWhitespace_ReturnsInvalid(string json)
{
Assert.AreEqual(MessageType.Invalid, JsonConvert.DeserializeObject<MessageType>(json));
}

[DataTestMethod]
[DataRow("123")]
[DataRow("true")]
[DataRow("null")]
public void ReadJson_NonStringToken_ReturnsInvalid(string json)
{
Assert.AreEqual(MessageType.Invalid, JsonConvert.DeserializeObject<MessageType>(json));
}

#endregion

#region MessageTypeConverter.WriteJson

[DataTestMethod]
[DataRow(MessageType.EnhancedBy, "ENHANCED_BY")]
[DataRow(MessageType.CardsEnabled, "CARDS_ENABLED")]
[DataRow(MessageType.OfferedCopy, "OFFERED_COPY")]
[DataRow(MessageType.LowSynergy, "LOW_SYNERGY")]
[DataRow(MessageType.Highlander, "HIGHLANDER")]
[DataRow(MessageType.SoftHighlander, "SOFT_HIGHLANDER")]
[DataRow(MessageType.HighlanderChances, "HIGHLANDER_CHANCES")]
[DataRow(MessageType.VeryRare, "VERY_RARE")]
[DataRow(MessageType.ScoreBoost, "SCORE_BOOST")]
[DataRow(MessageType.QuestHelps, "QUEST_HELPS")]
[DataRow(MessageType.QuestNumReq, "QUEST_NUM_REQ")]
[DataRow(MessageType.Invalid, "INVALID")]
public void WriteJson_SerializesToExpectedWireString(MessageType type, string expectedWire)
{
Assert.AreEqual("\"" + expectedWire + "\"", JsonConvert.SerializeObject(type));
}

[DataTestMethod]
[DataRow(MessageType.EnhancedBy)]
[DataRow(MessageType.LowSynergy)]
[DataRow(MessageType.QuestNumReq)]
[DataRow(MessageType.Invalid)]
public void WriteThenRead_RoundTripsToSameValue(MessageType type)
{
var json = JsonConvert.SerializeObject(type);
Assert.AreEqual(type, JsonConvert.DeserializeObject<MessageType>(json));
}

#endregion

#region Message.ParseContent

[TestMethod]
public void ParseContent_WithPopulatedContent_DeserializesFields()
{
var msg = JsonConvert.DeserializeObject<ArenaCardPickApiResponse.Message>(
"{\"type\":\"LOW_SYNERGY\",\"content\":{\"remaining_picks\":7}}");

Assert.AreEqual(MessageType.LowSynergy, msg.Type);
var content = msg.ParseContent<LowSynergyMessageContent>();
Assert.AreEqual(7, content.RemainingPicks);
}

[TestMethod]
public void ParseContent_WithNullContent_ReturnsDefaultInstance()
{
var msg = JsonConvert.DeserializeObject<ArenaCardPickApiResponse.Message>(
"{\"type\":\"LOW_SYNERGY\",\"content\":null}");

var content = msg.ParseContent<LowSynergyMessageContent>();
Assert.IsNotNull(content);
Assert.IsNull(content.RemainingPicks);
}

[TestMethod]
public void ParseContent_WithEmptyContent_ReturnsDefaultInstance()
{
var msg = JsonConvert.DeserializeObject<ArenaCardPickApiResponse.Message>(
"{\"type\":\"LOW_SYNERGY\",\"content\":{}}");

var content = msg.ParseContent<LowSynergyMessageContent>();
Assert.IsNotNull(content);
Assert.IsNull(content.RemainingPicks);
}

[TestMethod]
public void ParseContent_HighlanderContent_MapsCardId()
{
var msg = JsonConvert.DeserializeObject<ArenaCardPickApiResponse.Message>(
"{\"type\":\"HIGHLANDER\",\"content\":{\"highlander_card_id\":\"AT_001\"}}");

Assert.AreEqual(MessageType.Highlander, msg.Type);
Assert.AreEqual("AT_001", msg.ParseContent<HighlanderMessageContent>().HighlanderCardId);
}

[TestMethod]
public void Message_UnknownType_DeserializesAsInvalid()
{
var msg = JsonConvert.DeserializeObject<ArenaCardPickApiResponse.Message>(
"{\"type\":\"WHO_KNOWS\",\"content\":{}}");

Assert.AreEqual(MessageType.Invalid, msg.Type);
}

#endregion
}
}
27 changes: 27 additions & 0 deletions HDTTests/HsReplay/ArenaTrialTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Hearthstone_Deck_Tracker.HsReplay;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace HDTTests.HsReplay
{
[TestClass]
public class ArenaTrialTests
{
[TestMethod]
public void FormatDiagnostics_IncludesCountsTotalAndResetHours()
{
var s = ArenaTrial.FormatDiagnostics(1, 2, 5);
StringAssert.Contains(s, "starter=1");
StringAssert.Contains(s, "recurring=2");
StringAssert.Contains(s, "total=3");
StringAssert.Contains(s, "resetInHours=5");
}

[TestMethod]
public void FormatDiagnostics_NullResetHours_ShowsNotAvailable()
{
var s = ArenaTrial.FormatDiagnostics(0, 0, null);
StringAssert.Contains(s, "total=0");
StringAssert.Contains(s, "resetInHours=n/a");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,11 @@ private async void UpdateChoices(List<ArenaState.DraftChoice> choices)
{
if(starter + recurring == 0)
{
Log.Info("No trials left for hero pick, aborting");
Log.Info($"No trials left for hero pick, aborting ({ArenaTrial.FormatDiagnostics(starter, recurring, ArenaTrial.HoursUntilReset)})");
HSReplayNetClientAnalytics.OnArenaDraftStart(draftInfo, arenaOverlayVisible: false, IsTrialsActivated, trialsRemaining);
return;
}
Log.Info($"Trial activated for hero pick ({ArenaTrial.FormatDiagnostics(starter, recurring, ArenaTrial.HoursUntilReset)})");
IsTrialsActivated = true;
}

Expand Down Expand Up @@ -368,7 +369,7 @@ private async void UpdateChoices(List<ArenaState.DraftChoice> choices)
await ArenaTrial.EnsureLoaded(accountId.Hi, accountId.Lo);
if(!ArenaTrial.IsDeckResumable(deckId.Value))
{
Log.Info("Current deck is not registered for trials, aborting");
Log.Info($"Current deck ({deckId.Value}) is not registered for trials, aborting");
IsTrialsActivated = false;
ArenasmithScores.Clear();
return;
Expand Down Expand Up @@ -867,7 +868,7 @@ public async void OnDeckEditing()
await ArenaTrial.EnsureLoaded(accountId.Hi, accountId.Lo);
if(!ArenaTrial.IsDeckResumable(deckId.Value))
{
Log.Info("Current deck is not registered for trials, aborting");
Log.Info($"Current deck ({deckId.Value}) is not registered for trials, aborting");
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,12 @@

<StackPanel Visibility="{Binding IsTrialEnabledForDeck, Converter={StaticResource InverseBoolToVisibility}}">
<TextBlock Text="{lex:Loc ArenaPreDraft_Panel_JoinThisDraft}" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 8 0 0" Visibility="{Binding ResetTimeVisibility}">
<TextBlock>
<Run Text="{lex:Loc ArenaPreDraft_Panel_TrialsResetsIn}" />
<Bold><Run Text="{Binding TrialTimeRemaining}" /></Bold>
</TextBlock>
</StackPanel>
</StackPanel>
</StackPanel>
<Grid>
Expand Down
5 changes: 5 additions & 0 deletions Hearthstone Deck Tracker/HsReplay/ArenaTrial.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ static ArenaTrial()
private static ArenaTrialStatus? _status;
public static (int StarterTrialsRemaining, int RecurringTrialsRemaining)? RemainingTrials => _status != null ? (_status.StarterTrialsRemaining, _status.RecurringTrialsRemaining) : null;
public static int? MaxRecurringTrials => _status?.MaxRecurringTrials;
public static int? HoursUntilReset => _status?.HoursUntilReset;

internal static string FormatDiagnostics(int starterTrials, int recurringTrials, int? hoursUntilReset)
=> $"starter={starterTrials}, recurring={recurringTrials}, total={starterTrials + recurringTrials}, "
+ $"resetInHours={hoursUntilReset?.ToString() ?? "n/a"}";

public static string? TimeRemaining => _status?.HoursUntilReset == null ? null
: string.Format(LocUtil.Get("BattlegroundsPreLobby_Trial_ResetTimeRemaining_DaysHours"), _status.HoursUntilReset / 24, _status.HoursUntilReset % 24);
Expand Down