Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add duration property to the Item model to support the new duration feature. #35

Merged
merged 7 commits into from
Sep 30, 2023
54 changes: 54 additions & 0 deletions src/Todoist.Net.Tests/Models/DurationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;

using Todoist.Net.Models;
using Todoist.Net.Tests.Extensions;
using Xunit;

namespace Todoist.Net.Tests.Models
{
[Trait(Constants.TraitName, Constants.UnitTraitValue)]
public class DurationTests
{
[Fact]
public void AmountAssignment_InvalidValue_ThrowsException()
{
Duration duration;

Assert.Throws<ArgumentOutOfRangeException>(() =>
duration = new Duration(0, DurationUnit.Minute));

duration = new Duration(15, DurationUnit.Minute);

Assert.Throws<ArgumentOutOfRangeException>(() =>
duration.Amount = -5);
}

[Fact]
public void UnitAssignment_InvalidValue_ThrowsException()
{
Duration duration;

Assert.Throws<ArgumentNullException>(() =>
duration = new Duration(15, null));

duration = new Duration(15, DurationUnit.Minute);

Assert.Throws<ArgumentNullException>(() =>
duration.Unit = null);
}

[Fact]
public void TimeValueEvaluation_Success()
{
var duration = new Duration(15, DurationUnit.Minute);

Assert.Equal(TimeSpan.FromMinutes(15), duration.TimeValue);

duration.Amount = 3;
duration.Unit = DurationUnit.Day;

Assert.Equal(TimeSpan.FromDays(3), duration.TimeValue);
}

}
}
32 changes: 32 additions & 0 deletions src/Todoist.Net.Tests/Services/ItemsServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,5 +197,37 @@ public void CreateNewItem_DueDateIsLocal_DueDateNotChanged()

client.Items.DeleteAsync(item.Id).Wait();
}


[Fact]
[Trait(Constants.TraitName, Constants.IntegrationPremiumTraitValue)]
public void CreateItemClearDurationAndDelete_Success()
{
var client = TodoistClientFactory.Create(_outputHelper);

var item = new Item("duration task")
{
DueDate = new DueDate("22 Dec 2021 at 9:15", language: Language.English),
Duration = new Duration(45, DurationUnit.Minute)
};
client.Items.AddAsync(item).Wait();

var itemInfo = client.Items.GetAsync(item.Id).Result;

Assert.True(itemInfo.Item.Content == item.Content);
Assert.Equal("2021-12-22T09:15:00", itemInfo.Item.DueDate.StringDate);

Assert.Equal(item.Duration.Amount, itemInfo.Item.Duration.Amount);
Assert.Equal(item.Duration.Unit, itemInfo.Item.Duration.Unit);

itemInfo.Item.Duration = null;
client.Items.UpdateAsync(itemInfo.Item).Wait();

itemInfo = client.Items.GetAsync(item.Id).Result;
Assert.Null(itemInfo.Item.Duration);

client.Items.DeleteAsync(item.Id).Wait();
}

}
}
92 changes: 92 additions & 0 deletions src/Todoist.Net/Models/Duration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System;

using Newtonsoft.Json;

namespace Todoist.Net.Models
{
/// <summary>
/// Represents durations for tasks.
/// </summary>
public class Duration
{

private int _amount;
private DurationUnit _unit;

/// <summary>
/// Initializes a new instance of the <see cref="Duration" /> class.
/// </summary>
/// <param name="amount">The time amount.</param>
/// <param name="unit">The time unit.</param>
public Duration(int amount, DurationUnit unit)
{
Amount = amount;
Unit = unit;
}

internal Duration()
{
}

/// <summary>
/// Gets or sets the duration time amount.
/// </summary>
/// <remarks>
/// Must be a positive integer (greater than zero).
/// </remarks>
/// <value>
/// The time amount.
/// </value>
/// <exception cref="ArgumentOutOfRangeException">Duration amount must be greater than zero.</exception>"
[JsonProperty("amount")]
public int Amount
{
get => _amount;
set => _amount = value > 0
? value
: throw new ArgumentOutOfRangeException(nameof(Amount), "Duration amount must be greater than zero.");
}

/// <summary>
/// Gets or sets the duration time unit.
/// </summary>
/// <remarks>
/// Either <c>minute</c> or <c>day</c>.
/// </remarks>
/// <value>
/// The duration unit.
/// </value>
/// <exception cref="ArgumentNullException">Unit</exception>
[JsonProperty("unit")]
public DurationUnit Unit
{
get => _unit;
set => _unit = value ?? throw new ArgumentNullException(nameof(Unit));
}


/// <summary>
/// Gets the value of the duration as a <see cref="TimeSpan"/> object.
/// </summary>
/// <value>
/// The <see cref="TimeSpan"/> value of the duration.
/// </value>
[JsonIgnore]
public TimeSpan TimeValue
{
get
{
switch (Unit)
{
case var _ when Unit == DurationUnit.Minute:
return TimeSpan.FromMinutes(Amount);
case var _ when Unit == DurationUnit.Day:
return TimeSpan.FromDays(Amount);
default:
throw new NotImplementedException();
}
}
}

}
}
31 changes: 31 additions & 0 deletions src/Todoist.Net/Models/DurationUnit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace Todoist.Net.Models
{
/// <summary>
/// Represents a duration unit.
/// </summary>
/// <seealso cref="Todoist.Net.Models.StringEnum" />
public class DurationUnit : StringEnum
{
/// <summary>
/// Initializes a new instance of the <see cref="DurationUnit" /> class.
/// </summary>
/// <param name="value">The value.</param>
private DurationUnit(string value)
: base(value)
{
}

/// <summary>
/// Gets the minute unit.
/// </summary>
/// <value>The minute unit.</value>
public static DurationUnit Minute { get; } = new DurationUnit("minute");

/// <summary>
/// Gets the day unit.
/// </summary>
/// <value>The day unit.</value>
public static DurationUnit Day { get; } = new DurationUnit("day");

}
}
12 changes: 12 additions & 0 deletions src/Todoist.Net/Models/Item.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ internal Item()
[JsonProperty("due")]
public DueDate DueDate { get; set; }

/// <summary>
/// Gets or sets the duration.
/// </summary>
/// <remarks>
/// Durations are only available for Todoist Premium users.
/// </remarks>
/// <value>
/// The duration.
/// </value>
[JsonProperty("duration", NullValueHandling = NullValueHandling.Include)]
public Duration Duration { get; set; }

/// <summary>
/// Gets a value indicating whether this instance is checked.
/// </summary>
Expand Down