public void TimeZoneConverterTest(string input, string utcInput) { var utc = DateTime.Parse(utcInput).Normalize(); Assert.That(TimeParser.TryParse(input, out var result), Is.True, $"{input} failed to parse\nSupported time zones: {string.Join(", ", TimeParser.GetSupportedTimeZoneAbbreviations())}"); Assert.That(result, Is.EqualTo(utc)); Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Utc)); }
public void TimeZoneConverterTest(string input, string utcInput) { var utc = DateTime.Parse(utcInput).Normalize(); Assert.That(TimeParser.TryParse(input, out var result), Is.True); Assert.That(result, Is.EqualTo(utc)); Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Utc)); }
public void TryParse_WhenNullString_ThenReturnsFalse() { var result = timeParser.TryParse(null, out timeModel); Assert.IsFalse(result); }
private async Task <(bool success, DiscordMessage message)> EditEventPropertiesAsync(CommandContext ctx, EventSchedule evt, string eventName = null) { var interact = ctx.Client.GetInteractivity(); var abort = DiscordEmoji.FromUnicode("🛑"); var lastPage = DiscordEmoji.FromUnicode("↪"); var firstPage = DiscordEmoji.FromUnicode("↩"); var previousPage = DiscordEmoji.FromUnicode("⏪"); var nextPage = DiscordEmoji.FromUnicode("⏩"); var trash = DiscordEmoji.FromUnicode("🗑"); var saveEdit = DiscordEmoji.FromUnicode("💾"); var skipEventNameStep = !string.IsNullOrEmpty(eventName); DiscordMessage msg = null; string errorMsg = null; DiscordMessage txt; MessageReactionAddEventArgs emoji; step1: // step 1: get the new start date var embed = FormatEvent(evt, errorMsg, 1).WithDescription($"Example: `{DateTime.UtcNow:yyyy-MM-dd HH:mm} [PST]`\nBy default all times use UTC, only limited number of time zones supported"); msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Please specify a new **start date and time**", embed : embed).ConfigureAwait(false); errorMsg = null; (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, lastPage, nextPage, (evt.IsComplete() ? saveEdit : null)).ConfigureAwait(false); if (emoji != null) { if (emoji.Emoji == abort) { return(false, msg); } if (emoji.Emoji == saveEdit) { return(true, msg); } if (emoji.Emoji == lastPage) { goto step4; } } else if (txt != null) { if (!TimeParser.TryParse(txt.Content, out var newTime)) { errorMsg = $"Couldn't parse `{txt.Content}` as a start date and time"; goto step1; } var duration = evt.End - evt.Start; evt.Start = newTime.Ticks; evt.End = evt.Start + duration; evt.Year = newTime.Year; } else { return(false, msg); } step2: // step 2: get the new duration embed = FormatEvent(evt, errorMsg, 2).WithDescription("Example: `2d 1h 15m`, or `2.1:00`"); msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Please specify a new **event duration**", embed : embed.Build()).ConfigureAwait(false); errorMsg = null; (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, previousPage, nextPage, (evt.IsComplete() ? saveEdit : null)).ConfigureAwait(false); if (emoji != null) { if (emoji.Emoji == abort) { return(false, msg); } if (emoji.Emoji == saveEdit) { return(true, msg); } if (emoji.Emoji == previousPage) { goto step1; } if (skipEventNameStep) { goto step4; } } else if (txt != null) { var newLength = await TryParseTimeSpanAsync(ctx, txt.Content, false).ConfigureAwait(false); if (!newLength.HasValue) { errorMsg = $"Couldn't parse `{txt.Content}` as a duration"; goto step2; } evt.End = (evt.Start.AsUtc() + newLength.Value).Ticks; } else { return(false, msg); } step3: // step 3: get the new event name embed = FormatEvent(evt, errorMsg, 3); msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Please specify a new **event name**", embed : embed.Build()).ConfigureAwait(false); errorMsg = null; (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, previousPage, (string.IsNullOrEmpty(evt.EventName) ? null : trash), nextPage, (evt.IsComplete() ? saveEdit : null)).ConfigureAwait(false); if (emoji != null) { if (emoji.Emoji == abort) { return(false, msg); } if (emoji.Emoji == saveEdit) { return(true, msg); } if (emoji.Emoji == previousPage) { goto step2; } if (emoji.Emoji == trash) { evt.EventName = null; } } else if (txt != null) { evt.EventName = string.IsNullOrWhiteSpace(txt.Content) || txt.Content == "-" ? null : txt.Content; } else { return(false, msg); } step4: // step 4: get the new schedule entry name embed = FormatEvent(evt, errorMsg, 4); msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Please specify a new **schedule entry title**", embed : embed.Build()).ConfigureAwait(false); errorMsg = null; (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, previousPage, firstPage, (evt.IsComplete() ? saveEdit : null)).ConfigureAwait(false); if (emoji != null) { if (emoji.Emoji == abort) { return(false, msg); } if (emoji.Emoji == saveEdit) { return(true, msg); } if (emoji.Emoji == firstPage) { goto step1; } if (emoji.Emoji == previousPage) { if (skipEventNameStep) { goto step2; } goto step3; } } else if (txt != null) { if (string.IsNullOrEmpty(txt.Content)) { errorMsg = "Entry title cannot be empty"; goto step4; } evt.Name = txt.Content; } else { return(false, msg); } step5: // step 5: confirm if (errorMsg == null && !evt.IsComplete()) { errorMsg = "Some required properties are not defined"; } embed = FormatEvent(evt, errorMsg); msg = await msg.UpdateOrCreateMessageAsync(ctx.Channel, "Does this look good? (y/n)", embed : embed.Build()).ConfigureAwait(false); errorMsg = null; (msg, txt, emoji) = await interact.WaitForMessageOrReactionAsync(msg, ctx.User, InteractTimeout, abort, previousPage, firstPage, (evt.IsComplete() ? saveEdit : null)).ConfigureAwait(false); if (emoji != null) { if (emoji.Emoji == abort) { return(false, msg); } if (emoji.Emoji == saveEdit) { return(true, msg); } if (emoji.Emoji == previousPage) { goto step4; } if (emoji.Emoji == firstPage) { goto step1; } } else if (!string.IsNullOrEmpty(txt?.Content)) { if (!evt.IsComplete()) { goto step5; } switch (txt.Content.ToLowerInvariant()) { case "yes": case "y": case "✅": case "☑": case "✔": case "👌": case "👍": return(true, msg); case "no": case "n": case "❎": case "❌": case "👎": return(false, msg); default: errorMsg = "I don't know what you mean, so I'll just abort"; goto step5; } } else { return(false, msg); } return(false, msg); }