Commit 70945137 authored by HankG's avatar HankG

Add initial timeinterval code (in-mem repo partial)

parent d5e11ca9
using System;
namespace MySocialPortalLib.Model
{
public class TimelineInterval
{
public string Id { get; set; }
public DateTimeOffset IntervalStart { get; set; }
public DateTimeOffset IntervalStop { get; set; }
public string TimelineName { get; set; }
public TimelineInterval()
{
Id = Guid.NewGuid().ToString();
IntervalStart = DateTimeOffset.UnixEpoch;
IntervalStop = DateTimeOffset.UnixEpoch;
TimelineName = "";
}
public bool AllEquals(TimelineInterval other)
{
const double threshold = 2;
return Id == other.Id
&& TimelineName == other.TimelineName
&& Math.Abs(IntervalStart.Subtract(other.IntervalStart).TotalMilliseconds) <= threshold
&& Math.Abs(IntervalStop.Subtract(other.IntervalStop).TotalMilliseconds) <= threshold;
}
protected bool Equals(TimelineInterval other)
{
if (other == null)
{
return false;
}
return Id == other.Id;
}
public override bool Equals(object? other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other)) return true;
if (other.GetType() != this.GetType()) return false;
return Equals((TimelineInterval) other);
}
public override int GetHashCode()
{
return (Id != null ? Id.GetHashCode(StringComparison.InvariantCulture) : 0);
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using MySocialPortalLib.Model;
namespace MySocialPortalLib.Repository
{
public interface ITimelineRepository
{
void AddOrUpdate (TimelineInterval interval);
TimelineInterval? FindById(string id);
IList<TimelineInterval> FindByInterval(DateTimeOffset start, DateTimeOffset stop, bool inclusive);
void Remove (TimelineInterval interval);
void RemoveById(string id);
void RemoveByRange(IEnumerable<TimelineInterval> intervals);
long Count();
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using MySocialPortalLib.Model;
namespace MySocialPortalLib.Repository
{
public class TimelineInMemoryRepository : ITimelineRepository
{
public TimelineInMemoryRepository()
{
Items = new Dictionary<string, TimelineInterval>();
}
public void AddOrUpdate(TimelineInterval interval)
{
Items[interval.Id] = interval;
}
public TimelineInterval? FindById(string id)
{
Items.TryGetValue(id, out var item);
return item;
}
public IList<TimelineInterval> FindByInterval(DateTimeOffset start, DateTimeOffset stop, bool inclusive)
{
throw new NotImplementedException();
}
public void Remove(TimelineInterval interval)
{
throw new NotImplementedException();
}
public void RemoveById(string id)
{
throw new NotImplementedException();
}
public void RemoveByRange(IEnumerable<TimelineInterval> intervals)
{
throw new NotImplementedException();
}
public long Count()
{
throw new NotImplementedException();
}
private Dictionary<string, TimelineInterval> Items;
}
}
\ No newline at end of file
namespace MySocialPortalLib.Service
{
public class TimelineManagementService
{
}
}
\ No newline at end of file
using System;
using MySocialPortalLib.Model;
using Newtonsoft.Json.Linq;
namespace MySocialPortalLib.Util
{
public static class TimelineIntervalUtilities
{
public static TimelineInterval Bounds(TimelineInterval item1, TimelineInterval item2)
{
if (item1 == null || item2 == null)
{
throw new NullReferenceException();
}
var start = item1.IntervalStart < item2.IntervalStart ? item1.IntervalStart : item2.IntervalStart;
var stop = item1.IntervalStop > item2.IntervalStop ? item1.IntervalStop : item2.IntervalStop;
return new TimelineInterval
{
IntervalStart = start,
IntervalStop = stop,
TimelineName = item1.TimelineName
};
}
public static TimelineInterval? Gap(TimelineInterval item1, TimelineInterval item2)
{
if (item1 == null || item2 == null)
{
return null;
}
var earlier = item1;
var later = item2;
if (item2.IntervalStart < item1.IntervalStart)
{
earlier = item2;
later = item1;
}
if (earlier.IntervalStop < later.IntervalStart)
{
return new TimelineInterval
{
IntervalStart = earlier.IntervalStop,
IntervalStop = later.IntervalStart,
TimelineName = item1.TimelineName
};
}
return null;
}
}
}
\ No newline at end of file
using System;
using System.Text.Json;
using MySocialPortalLib.Model;
using Xunit;
namespace MySocialPortalLibTest.Model
{
public class TimelineIntervalTest
{
[Fact]
public void TestConstruction()
{
Assert.NotNull(new TimelineInterval());
}
[Fact]
public void TestSerialization()
{
var interval = new TimelineInterval
{
IntervalStart = DateTimeOffset.Now,
IntervalStop = DateTimeOffset.Now.AddDays(1)
};
var json = JsonSerializer.Serialize(interval);
var interval2 = JsonSerializer.Deserialize<TimelineInterval>(json);
Assert.True(interval.AllEquals(interval2));
}
}
}
\ No newline at end of file
using System;
using MySocialPortalLib.Model;
using MySocialPortalLib.Util;
using Xunit;
namespace MySocialPortalLibTest.Util
{
public class TimelineItemUtilitiesTest
{
[Fact]
public void TestBounds()
{
const int year = 2019;
const int month = 5;
const int day = 6;
var expectedBoundsMinimum = new DateTimeOffset(year, month, day, 1, 0, 0, TimeSpan.Zero);
var expectedBoundsMaximum = new DateTimeOffset(year, month, day, 12, 0, 0, TimeSpan.Zero);
var label1 = "label";
var label2 = "label";
var interval1 = new TimelineInterval
{
IntervalStart = expectedBoundsMinimum,
IntervalStop = expectedBoundsMinimum.AddHours(1),
TimelineName = label1
};
var interval2 = new TimelineInterval
{
IntervalStart = expectedBoundsMaximum.AddHours(-1),
IntervalStop = expectedBoundsMaximum,
TimelineName = label2
};
var result = TimelineIntervalUtilities.Bounds(interval1, interval2);
Assert.Equal(expectedBoundsMinimum, result.IntervalStart);
Assert.Equal(expectedBoundsMaximum, result.IntervalStop);
Assert.Equal(label1, result.TimelineName);
result = TimelineIntervalUtilities.Bounds(interval2, interval1);
Assert.Equal(expectedBoundsMinimum, result.IntervalStart);
Assert.Equal(expectedBoundsMaximum, result.IntervalStop);
Assert.Equal(label2, result.TimelineName);
}
/// <summary>
/// Case A
/// #1 |-------------|
/// #2 |--------------|
/// </summary>
[Fact]
public void TestGapCaseA()
{
var label1 = "label1";
var label2 = "label2";
var interval1 = new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(1),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(3),
TimelineName = label1
};
var interval2 = new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(5),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(6),
TimelineName = label2
};
var result = TimelineIntervalUtilities.Gap(interval1, interval2);
Assert.Equal(interval1.IntervalStop, result.IntervalStart);
Assert.Equal(interval2.IntervalStart, result.IntervalStop);
Assert.Equal(label1, result.TimelineName);
}
/// <summary>
/// Case B
/// #1 |----------------------|
/// #2 |--------------|
/// </summary>
[Fact]
public void TestGapCaseB()
{
var label1 = "label1";
var label2 = "label2";
var interval1 = new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(1),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(6),
TimelineName = label1
};
var interval2 = new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(5),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(7),
TimelineName = label2
};
Assert.Null(TimelineIntervalUtilities.Gap(interval1, interval2));
}
/// <summary>
/// Case C
/// #1 |--------------|
/// #2 |----------------------|
/// </summary>
[Fact]
public void TestGapCaseC()
{
var label1 = "label1";
var label2 = "label2";
var interval1= new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(5),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(7),
TimelineName = label1
};
var interval2 = new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(1),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(6),
TimelineName = label2
};
Assert.Null(TimelineIntervalUtilities.Gap(interval1, interval2));
}
/// <summary>
/// Case D
/// #1 |--------------|
/// #2 |------|
/// </summary>
[Fact]
public void TestGapCaseD()
{
var label1 = "label1";
var label2 = "label2";
var interval1= new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(1),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(7),
TimelineName = label1
};
var interval2 = new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(3),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(4),
TimelineName = label2
};
Assert.Null(TimelineIntervalUtilities.Gap(interval1, interval2));
}
/// <summary>
/// Case E
/// #1 |--------------|
/// #2 |------|
/// </summary>
[Fact]
public void TestGapCaseE()
{
var label1 = "label1";
var label2 = "label2";
var interval1= new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(3),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(4),
TimelineName = label1
};
var interval2 = new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(1),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(7),
TimelineName = label2
};
Assert.Null(TimelineIntervalUtilities.Gap(interval1, interval2));
}
/// <summary>
/// Case F
/// #1 |--------------|
/// #2 |------|
/// </summary>
[Fact]
public void TestGapCaseF()
{
var label1 = "label1";
var label2 = "label2";
var interval1= new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(5),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(6),
TimelineName = label1
};
var interval2 = new TimelineInterval
{
IntervalStart = DateTimeOffset.UnixEpoch.AddDays(1),
IntervalStop = DateTimeOffset.UnixEpoch.AddDays(3),
TimelineName = label2
};
var result = TimelineIntervalUtilities.Gap(interval1, interval2);
Assert.Equal(interval2.IntervalStop, result.IntervalStart);
Assert.Equal(interval1.IntervalStart, result.IntervalStop);
Assert.Equal(label1, result.TimelineName);
}
}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment