Skip to content

Commit 2c26e64

Browse files
author
Lasse Sjorup
committed
Added time condition files. not included in project file yet.
1 parent e4fef83 commit 2c26e64

8 files changed

Lines changed: 441 additions & 25 deletions

File tree

project/UnitTests/Core/Tasks/ConditionalTaskTest.cs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4-
using System.Linq;
5-
using System.Text;
64
using Exortech.NetReflector;
75
using NUnit.Framework;
86
using Rhino.Mocks;
97
using ThoughtWorks.CruiseControl.Core;
108
using ThoughtWorks.CruiseControl.Core.Tasks;
11-
using ThoughtWorks.CruiseControl.Core.Util;
12-
using ThoughtWorks.CruiseControl.Remote;
9+
using ThoughtWorks.CruiseControl.Remote.Parameters;
1310

1411
namespace ThoughtWorks.CruiseControl.UnitTests.Core.Tasks
1512
{
@@ -19,22 +16,22 @@ public class ConditionalTaskTest
1916
MockRepository mocks = new MockRepository();
2017

2118
[SetUp]
22-
protected void SetUp()
19+
protected virtual void SetUp()
2320
{
2421
}
2522

2623
[TearDown]
27-
protected void TearDown()
24+
protected virtual void TearDown()
2825
{
2926
}
3027

3128
[TestFixtureSetUp]
32-
public void TestFixtureSetup()
29+
public virtual void TestFixtureSetup()
3330
{
3431
}
3532

3633
[TestFixtureTearDown]
37-
public void TestFixtureTearDown()
34+
public virtual void TestFixtureTearDown()
3835
{
3936
}
4037

@@ -91,8 +88,7 @@ public void ConditionalTaskTest_ConditionTrue_RunTask()
9188
ITask runTask = mocks.StrictMock<ITask>();
9289
Expect.Call(delegate { runTask.Run(null); }).IgnoreArguments();
9390
ITask noRunTask = mocks.StrictMock<ITask>();
94-
IIntegrationResult ResultMock = IntegrationResultMother.CreateSuccessful(); //mocks.StrictMock<IIntegrationResult>();
95-
//Expect.Call(ResultMock.Status).PropertyBehavior().Return(IntegrationStatus.Success).IgnoreArguments().Repeat.Any();
91+
IIntegrationResult ResultMock = IntegrationResultMother.CreateSuccessful();
9692

9793
mocks.ReplayAll();
9894

@@ -116,10 +112,6 @@ public void ConditionalTaskTest_ConditionFalse_RunElseTask()
116112
Expect.Call(delegate { runTask.Run(null); }).IgnoreArguments();
117113
ITask noRunTask = mocks.StrictMock<ITask>();
118114
IIntegrationResult ResultMock = IntegrationResultMother.CreateSuccessful();
119-
//mocks.StrictMock<IIntegrationResult>();
120-
//BuildProgressInformation bpi = mocks.StrictMock<BuildProgressInformation>
121-
//Expect.Call(ResultMock.Status).PropertyBehavior().Return(IntegrationStatus.Success).IgnoreArguments().Repeat.Any();
122-
//Expect.Call(ResultMock.BuildProgressInformation).IgnoreArguments().Return()
123115
mocks.ReplayAll();
124116

125117
ConditionalTask task = new ConditionalTask();
@@ -155,5 +147,21 @@ public void ConditionalTaskTest_xmlinterface_pass()
155147
Debug.WriteLine(testXml);
156148
ConditionalTask result = NetReflector.Read(testXml) as ConditionalTask;
157149
}
150+
151+
//[Test]
152+
//[Description("DynamicValues Success")]
153+
//[Category("Category")]
154+
//public void ConditionalTaskTest_DynamicValues_Success()
155+
//{
156+
// CommentTask task = new CommentTask();
157+
// task.Message = "$[buildType|DEV]";
158+
159+
// IEnumerable<ParameterBase> pardef = null;
160+
// Dictionary<string, string> par = new Dictionary<string, string>();
161+
// par.Add("buildType", "TEST");
162+
// task.ApplyParameters(par, pardef);
163+
// Assert.That(task.Message, Is.EqualTo("TEST"));
164+
//}
165+
158166
}
159167
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Text.RegularExpressions;
5+
6+
namespace ThoughtWorks.CruiseControl.Core.tasks.Conditions.DateTimeHelpers
7+
{
8+
[DebuggerDisplay("Time period [{FromTime} - {ToTime}] Inverted : {Inverted}")]
9+
public class TimePeriod
10+
{
11+
private static readonly Regex valueSplitter = new Regex(@"^(?<From>\d{1,2}:\d{2})-(?<To>\d{1,2}:\d{2})$");
12+
13+
private readonly TimeSpan _fromTime;
14+
private readonly bool _inverted;
15+
16+
private readonly TimeSpan _toTime;
17+
18+
/// <exception cref="System.ArgumentException"><c>ArgumentException</c>.</exception>
19+
public TimePeriod(string source)
20+
{
21+
if (!valueSplitter.IsMatch(source))
22+
throw new ArgumentException("Time periods must be in for format '[hour]:[minute]-[hour]:[minute]'");
23+
24+
Match split = valueSplitter.Match(source);
25+
26+
_fromTime = Parse(split.Groups["From"].Value);
27+
_toTime = Parse(split.Groups["To"].Value);
28+
29+
if (_fromTime > _toTime)
30+
{
31+
_inverted = true;
32+
TimeSpan tempSpan = _fromTime;
33+
_fromTime = _toTime;
34+
_toTime = tempSpan;
35+
}
36+
}
37+
38+
private TimeSpan FromTime
39+
{
40+
get
41+
{
42+
return _fromTime;
43+
}
44+
}
45+
46+
private TimeSpan ToTime
47+
{
48+
get
49+
{
50+
return _toTime;
51+
}
52+
}
53+
54+
private bool Inverted
55+
{
56+
get
57+
{
58+
return _inverted;
59+
}
60+
}
61+
62+
public static implicit operator string(TimePeriod p)
63+
{
64+
return p.ToString();
65+
}
66+
67+
public static implicit operator TimePeriod(string s)
68+
{
69+
return new TimePeriod(s);
70+
}
71+
72+
public static TimePeriod[] ParsePeriods(string periods)
73+
{
74+
List<TimePeriod> result = new List<TimePeriod>();
75+
76+
string[] periodArray = periods.Split(',');
77+
foreach (string period in periodArray)
78+
{
79+
result.Add(new TimePeriod(period));
80+
}
81+
82+
return result.ToArray();
83+
}
84+
85+
/// <exception cref="ArgumentException"><c>ArgumentException</c>.</exception>
86+
public static TimeSpan Parse(string value)
87+
{
88+
TimeSpan result;
89+
if (!TimeSpan.TryParse(value, out result))
90+
if (value == "24:00")
91+
result = new TimeSpan(1, 0, 0, 0);
92+
else
93+
throw new ArgumentException("Invalid time specification '" + value + "'");
94+
return result;
95+
}
96+
97+
public bool Contained(TimeSpan time)
98+
{
99+
bool contained = (FromTime.Ticks <= time.Ticks && ToTime.Ticks >= time.Ticks);
100+
return Inverted ? !contained : contained;
101+
}
102+
103+
public override string ToString()
104+
{
105+
TimeSpan to = Inverted ? FromTime : ToTime;
106+
TimeSpan from = Inverted ? ToTime : FromTime;
107+
108+
if (to.Days == 0)
109+
return string.Format("{0:D2}:{1:D2}-{2:D2}:{3:D2}", from.Hours, from.Minutes, to.Hours, to.Minutes);
110+
111+
return string.Format("{0:D2}:{1:D2}-24:00", from.Hours, from.Minutes);
112+
}
113+
}
114+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace ThoughtWorks.CruiseControl.Core.tasks.Conditions.DateTimeHelpers
2+
{
3+
public enum TimeToEvaluate
4+
{
5+
now,
6+
buildStart,
7+
buildEnd,
8+
firstModification,
9+
lastModification
10+
}
11+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System;
2+
using System.Text.RegularExpressions;
3+
4+
namespace ThoughtWorks.CruiseControl.Core.tasks.Conditions.DateTimeHelpers
5+
{
6+
public static class DatetimeFunctions
7+
{
8+
internal static DateTime getTimeInTimeZone(string zone, DateTime time)
9+
{
10+
TimeSpan offset = getTimeZoneOffset(zone, time);
11+
return time.Add(offset);
12+
}
13+
14+
/// <exception cref="ArgumentException">Timezone must be in the format GMT[+|-][hour]:[minute]</exception>
15+
public static TimeSpan getTimeZoneOffset(string zone, DateTime time)
16+
{
17+
if (string.IsNullOrEmpty(zone) || zone.Equals("current", StringComparison.InvariantCultureIgnoreCase)) return new TimeSpan(0);
18+
19+
TimeSpan baseOffset = new TimeSpan(-TimeZone.CurrentTimeZone.GetUtcOffset(time).Ticks);
20+
21+
TimeSpan timeZoneOffset = ParseTimeZone(zone);
22+
return timeZoneOffset - baseOffset;
23+
}
24+
25+
public static TimeSpan ParseTimeZone(string zone)
26+
{
27+
Regex timezoneSplitter = new Regex(@"^GMT(?<offset>(?<symbol>[+-])(?<hour>\d{1,2})(:(?<minute>\d{2}))?)?$");
28+
if (!timezoneSplitter.IsMatch(zone))
29+
throw new ArgumentException("Timezone must be in the format GMT[+|-][hour]:[minute]");
30+
31+
Match timezone = timezoneSplitter.Match(zone);
32+
if (!timezone.Groups["offset"].Success)
33+
return new TimeSpan(0); //Only GMT specified
34+
35+
bool positive = timezone.Groups["symbol"].Value == "+";
36+
int hours = 0;
37+
int minutes = 0;
38+
int.TryParse(timezone.Groups["hour"].Value, out hours);
39+
int.TryParse(timezone.Groups["minute"].Value, out minutes);
40+
41+
if(hours>12)
42+
throw new ArgumentException("GMT must be between -12 and +12");
43+
44+
if(minutes<0 || minutes>59)
45+
throw new ArgumentException("Minutes must be between 0 and 59");
46+
47+
TimeSpan timeZoneOffset = positive ? new TimeSpan(0, hours, minutes, 0) : -new TimeSpan(0, hours, minutes, 0);
48+
return timeZoneOffset;
49+
}
50+
}
51+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
3+
namespace ThoughtWorks.CruiseControl.Core.tasks.Conditions.DateTimeHelpers
4+
{
5+
[Flags]
6+
public enum WeekDay
7+
{
8+
None = 0,
9+
Monday = 1,
10+
Mon = 1,
11+
Thusday = 2,
12+
Tue = 2,
13+
Wednesday = 4,
14+
Wed = 4,
15+
Thursday = 8,
16+
Thu = 8,
17+
Friday = 16,
18+
Fri = 16,
19+
Saturday = 32,
20+
Sat = 32,
21+
Sunday = 64,
22+
Sun = 64,
23+
24+
Weekend = Sat | Sun,
25+
Workweek = Mon | Tue | Wed | Thu | Fri,
26+
Any = Weekend | Workweek
27+
}
28+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
3+
namespace ThoughtWorks.CruiseControl.Core.tasks.Conditions.DateTimeHelpers
4+
{
5+
public class WeekDayMask
6+
{
7+
private WeekDay mask;
8+
public WeekDayMask(string weekdays)
9+
{
10+
mask = GetWeekDayMask(weekdays);
11+
}
12+
13+
internal static WeekDay GetWeekDayMask(string weekdays)
14+
{
15+
WeekDay result = WeekDay.None;
16+
foreach (string weekday in weekdays.Split(','))
17+
{
18+
if (weekday.Contains("-"))
19+
{
20+
string[] split = weekday.Split('-');
21+
if (split.Length != 2)
22+
throw new ArgumentException("Invalid weekdays string", "weekdays");
23+
24+
WeekDay startWeekDay = ParseWeekDay(split[0]);
25+
int startOffset = (int)Math.Log((int)startWeekDay, 2);
26+
int endOffset = (int)Math.Log((int)ParseWeekDay(split[1]), 2);
27+
if (startOffset == endOffset)
28+
result = startWeekDay;
29+
else
30+
if (startOffset < endOffset)
31+
for (int i = startOffset; i <= endOffset; i++)
32+
result = result | (WeekDay)(int)Math.Pow(2, i);
33+
else
34+
{
35+
for (int i = 0; i <= endOffset; i++)
36+
result = result | (WeekDay)(int)Math.Pow(2, i);
37+
for (int i = startOffset; i <= 6; i++)
38+
result = result | (WeekDay)(int)Math.Pow(2, i);
39+
}
40+
}
41+
else
42+
result = result | ParseWeekDay(weekday);
43+
}
44+
return result;
45+
}
46+
47+
internal static WeekDay ParseWeekDay(string weekday)
48+
{
49+
try
50+
{
51+
return (WeekDay)Enum.Parse(typeof(WeekDay), weekday, true);
52+
}
53+
catch (Exception exception)
54+
{
55+
throw new ArgumentException("Unable to parse weekday string '" + weekday + "'", exception);
56+
}
57+
}
58+
59+
public override string ToString()
60+
{
61+
return mask.ToString();
62+
}
63+
64+
public static implicit operator string(WeekDayMask mask)
65+
{
66+
return mask.ToString();
67+
}
68+
69+
public static implicit operator WeekDayMask(string s)
70+
{
71+
return new WeekDayMask(s);
72+
}
73+
74+
public bool Contains(WeekDay day)
75+
{
76+
return ((day & mask) != WeekDay.None);
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)