Skip to content

Commit 9627eed

Browse files
committed
Introduced strongly-typed Get/Set methods
Introduced `GetBoolean()`, `GetInteger()`, and `GetDateTime()` as well as corresponding `SetBoolean()`, `SetInteger()`, and `SetDateTime()` values. Retrofitted existing properties and established unit tests.
1 parent 6925697 commit 9627eed

5 files changed

Lines changed: 251 additions & 29 deletions

File tree

Ignia.Topics.Tests/AttributeValueCollectionTest.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
| Client Ignia, LLC
44
| Project Topics Library
55
\=============================================================================================================================*/
6+
using System;
67
using System.Reflection;
78
using Ignia.Topics.Collections;
89
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -30,6 +31,78 @@ public void AttributeValueCollection_GetValueTest() {
3031
Assert.AreEqual<string>("Test", topic.Attributes.GetValue("Key"));
3132
}
3233

34+
/*==========================================================================================================================
35+
| TEST: GET INTEGER
36+
\-------------------------------------------------------------------------------------------------------------------------*/
37+
/// <summary>
38+
/// Ensures that integer values can be set and retrieved as expected.
39+
/// </summary>
40+
[TestMethod]
41+
public void AttributeValueCollection_GetIntegerTest() {
42+
43+
var topic = TopicFactory.Create("Test", "Container");
44+
45+
topic.Attributes.SetInteger("Number1", 1);
46+
topic.Attributes.SetInteger("Number2", 2);
47+
topic.Attributes.SetValue("Number3", "Invalid");
48+
49+
Assert.AreEqual<int>(1, topic.Attributes.GetInteger("Number1", 5));
50+
Assert.AreEqual<int>(2, topic.Attributes.GetInteger("Number2", 5));
51+
Assert.AreEqual<int>(5, topic.Attributes.GetInteger("Number3", 5));
52+
Assert.AreEqual<int>(5, topic.Attributes.GetInteger("InvalidKey", 5));
53+
54+
}
55+
56+
/*==========================================================================================================================
57+
| TEST: GET DATETIME
58+
\-------------------------------------------------------------------------------------------------------------------------*/
59+
/// <summary>
60+
/// Ensures that integer values can be set and retrieved as expected.
61+
/// </summary>
62+
[TestMethod]
63+
public void AttributeValueCollection_GetDateTimeTest() {
64+
65+
var topic = TopicFactory.Create("Test", "Container");
66+
var dateTime1 = new DateTime(1976, 10, 15);
67+
var dateTime2 = new DateTime(1981, 06, 03);
68+
69+
topic.Attributes.SetDateTime("DateTime1", dateTime1);
70+
topic.Attributes.SetDateTime("DateTime2", dateTime2);
71+
topic.Attributes.SetValue("DateTime3", "Invalid");
72+
73+
Assert.AreEqual<DateTime>(dateTime1, topic.Attributes.GetDateTime("DateTime1", DateTime.MinValue));
74+
Assert.AreEqual<DateTime>(dateTime2, topic.Attributes.GetDateTime("DateTime2", DateTime.MinValue));
75+
Assert.AreEqual<DateTime>(dateTime1, topic.Attributes.GetDateTime("DateTime3", dateTime1));
76+
Assert.AreEqual<DateTime>(dateTime2, topic.Attributes.GetDateTime("InvalidKey", dateTime2));
77+
78+
}
79+
80+
/*==========================================================================================================================
81+
| TEST: GET BOOLEAN
82+
\-------------------------------------------------------------------------------------------------------------------------*/
83+
/// <summary>
84+
/// Ensures that boolean values can be set and retrieved as expected.
85+
/// </summary>
86+
[TestMethod]
87+
public void AttributeValueCollection_GetBooleanTest() {
88+
89+
var topic = TopicFactory.Create("Test", "Container");
90+
91+
topic.Attributes.SetBoolean("IsValue1", true);
92+
topic.Attributes.SetBoolean("IsValue2", false);
93+
topic.Attributes.SetValue("IsValue3", "Invalid");
94+
95+
Assert.IsTrue(topic.Attributes.GetBoolean("IsValue1", false));
96+
Assert.IsFalse(topic.Attributes.GetBoolean("IsValue2", true));
97+
Assert.IsTrue(topic.Attributes.GetBoolean("IsValue3", true));
98+
Assert.IsFalse(topic.Attributes.GetBoolean("IsValue3", false));
99+
Assert.IsTrue(topic.Attributes.GetBoolean("InvalidKey", true));
100+
Assert.IsFalse(topic.Attributes.GetBoolean("InvalidKey", false));
101+
102+
}
103+
104+
105+
33106
/*==========================================================================================================================
34107
| TEST: DEFAULT VALUE
35108
\-------------------------------------------------------------------------------------------------------------------------*/

Ignia.Topics/AttributeDescriptor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ public string GetConfigurationValue(string key, string defaultValue = null) {
218218
/// </remarks>
219219
[AttributeSetter]
220220
public new bool IsHidden {
221-
get => Attributes.GetValue("IsHidden", "0").Equals("1");
221+
get => Attributes.GetBoolean("IsHidden", false);
222222
set => SetAttributeValue("IsHidden", value? "1" : "0");
223223
}
224224

@@ -234,7 +234,7 @@ public string GetConfigurationValue(string key, string defaultValue = null) {
234234
/// </remarks>
235235
[AttributeSetter]
236236
public bool IsRequired {
237-
get => Attributes.GetValue("IsRequired", "0").Equals("1");
237+
get => Attributes.GetBoolean("IsRequired", false);
238238
set => SetAttributeValue("IsRequired", value ? "1" : "0");
239239
}
240240

@@ -275,7 +275,7 @@ public string DefaultValue {
275275
/// </remarks>
276276
[AttributeSetter]
277277
public bool StoreInBlob {
278-
get => Attributes.GetValue("StoreInBlob", "1").Equals("1");
278+
get => Attributes.GetBoolean("StoreInBlob", true);
279279
set => SetAttributeValue("StoreInBlob", value ? "1" : "0");
280280
}
281281

Ignia.Topics/Collections/AttributeValueCollection.cs

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,81 @@ private string GetValue(string name, string defaultValue, bool inheritFromParent
172172

173173
}
174174

175+
/*==========================================================================================================================
176+
| METHOD: GET BOOLEAN VALUE
177+
\-------------------------------------------------------------------------------------------------------------------------*/
178+
/// <summary>
179+
/// Gets a named attribute from the Attributes dictionary with a specified default value, an optional setting for enabling
180+
/// of inheritance, and an optional setting for searching through derived topics for values. Return as a boolean.
181+
/// </summary>
182+
/// <param name="name">The string identifier for the <see cref="AttributeValue"/>.</param>
183+
/// <param name="defaultValue">A string value to which to fall back in the case the value is not found.</param>
184+
/// <param name="inheritFromParent">
185+
/// Boolean indicator nothing whether to search through the topic's parents in order to get the value.
186+
/// </param>
187+
/// <param name="inheritFromDerived">
188+
/// Boolean indicator nothing whether to search through any of the topic's <see cref="Topic.DerivedTopic"/> topics in
189+
/// order to get the value.
190+
/// </param>
191+
/// <returns>The string value for the Attribute.</returns>
192+
public bool GetBoolean(string name, bool defaultValue, bool inheritFromParent = false, bool inheritFromDerived = true) {
193+
Contract.Requires<ArgumentNullException>(!String.IsNullOrWhiteSpace(name));
194+
return Int32.TryParse(
195+
GetValue(name, defaultValue ? "1" : "0", inheritFromParent, (inheritFromDerived ? 5 : 0)),
196+
out var result
197+
) ? result.Equals(1) : defaultValue;
198+
}
199+
200+
/*==========================================================================================================================
201+
| METHOD: GET INTEGER
202+
\-------------------------------------------------------------------------------------------------------------------------*/
203+
/// <summary>
204+
/// Gets a named attribute from the Attributes dictionary with a specified default value, an optional setting for enabling
205+
/// of inheritance, and an optional setting for searching through derived topics for values. Return as a integer.
206+
/// </summary>
207+
/// <param name="name">The string identifier for the <see cref="AttributeValue"/>.</param>
208+
/// <param name="defaultValue">A string value to which to fall back in the case the value is not found.</param>
209+
/// <param name="inheritFromParent">
210+
/// Boolean indicator nothing whether to search through the topic's parents in order to get the value.
211+
/// </param>
212+
/// <param name="inheritFromDerived">
213+
/// Boolean indicator nothing whether to search through any of the topic's <see cref="Topic.DerivedTopic"/> topics in
214+
/// order to get the value.
215+
/// </param>
216+
/// <returns>The string value for the Attribute.</returns>
217+
public int GetInteger(string name, int defaultValue, bool inheritFromParent = false, bool inheritFromDerived = true) {
218+
Contract.Requires<ArgumentNullException>(!String.IsNullOrWhiteSpace(name));
219+
return Int32.TryParse(
220+
GetValue(name, defaultValue.ToString(), inheritFromParent, (inheritFromDerived ? 5 : 0)),
221+
out var result
222+
)? result : defaultValue;
223+
}
224+
225+
/*==========================================================================================================================
226+
| METHOD: GET DATETIME
227+
\-------------------------------------------------------------------------------------------------------------------------*/
228+
/// <summary>
229+
/// Gets a named attribute from the Attributes dictionary with a specified default value, an optional setting for enabling
230+
/// of inheritance, and an optional setting for searching through derived topics for values. Return as a datetime.
231+
/// </summary>
232+
/// <param name="name">The string identifier for the <see cref="AttributeValue"/>.</param>
233+
/// <param name="defaultValue">A string value to which to fall back in the case the value is not found.</param>
234+
/// <param name="inheritFromParent">
235+
/// Boolean indicator nothing whether to search through the topic's parents in order to get the value.
236+
/// </param>
237+
/// <param name="inheritFromDerived">
238+
/// Boolean indicator nothing whether to search through any of the topic's <see cref="Topic.DerivedTopic"/> topics in
239+
/// order to get the value.
240+
/// </param>
241+
/// <returns>The string value for the Attribute.</returns>
242+
public DateTime GetDateTime(string name, DateTime defaultValue, bool inheritFromParent = false, bool inheritFromDerived = true) {
243+
Contract.Requires<ArgumentNullException>(!String.IsNullOrWhiteSpace(name));
244+
return DateTime.TryParse(
245+
GetValue(name, defaultValue.ToString(), inheritFromParent, (inheritFromDerived ? 5 : 0)),
246+
out var result
247+
)? result : defaultValue;
248+
}
249+
175250
/*==========================================================================================================================
176251
| METHOD: SET VALUE
177252
\-------------------------------------------------------------------------------------------------------------------------*/
@@ -291,6 +366,102 @@ internal void SetValue(string key, string value, bool? isDirty, bool enforceBusi
291366

292367
}
293368

369+
/*==========================================================================================================================
370+
| METHOD: SET BOOLEAN
371+
\-------------------------------------------------------------------------------------------------------------------------*/
372+
/// <summary>
373+
/// Helper method that either adds a new <see cref="AttributeValue"/> object or updates the value of an existing one,
374+
/// depending on whether that value already exists.
375+
/// </summary>
376+
/// <param name="key">The string identifier for the AttributeValue.</param>
377+
/// <param name="value">The text value for the AttributeValue.</param>
378+
/// <param name="isDirty">
379+
/// Specified whether the value should be marked as <see cref="AttributeValue.IsDirty"/>. By default, it will be marked as
380+
/// dirty if the value is new or has changed from a previous value. By setting this parameter, that behavior is
381+
/// overwritten to accept whatever value is submitted. This can be used, for instance, to prevent an update from being
382+
/// persisted to the data store on <see cref="ITopicRepository.Save(Topic, Boolean, Boolean)"/>.
383+
/// </param>
384+
/// <requires
385+
/// description="The key must be specified for the AttributeValue key/value pair."
386+
/// exception="T:System.ArgumentNullException">
387+
/// !String.IsNullOrWhiteSpace(key)
388+
/// </requires>
389+
/// <requires
390+
/// description="The value must be specified for the AttributeValue key/value pair."
391+
/// exception="T:System.ArgumentNullException">
392+
/// !String.IsNullOrWhiteSpace(value)
393+
/// </requires>
394+
/// <requires
395+
/// description="The key should be an alphanumeric sequence; it should not contain spaces or symbols"
396+
/// exception="T:System.ArgumentException">
397+
/// !value.Contains(" ")
398+
/// </requires>
399+
public void SetBoolean(string key, bool value, bool? isDirty = null) => SetValue(key, value? "1" : "0", isDirty, true);
400+
401+
/*==========================================================================================================================
402+
| METHOD: SET INTEGER
403+
\-------------------------------------------------------------------------------------------------------------------------*/
404+
/// <summary>
405+
/// Helper method that either adds a new <see cref="AttributeValue"/> object or updates the value of an existing one,
406+
/// depending on whether that value already exists.
407+
/// </summary>
408+
/// <param name="key">The string identifier for the AttributeValue.</param>
409+
/// <param name="value">The text value for the AttributeValue.</param>
410+
/// <param name="isDirty">
411+
/// Specified whether the value should be marked as <see cref="AttributeValue.IsDirty"/>. By default, it will be marked as
412+
/// dirty if the value is new or has changed from a previous value. By setting this parameter, that behavior is
413+
/// overwritten to accept whatever value is submitted. This can be used, for instance, to prevent an update from being
414+
/// persisted to the data store on <see cref="ITopicRepository.Save(Topic, Boolean, Boolean)"/>.
415+
/// </param>
416+
/// <requires
417+
/// description="The key must be specified for the AttributeValue key/value pair."
418+
/// exception="T:System.ArgumentNullException">
419+
/// !String.IsNullOrWhiteSpace(key)
420+
/// </requires>
421+
/// <requires
422+
/// description="The value must be specified for the AttributeValue key/value pair."
423+
/// exception="T:System.ArgumentNullException">
424+
/// !String.IsNullOrWhiteSpace(value)
425+
/// </requires>
426+
/// <requires
427+
/// description="The key should be an alphanumeric sequence; it should not contain spaces or symbols"
428+
/// exception="T:System.ArgumentException">
429+
/// !value.Contains(" ")
430+
/// </requires>
431+
public void SetInteger(string key, int value, bool? isDirty = null) => SetValue(key, value.ToString(), isDirty, true);
432+
433+
/*==========================================================================================================================
434+
| METHOD: SET DATETIME
435+
\-------------------------------------------------------------------------------------------------------------------------*/
436+
/// <summary>
437+
/// Helper method that either adds a new <see cref="AttributeValue"/> object or updates the value of an existing one,
438+
/// depending on whether that value already exists.
439+
/// </summary>
440+
/// <param name="key">The string identifier for the AttributeValue.</param>
441+
/// <param name="value">The text value for the AttributeValue.</param>
442+
/// <param name="isDirty">
443+
/// Specified whether the value should be marked as <see cref="AttributeValue.IsDirty"/>. By default, it will be marked as
444+
/// dirty if the value is new or has changed from a previous value. By setting this parameter, that behavior is
445+
/// overwritten to accept whatever value is submitted. This can be used, for instance, to prevent an update from being
446+
/// persisted to the data store on <see cref="ITopicRepository.Save(Topic, Boolean, Boolean)"/>.
447+
/// </param>
448+
/// <requires
449+
/// description="The key must be specified for the AttributeValue key/value pair."
450+
/// exception="T:System.ArgumentNullException">
451+
/// !String.IsNullOrWhiteSpace(key)
452+
/// </requires>
453+
/// <requires
454+
/// description="The value must be specified for the AttributeValue key/value pair."
455+
/// exception="T:System.ArgumentNullException">
456+
/// !String.IsNullOrWhiteSpace(value)
457+
/// </requires>
458+
/// <requires
459+
/// description="The key should be an alphanumeric sequence; it should not contain spaces or symbols"
460+
/// exception="T:System.ArgumentException">
461+
/// !value.Contains(" ")
462+
/// </requires>
463+
public void SetDateTime(string key, DateTime value, bool? isDirty = null) => SetValue(key, value.ToString(), isDirty, true);
464+
294465
/*==========================================================================================================================
295466
| OVERRIDE: INSERT ITEM
296467
\-------------------------------------------------------------------------------------------------------------------------*/

Ignia.Topics/ContentTypeDescriptor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public ContentTypeDescriptor(
9797
/// </remarks>
9898
[AttributeSetter]
9999
public bool DisableChildTopics {
100-
get => (Attributes.GetValue("DisableChildTopics", "0").Equals("1"));
100+
get => Attributes.GetBoolean("DisableChildTopics", false);
101101
set => SetAttributeValue("DisableChildTopics", value ? "1" : "0");
102102
}
103103

Ignia.Topics/Topic.cs

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ public string View {
254254
/// </summary>
255255
[AttributeSetter]
256256
public bool IsHidden {
257-
get => Attributes.GetValue("IsHidden", "0").Equals("1");
257+
get => Attributes.GetBoolean("IsHidden", false);
258258
set => SetAttributeValue("IsHidden", value ? "1" : "0");
259259
}
260260

@@ -266,7 +266,7 @@ public bool IsHidden {
266266
/// </summary>
267267
[AttributeSetter]
268268
public bool IsDisabled {
269-
get => Attributes.GetValue("IsDisabled", "0").Equals("1");
269+
get => Attributes.GetBoolean("IsDisabled", false);
270270
set => SetAttributeValue("IsDisabled", value ? "1" : "0");
271271
}
272272

@@ -336,29 +336,7 @@ public string Description {
336336
/// !string.IsNullOrWhiteSpace(value.ToString())
337337
/// </requires>
338338
public DateTime LastModified {
339-
get {
340-
341-
/*----------------------------------------------------------------------------------------------------------------------
342-
| Establish default value
343-
\---------------------------------------------------------------------------------------------------------------------*/
344-
var defaultValue = VersionHistory.Count > 0 ? VersionHistory.LastOrDefault() : DateTime.MinValue;
345-
346-
/*----------------------------------------------------------------------------------------------------------------------
347-
| Return converted string attribute value, if available
348-
\---------------------------------------------------------------------------------------------------------------------*/
349-
var lastModified = Attributes.GetValue("LastModified", defaultValue.ToString());
350-
351-
// Return converted DateTime
352-
if (DateTime.TryParse(lastModified, out var dateTimeValue)) {
353-
return dateTimeValue;
354-
}
355-
356-
/*----------------------------------------------------------------------------------------------------------------------
357-
| Otherwise, return default of minimum value
358-
\---------------------------------------------------------------------------------------------------------------------*/
359-
return defaultValue;
360-
361-
}
339+
get => Attributes.GetDateTime("LastModified", VersionHistory.DefaultIfEmpty(DateTime.MinValue).LastOrDefault());
362340
set => SetAttributeValue("LastModified", value.ToString());
363341
}
364342

0 commit comments

Comments
 (0)