diff --git a/.gitattributes b/.gitattributes
index f6c098b67..0c1426c52 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -3,10 +3,12 @@
# Declare files that will always have CRLF line endings on checkout.
*.txt text eol=crlf
+*.hl7 text eol=crlf
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
# Treat these files as text so we don;t get inconsistency with line endings between OS
-tests/NHapi.NUnit/TestData/BadInputs/**/* -text
\ No newline at end of file
+tests/NHapi.NUnit/TestData/BadInputs/**/* -text
+tests/NHapi.NUnit/TestData/Util/**/* -text
\ No newline at end of file
diff --git a/src/NHapi.Base/Parser/LegacyPipeParser.cs b/src/NHapi.Base/Parser/LegacyPipeParser.cs
index 6bc1bd870..e84820528 100644
--- a/src/NHapi.Base/Parser/LegacyPipeParser.cs
+++ b/src/NHapi.Base/Parser/LegacyPipeParser.cs
@@ -265,7 +265,7 @@ public override void Parse(IMessage message, string @string, ParserOptions parse
}
var messageIter = new Util.MessageIterator(message, "MSH", true);
- FilterIterator.IPredicate segmentsOnly = new AnonymousClassPredicate(this);
+ FilterIterator.IPredicate segmentsOnly = new IsSegmentPredicate(this);
var segmentIter = new FilterIterator(messageIter, segmentsOnly);
var segments = Split(@string, SegDelim);
@@ -299,7 +299,7 @@ public override void Parse(IMessage message, string @string, ParserOptions parse
Log.Debug("Parsing segment " + name);
messageIter.Direction = name;
- FilterIterator.IPredicate byDirection = new AnonymousClassPredicate1(name, this);
+ FilterIterator.IPredicate byDirection = new ByDirectionPredicate(name, this);
var dirIter = new FilterIterator(segmentIter, byDirection);
if (dirIter.MoveNext())
@@ -939,46 +939,46 @@ public MessageStructure(string theMessageStructure, bool isExplicitlyDefined)
public bool ExplicitlyDefined { get; }
}
- private class AnonymousClassPredicate : FilterIterator.IPredicate
+ private sealed class IsSegmentPredicate : FilterIterator.IPredicate
{
- public AnonymousClassPredicate(LegacyPipeParser enclosingInstance)
+ public IsSegmentPredicate(LegacyPipeParser enclosingInstance)
{
- Enclosing_Instance = enclosingInstance;
+ EnclosingInstance = enclosingInstance;
}
- public LegacyPipeParser Enclosing_Instance { get; }
+ public LegacyPipeParser EnclosingInstance { get; }
- public virtual bool evaluate(object obj)
+ public bool evaluate(object obj)
{
return Evaluate(obj);
}
- public virtual bool Evaluate(object obj)
+ public bool Evaluate(object obj)
{
- return typeof(ISegment).IsAssignableFrom(obj.GetType());
+ return obj is ISegment;
}
}
- private class AnonymousClassPredicate1 : FilterIterator.IPredicate
+ private sealed class ByDirectionPredicate : FilterIterator.IPredicate
{
- public AnonymousClassPredicate1(string name, LegacyPipeParser enclosingInstance)
+ public ByDirectionPredicate(string name, LegacyPipeParser enclosingInstance)
{
Name = name;
- Enclosing_Instance = enclosingInstance;
+ EnclosingInstance = enclosingInstance;
}
- public LegacyPipeParser Enclosing_Instance { get; }
+ public LegacyPipeParser EnclosingInstance { get; }
private string Name { get; }
///
- public virtual bool evaluate(object obj)
+ public bool evaluate(object obj)
{
return Evaluate(obj);
}
///
- public virtual bool Evaluate(object obj)
+ public bool Evaluate(object obj)
{
var structureName = ((IStructure)obj).GetStructureName();
Log.Debug($"LegacyPipeParser iterating message in direction {Name} at {structureName}");
diff --git a/src/NHapi.Base/Util/MessageNavigator.cs b/src/NHapi.Base/Util/MessageNavigator.cs
index 3231a34ee..afe115133 100644
--- a/src/NHapi.Base/Util/MessageNavigator.cs
+++ b/src/NHapi.Base/Util/MessageNavigator.cs
@@ -28,6 +28,7 @@ namespace NHapi.Base.Util
{
using System;
using System.Collections;
+ using System.Collections.Generic;
using NHapi.Base.Model;
@@ -48,7 +49,7 @@ namespace NHapi.Base.Util
///
public class MessageNavigator
{
- private ArrayList ancestors;
+ private Stack ancestors;
private int currentChild; // -1 means current structure is current group (special case used for root)
private string[] childNames;
@@ -112,16 +113,14 @@ public virtual void DrillDown(int childNumber, int rep)
if (childNumber != -1)
{
var s = CurrentGroup.GetStructure(childNames[childNumber], rep);
- if (!(s is IGroup))
+ if (s is not IGroup group)
{
throw new HL7Exception("Can't drill into segment", ErrorCode.APPLICATION_INTERNAL_ERROR);
}
- var group = (IGroup)s;
-
// stack the current group and location
var gc = new GroupContext(this, CurrentGroup, currentChild);
- ancestors.Add(gc);
+ ancestors.Push(gc);
CurrentGroup = group;
}
@@ -166,7 +165,7 @@ public virtual bool DrillUp()
// pop the top group and resume search there
if (ancestors.Count != 0)
{
- var gc = (GroupContext)SupportClass.StackSupport.Pop(ancestors);
+ var gc = ancestors.Pop();
CurrentGroup = gc.Group;
currentChild = gc.Child;
childNames = CurrentGroup.Names;
@@ -226,22 +225,23 @@ public virtual void NextChild()
"StyleCop.CSharp.NamingRules",
"SA1300:Element should begin with upper-case letter",
Justification = "As this is a public member, we will duplicate the method and mark this one as obsolete.")]
- public virtual void toChild(int child)
+ public virtual string toChild(int child)
{
- ToChild(child);
+ return ToChild(child);
}
/// Moves to the sibling of the current location at the specified index.
- public virtual void ToChild(int child)
+ public virtual string ToChild(int child)
{
if (child >= 0 && child < childNames.Length)
{
currentChild = child;
+ return this.childNames[child];
}
else
{
throw new HL7Exception(
- "Can't advance to child " + child + " -- only " + childNames.Length + " children",
+ $"Can't advance to child {child} -- only {childNames.Length} children",
ErrorCode.APPLICATION_INTERNAL_ERROR);
}
}
@@ -259,7 +259,7 @@ public virtual void reset()
/// Resets the location to the beginning of the tree (the root).
public virtual void Reset()
{
- ancestors = new ArrayList();
+ ancestors = new Stack();
CurrentGroup = Root;
currentChild = -1;
childNames = CurrentGroup.Names;
@@ -280,18 +280,13 @@ public virtual IStructure getCurrentStructure(int rep)
///
public virtual IStructure GetCurrentStructure(int rep)
{
- IStructure ret = null;
- if (currentChild != -1)
- {
- var childName = childNames[currentChild];
- ret = CurrentGroup.GetStructure(childName, rep);
- }
- else
+ if (currentChild == -1)
{
- ret = CurrentGroup;
+ return CurrentGroup;
}
- return ret;
+ var childName = childNames[currentChild];
+ return this.CurrentGroup.GetStructure(childName, rep);
}
[Obsolete("This method has been replaced by 'Iterate'.")]
@@ -315,36 +310,30 @@ public virtual void iterate(bool segmentsOnly, bool loop)
/// if true, loops back to beginning when end of msg reached; if false,
/// throws HL7Exception if end of msg reached.
///
- public virtual void Iterate(bool segmentsOnly, bool loop)
+ public virtual string Iterate(bool segmentsOnly, bool loop)
{
- IStructure start = null;
-
- if (currentChild == -1)
- {
- start = CurrentGroup;
- }
- else
- {
- start = CurrentGroup.GetStructure(childNames[currentChild]);
- }
+ var start = currentChild == -1
+ ? CurrentGroup
+ : CurrentGroup.GetStructure(childNames[currentChild]);
// using a non-existent direction and not allowing segment creation means that only
// the first rep of anything is traversed.
IEnumerator it = new MessageIterator(start, "doesn't exist", false);
if (segmentsOnly)
{
- FilterIterator.IPredicate predicate = new AnonymousClassPredicate(this);
+ FilterIterator.IPredicate predicate = new IsSegmentPredicate(this);
it = new FilterIterator(it, predicate);
}
if (it.MoveNext())
{
var next = (IStructure)it.Current;
- DrillHere(next);
+ return DrillHere(next);
}
else if (loop)
{
Reset();
+ return string.Empty;
}
else
{
@@ -355,19 +344,19 @@ public virtual void Iterate(bool segmentsOnly, bool loop)
}
/// Navigates to a specific location in the message.
- private void DrillHere(IStructure destination)
+ private string DrillHere(IStructure destination)
{
var pathElem = destination;
- var pathStack = new ArrayList();
- var indexStack = new ArrayList();
+ var pathStack = new Stack();
+ var indexStack = new Stack();
do
{
var index = MessageIterator.GetIndex(pathElem.ParentStructure, pathElem);
- indexStack.Add(index);
+ indexStack.Push(index);
pathElem = pathElem.ParentStructure;
- pathStack.Add(pathElem);
+ pathStack.Push(pathElem);
}
- while (!Root.Equals(pathElem) && !typeof(IMessage).IsAssignableFrom(pathElem.GetType()));
+ while (!Root.Equals(pathElem) && pathElem is not IMessage);
if (!Root.Equals(pathElem))
{
@@ -375,10 +364,11 @@ private void DrillHere(IStructure destination)
}
Reset();
+ string result = null;
while (pathStack.Count != 0)
{
- var parent = (IGroup)SupportClass.StackSupport.Pop(pathStack);
- var index = (MessageIterator.Index)SupportClass.StackSupport.Pop(indexStack);
+ var parent = (IGroup)pathStack.Pop();
+ var index = indexStack.Pop();
var child = Search(parent.Names, index.Name);
if (pathStack.Count != 0)
{
@@ -386,15 +376,17 @@ private void DrillHere(IStructure destination)
}
else
{
- ToChild(child);
+ result = ToChild(child);
}
}
+
+ return result;
}
/// Like Arrays.binarySearch, only probably slower and doesn't require
/// a sorted list. Also just returns -1 if item isn't found.
///
- private int Search(object[] list, object item)
+ private int Search(string[] list, object item)
{
var found = -1;
for (var i = 0; i < list.Length && found == -1; i++)
@@ -408,59 +400,43 @@ private int Search(object[] list, object item)
return found;
}
- /// Drills down recursively until a segment is reached.
- private void FindLeaf()
- {
- if (currentChild == -1)
- {
- currentChild = 0;
- }
-
- var c = CurrentGroup.GetClass(childNames[currentChild]);
- if (typeof(IGroup).IsAssignableFrom(c))
- {
- DrillDown(currentChild, 0);
- FindLeaf();
- }
- }
-
/// A structure to hold current location information at
/// one level of the message tree. A stack of these
/// identifies the current location completely.
///
private class GroupContext
{
- public GroupContext(MessageNavigator enclosingInstance, IGroup g, int c)
+ public GroupContext(MessageNavigator enclosingInstance, IGroup group, int child)
{
EnclosingInstance = enclosingInstance;
- Group = g;
- Child = c;
+ Group = group;
+ Child = child;
}
public MessageNavigator EnclosingInstance { get; }
- public IGroup Group { get; set; }
+ public IGroup Group { get; }
- public int Child { get; set; }
+ public int Child { get; }
}
- private class AnonymousClassPredicate : FilterIterator.IPredicate
+ private sealed class IsSegmentPredicate : FilterIterator.IPredicate
{
- public AnonymousClassPredicate(MessageNavigator enclosingInstance)
+ public IsSegmentPredicate(MessageNavigator enclosingInstance)
{
EnclosingInstance = enclosingInstance;
}
public MessageNavigator EnclosingInstance { get; }
- public virtual bool evaluate(object obj)
+ public bool evaluate(object obj)
{
return Evaluate(obj);
}
- public virtual bool Evaluate(object obj)
+ public bool Evaluate(object obj)
{
- return typeof(ISegment).IsAssignableFrom(obj.GetType());
+ return obj is ISegment;
}
}
}
diff --git a/src/NHapi.Base/Util/SegmentFinder.cs b/src/NHapi.Base/Util/SegmentFinder.cs
index e33c0cacd..e7b9bc299 100644
--- a/src/NHapi.Base/Util/SegmentFinder.cs
+++ b/src/NHapi.Base/Util/SegmentFinder.cs
@@ -36,6 +36,24 @@ namespace NHapi.Base.Util
///
public class SegmentFinder : MessageNavigator
{
+ [System.Diagnostics.CodeAnalysis.SuppressMessage(
+ "StyleCop.CSharp.NamingRules",
+ "SA1310:Field names should not contain underscore",
+ Justification = "Because these are constants and not just fields there is a rule clash.")]
+ private const string VALID_PATTERN = "[\\w\\*\\?]*";
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessage(
+ "StyleCop.CSharp.NamingRules",
+ "SA1310:Field names should not contain underscore",
+ Justification = "Because these are constants and not just fields there is a rule clash.")]
+ private const string LITERAL_UNBOUNDED = "\\*";
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessage(
+ "StyleCop.CSharp.NamingRules",
+ "SA1310:Field names should not contain underscore",
+ Justification = "Because these are constants and not just fields there is a rule clash.")]
+ private const string LITERAL_OPTIONAL = "\\?";
+
/// Creates a new instance of SegmentFinder.
/// the scope of searches -- may be a whole message or only a branch.
///
@@ -67,12 +85,12 @@ public virtual ISegment findSegment(string namePattern, int rep)
/// the repetition of the segment to return.
public virtual ISegment FindSegment(string namePattern, int rep)
{
- IStructure s = null;
+ IStructure s;
do
{
s = FindStructure(namePattern, rep);
}
- while (!typeof(ISegment).IsAssignableFrom(s.GetType()));
+ while (s is not ISegment);
return (ISegment)s;
}
@@ -90,12 +108,12 @@ public virtual IGroup findGroup(string namePattern, int rep)
/// As findSegment(), but will only return a group.
public virtual IGroup FindGroup(string namePattern, int rep)
{
- IStructure s = null;
+ IStructure s;
do
{
s = FindStructure(namePattern, rep);
}
- while (!typeof(IGroup).IsAssignableFrom(s.GetType()));
+ while (s is not IGroup);
return (IGroup)s;
}
@@ -126,12 +144,12 @@ public virtual ISegment getSegment(string namePattern, int rep)
public virtual ISegment GetSegment(string namePattern, int rep)
{
var s = GetStructure(namePattern, rep);
- if (!typeof(ISegment).IsAssignableFrom(s.GetType()))
+ if (s is not ISegment segment)
{
- throw new HL7Exception(s.GetStructureName() + " is not a segment", ErrorCode.APPLICATION_INTERNAL_ERROR);
+ throw new HL7Exception($"{s.GetStructureName()} is not a segment", ErrorCode.APPLICATION_INTERNAL_ERROR);
}
- return (ISegment)s;
+ return segment;
}
[Obsolete("This method has been replaced by 'GetGroup'.")]
@@ -148,12 +166,12 @@ public virtual IGroup getGroup(string namePattern, int rep)
public virtual IGroup GetGroup(string namePattern, int rep)
{
var s = GetStructure(namePattern, rep);
- if (!typeof(IGroup).IsAssignableFrom(s.GetType()))
+ if (s is not IGroup group)
{
- throw new HL7Exception(s.GetStructureName() + " is not a group", ErrorCode.APPLICATION_INTERNAL_ERROR);
+ throw new HL7Exception($"{s.GetStructureName()} is not a group", ErrorCode.APPLICATION_INTERNAL_ERROR);
}
- return (IGroup)s;
+ return group;
}
/// Returns the first matching structure AFTER the current position.
@@ -163,9 +181,9 @@ private IStructure FindStructure(string namePattern, int rep)
while (s == null)
{
- Iterate(false, false);
+ var currentNameInParent = Iterate(false, false);
var currentName = GetCurrentStructure(0).GetStructureName();
- if (Matches(namePattern, currentName))
+ if (Matches(namePattern, currentName) || Matches(namePattern, currentNameInParent))
{
s = GetCurrentStructure(rep);
}
@@ -195,7 +213,7 @@ private IStructure GetStructure(string namePattern, int rep)
if (s == null)
{
- throw new HL7Exception("Can't find " + namePattern + " as a direct child", ErrorCode.APPLICATION_INTERNAL_ERROR);
+ throw new HL7Exception($"Can't find {namePattern} as a direct child", ErrorCode.APPLICATION_INTERNAL_ERROR);
}
return s;
@@ -210,15 +228,15 @@ private bool Matches(string pattern, string candidate)
return true;
}
- if (!Regex.IsMatch(pattern, "[\\w\\*\\?]*"))
+ if (!Regex.IsMatch(pattern, VALID_PATTERN))
{
- throw new ArgumentException("The pattern " + pattern + " is not valid. Only [\\w\\*\\?]* allowed.");
+ throw new ArgumentException($"The pattern {pattern} is not valid. Only [\\w\\*\\?]* allowed.");
}
- pattern = Regex.Replace(pattern, "\\*", ".*");
- pattern = Regex.Replace(pattern, "\\?", ".");
+ pattern = Regex.Replace(pattern, LITERAL_UNBOUNDED, ".*");
+ pattern = Regex.Replace(pattern, LITERAL_OPTIONAL, ".");
- return Regex.IsMatch(candidate, pattern);
+ return Regex.IsMatch(candidate, $"^{pattern}$");
}
}
}
\ No newline at end of file
diff --git a/src/NHapi.Base/Util/Terser.cs b/src/NHapi.Base/Util/Terser.cs
index b8958aa78..6175cab9b 100644
--- a/src/NHapi.Base/Util/Terser.cs
+++ b/src/NHapi.Base/Util/Terser.cs
@@ -192,15 +192,14 @@ public static IPrimitive GetPrimitive(IType type, int component, int subcomponen
var comp = GetComponent(type, component);
- if (type is Varies && comp is GenericPrimitive && subcomponent > 1)
+ if (type is Varies varies && comp is GenericPrimitive && subcomponent > 1)
{
try
{
- var varies = (Varies)type;
var comp2 = new GenericComposite(type.Message);
varies.Data = comp2;
- comp = GetComponent(type, component);
+ comp = GetComponent(varies, component);
}
catch (DataTypeException ex)
{
@@ -237,10 +236,10 @@ public static int[] GetIndices(string spec)
tok.NextToken(); // skip over segment
if (!tok.HasMoreTokens())
{
- throw new HL7Exception("Must specify field in spec " + spec, ErrorCode.APPLICATION_INTERNAL_ERROR);
+ throw new HL7Exception($"Must specify field in spec {spec}", ErrorCode.APPLICATION_INTERNAL_ERROR);
}
- int[] ret = null;
+ int[] ret;
try
{
var fieldSpec = new SupportClass.Tokenizer(tok.NextToken(), "()", false);
@@ -263,12 +262,12 @@ public static int[] GetIndices(string spec)
subcomponent = int.Parse(tok.NextToken());
}
- var result = new int[] { fieldNum, fieldRep, component, subcomponent };
+ var result = new[] { fieldNum, fieldRep, component, subcomponent };
ret = result;
}
catch (FormatException)
{
- throw new HL7Exception("Invalid integer in spec " + spec, ErrorCode.APPLICATION_INTERNAL_ERROR);
+ throw new HL7Exception($"Invalid integer in spec {spec}", ErrorCode.APPLICATION_INTERNAL_ERROR);
}
return ret;
@@ -293,21 +292,21 @@ public static int numSubComponents(IType type, int component)
/// numbered from 1.
public static int NumSubComponents(IType type, int component)
{
- var n = -1;
- if (component == 1 && typeof(IPrimitive).IsAssignableFrom(type.GetType()))
+ int subComponentTotal;
+ if (component == 1 && type is IPrimitive)
{
// note that getComponent(primitive, 1) below returns the primitive
// itself -- if we do numComponents on it, we'll end up with the
// number of components in the field, not the number of subcomponents
- n = 1;
+ subComponentTotal = 1;
}
else
{
var comp = GetComponent(type, component);
- n = NumComponents(comp);
+ subComponentTotal = NumComponents(comp);
}
- return n;
+ return subComponentTotal;
}
[Obsolete("This method has been replaced by 'NumComponents'.")]
@@ -326,13 +325,16 @@ public static int numComponents(IType type)
///
public static int NumComponents(IType type)
{
- if (typeof(Varies).IsAssignableFrom(type.GetType()))
+ while (true)
{
- return NumComponents(((Varies)type).Data);
- }
- else
- {
- return NumStandardComponents(type) + type.ExtraComponents.NumComponents();
+ if (type is Varies varies)
+ {
+ type = varies.Data;
+ }
+ else
+ {
+ return NumStandardComponents(type) + type.ExtraComponents.NumComponents();
+ }
}
}
@@ -368,7 +370,7 @@ public virtual ISegment getSegment(string segSpec)
/// Returns the segment specified in the given segment_path_spec.
public virtual ISegment GetSegment(string segSpec)
{
- ISegment seg = null;
+ ISegment segment = null;
if (segSpec.Substring(0, 1 - 0).Equals("/"))
{
@@ -381,47 +383,29 @@ public virtual ISegment GetSegment(string segSpec)
{
var pathSpec = tok.NextToken();
var ps = ParsePathSpec(pathSpec);
- if (tok.HasMoreTokens())
- {
- ps.IsGroup = true;
- }
- else
- {
- ps.IsGroup = false;
- }
+ ps.IsGroup = tok.HasMoreTokens();
if (ps.IsGroup)
{
- IGroup g = null;
- if (ps.Find)
- {
- g = finder.FindGroup(ps.Pattern, ps.Rep);
- }
- else
- {
- g = finder.GetGroup(ps.Pattern, ps.Rep);
- }
+ var group = ps.Find
+ ? finder.FindGroup(ps.Pattern, ps.Rep)
+ : finder.GetGroup(ps.Pattern, ps.Rep);
- finder = new SegmentFinder(g);
+ finder = new SegmentFinder(group);
}
else
{
- if (ps.Find)
- {
- seg = finder.FindSegment(ps.Pattern, ps.Rep);
- }
- else
- {
- seg = finder.GetSegment(ps.Pattern, ps.Rep);
- }
+ segment = ps.Find
+ ? finder.FindSegment(ps.Pattern, ps.Rep)
+ : finder.GetSegment(ps.Pattern, ps.Rep);
}
}
- return seg;
+ return segment;
}
/// Sets the string value of the field specified. See class docs for location spec syntax.
- public virtual void Set(string spec, string value_Renamed)
+ public virtual void Set(string spec, string valueRenamed)
{
var tok = new SupportClass.Tokenizer(spec, "-", false);
var segment = GetSegment(tok.NextToken());
@@ -429,11 +413,10 @@ public virtual void Set(string spec, string value_Renamed)
var ind = GetIndices(spec);
if (log.DebugEnabled)
{
- log.Debug("Setting " + spec + " seg: " + segment.GetStructureName() + " ind: " + ind[0] + " " + ind[1] + " " +
- ind[2] + " " + ind[3]);
+ log.Debug($"Setting {spec} seg: {segment.GetStructureName()} ind: {ind[0]} {ind[1]} {ind[2]} {ind[3]}");
}
- Set(segment, ind[0], ind[1], ind[2], ind[3], value_Renamed);
+ Set(segment, ind[0], ind[1], ind[2], ind[3], valueRenamed);
}
///
@@ -451,24 +434,23 @@ private static IPrimitive GetPrimitive(ISegment segment, int field, int rep, int
///
private static IPrimitive GetPrimitive(IType type)
{
- if (type is IPrimitive)
+ switch (type)
{
- return (IPrimitive)type;
- }
+ case IPrimitive primitive:
+ return primitive;
+ case IComposite composite:
+ try
+ {
+ return GetPrimitive(composite[0]);
+ }
+ catch (HL7Exception e)
+ {
+ throw new ApplicationException("Internal error: HL7Exception thrown on Composite.getComponent(0).", e);
+ }
- if (type is IComposite)
- {
- try
- {
- return GetPrimitive(((IComposite)type)[0]);
- }
- catch (HL7Exception e)
- {
- throw new ApplicationException("Internal error: HL7Exception thrown on Composite.getComponent(0).", e);
- }
+ default:
+ return GetPrimitive(((Varies)type).Data);
}
-
- return GetPrimitive(((Varies)type).Data);
}
/// Returns the component (or sub-component, as the case may be) at the given
@@ -485,13 +467,13 @@ private static IType GetComponent(IType type, int comp)
return type;
}
- if (type is IComposite)
+ if (type is IComposite composite)
{
- if (comp <= NumStandardComponents(type) || type is GenericComposite)
+ if (comp <= NumStandardComponents(composite) || composite is GenericComposite)
{
try
{
- return ((IComposite)type)[comp - 1];
+ return composite[comp - 1];
}
catch (DataTypeException ex)
{
@@ -502,48 +484,39 @@ private static IType GetComponent(IType type, int comp)
}
}
- if (type is Varies)
+ if (type is Varies varies)
{
- var v = (Varies)type;
-
try
{
- if (comp > 1 && v.Data is GenericPrimitive)
+ if (comp > 1 && varies.Data is GenericPrimitive)
{
- v.Data = new GenericComposite(v.Message);
+ varies.Data = new GenericComposite(varies.Message);
}
}
catch (DataTypeException de)
{
- var message = "Unexpected exception copying data to generic composite: " + de.Message;
+ var message = $"Unexpected exception copying data to generic composite: {de.Message}";
log.Error(message, de);
throw new ApplicationException(message);
}
- return GetComponent(v.Data, comp);
+ return GetComponent(varies.Data, comp);
}
return type.ExtraComponents.getComponent(comp - NumStandardComponents(type) - 1);
}
- private static int NumStandardComponents(IType t)
+ private static int NumStandardComponents(IType type)
{
- var n = 0;
- if (typeof(Varies).IsAssignableFrom(t.GetType()))
- {
- n = NumStandardComponents(((Varies)t).Data);
- }
- else if (typeof(IComposite).IsAssignableFrom(t.GetType()))
+ var length = type switch
{
- n = ((IComposite)t).Components.Length;
- }
- else
- {
- n = 1;
- }
+ Varies varies => NumStandardComponents(varies.Data),
+ IComposite composite => composite.Components.Length,
+ _ => 1
+ };
- return n;
+ return length;
}
/// Gets path information from a path spec.
@@ -577,7 +550,7 @@ private PathSpec ParsePathSpec(string spec)
}
catch (FormatException)
{
- throw new HL7Exception(repString + " is not a valid rep #", ErrorCode.APPLICATION_INTERNAL_ERROR);
+ throw new HL7Exception($"{repString} is not a valid rep #", ErrorCode.APPLICATION_INTERNAL_ERROR);
}
}
else
diff --git a/tests/NHapi.NUnit/NHapi.NUnit.csproj b/tests/NHapi.NUnit/NHapi.NUnit.csproj
index ea4bf4ebe..972e751f1 100644
--- a/tests/NHapi.NUnit/NHapi.NUnit.csproj
+++ b/tests/NHapi.NUnit/NHapi.NUnit.csproj
@@ -25,6 +25,9 @@
PreserveNewest
+
+ PreserveNewest
+
diff --git a/tests/NHapi.NUnit/TestData/Util/segmentfinder_a24.hl7 b/tests/NHapi.NUnit/TestData/Util/segmentfinder_a24.hl7
new file mode 100644
index 000000000..ab1c38870
--- /dev/null
+++ b/tests/NHapi.NUnit/TestData/Util/segmentfinder_a24.hl7
@@ -0,0 +1,4 @@
+MSH^~|\&^SENDING^200M^RECEIVING^200^20120918173931-0500^^ADT~A24^2003582144^T^2.4^^^AL^AL^
+EVN^A24^20120918173931-0500
+PID^1^^11111~~~FOO&&0363~NI~FACILITY ID&200M&L^^SMITH~JOHN~TEST
+PID^2^^22222~~~FOO&&0363~NI~FACILITY ID&200M&L^^SMITH~JOHN~TEST
diff --git a/tests/NHapi.NUnit/Util/MessageNavigatorTests.cs b/tests/NHapi.NUnit/Util/MessageNavigatorTests.cs
new file mode 100644
index 000000000..88184f3d4
--- /dev/null
+++ b/tests/NHapi.NUnit/Util/MessageNavigatorTests.cs
@@ -0,0 +1,86 @@
+namespace NHapi.NUnit.Util
+{
+ using global::NUnit.Framework;
+
+ using NHapi.Base.Util;
+ using NHapi.Model.V24.Message;
+ using NHapi.Model.V24.Segment;
+
+ [TestFixture]
+ public class MessageNavigatorTests
+ {
+ [Test]
+ public void TestNavigate()
+ {
+ // Arrange
+ var message = new ADT_A01();
+ message.GetINSURANCE().IN1.CoverageType.Value = "a";
+ message.MSH.CountryCode.Value = "b";
+ message.PD1.Handicap.Value = "c";
+
+ var sut = new MessageNavigator(message);
+
+ // Act
+ sut.DrillDown(16, 0);
+ var in1 = (IN1)sut.GetCurrentStructure(0);
+
+ sut.Reset();
+ sut.NextChild();
+ var msh = (MSH)sut.GetCurrentStructure(0);
+
+ sut.Reset();
+ sut.NextChild();
+ sut.NextChild();
+ sut.NextChild();
+ sut.NextChild();
+ var pd1 = (PD1)sut.GetCurrentStructure(0);
+
+ // Assert
+ Assert.AreEqual("a", in1.CoverageType.Value);
+ Assert.AreEqual("b", msh.CountryCode.Value);
+ Assert.AreEqual("a", in1.CoverageType.Value);
+ Assert.AreEqual("c", pd1.Handicap.Value);
+ }
+
+ [Test]
+ public void TestIterator()
+ {
+ // Arrange
+ var message = new ADT_A01();
+ message.GetINSURANCE().IN1.CoverageType.Value = "a";
+ message.MSH.CountryCode.Value = "b";
+ message.PD1.Handicap.Value = "c";
+
+ var sut = new MessageNavigator(message);
+
+ // Act
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ sut.Iterate(true, false);
+ var in1 = (IN1)sut.GetCurrentStructure(0);
+
+ sut.Reset();
+ sut.ToChild(3);
+ var pd1 = (PD1)sut.GetCurrentStructure(0);
+
+ // Assert
+ Assert.AreEqual("a", in1.CoverageType.Value);
+ Assert.AreEqual("c", pd1.Handicap.Value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/NHapi.NUnit/Util/SegmentFinderTests.cs b/tests/NHapi.NUnit/Util/SegmentFinderTests.cs
new file mode 100644
index 000000000..afaa4d0ed
--- /dev/null
+++ b/tests/NHapi.NUnit/Util/SegmentFinderTests.cs
@@ -0,0 +1,147 @@
+namespace NHapi.NUnit.Util
+{
+ using System.IO;
+
+ using global::NUnit.Framework;
+
+ using NHapi.Base.Model;
+ using NHapi.Base.Parser;
+ using NHapi.Base.Util;
+ using NHapi.Model.V24.Message;
+ using NHapi.Model.V26.Group;
+ using NHapi.Model.V26.Segment;
+
+ using ORU_R01 = NHapi.Model.V26.Message.ORU_R01;
+ using ROL = NHapi.Model.V24.Segment.ROL;
+
+ [TestFixture]
+ public class SegmentFinderTests
+ {
+ [Test]
+ public void FindSegment_ReturnsExpectedValue()
+ {
+ // Arrange
+ var message = new ADT_A01();
+ message.GetROL().ActionCode.Value = "a";
+ message.GetROL2().ActionCode.Value = "b";
+ message.GetPROCEDURE().GetROL().ActionCode.Value = "c";
+ message.GetINSURANCE().GetROL().ActionCode.Value = "d";
+
+ var finder = new SegmentFinder(message);
+
+ // Act
+ var first = ((ROL)finder.FindSegment("ROL", 0)).ActionCode.Value;
+ var second = ((ROL)finder.FindSegment("ROL", 0)).ActionCode.Value;
+ var third = ((ROL)finder.FindSegment("ROL", 0)).ActionCode.Value;
+ var fourth = ((ROL)finder.FindSegment("ROL", 0)).ActionCode.Value;
+
+ // Assert
+ Assert.AreEqual("a", first);
+ Assert.AreEqual("b", second);
+ Assert.AreEqual("c", third);
+ Assert.AreEqual("d", fourth);
+ }
+
+ [Test]
+ public void GetSegment_ReturnExpectedValue()
+ {
+ // Arrange
+ var r01 = new ORU_R01();
+ r01.MSH.MessageType.MessageStructure.Value = "ORU";
+ r01.MSH.MessageType.TriggerEvent.Value = "R01";
+ r01.MSH.FieldSeparator.Value = "|";
+ r01.MSH.EncodingCharacters.Value = @"^~\&";
+ r01.MSH.VersionID.VersionID.Value = "2.4";
+ r01.MSH.ProcessingID.ProcessingID.Value = "T";
+
+ r01.GetSFT(0).SoftwareVendorOrganization.OrganizationName.Value = "A";
+ r01.GetSFT(1).SoftwareVendorOrganization.OrganizationName.Value = "B";
+ r01.GetSFT(2).SoftwareVendorOrganization.OrganizationName.Value = "C";
+
+ var encodingCharacters = EncodingCharacters.FromMessage(r01);
+
+ var finder = new SegmentFinder(r01);
+
+ // Act
+ var sft1 = (SFT)finder.GetSegment("SFT", 0);
+ var sft2 = (SFT)finder.GetSegment("SFT", 1);
+ var sft3 = (SFT)finder.GetSegment("SFT", 2);
+
+ // Assert
+ Assert.AreEqual("A", PipeParser.Encode(sft1.SoftwareVendorOrganization, encodingCharacters));
+ Assert.AreEqual("B", PipeParser.Encode(sft2.SoftwareVendorOrganization, encodingCharacters));
+ Assert.AreEqual("C", PipeParser.Encode(sft3.SoftwareVendorOrganization, encodingCharacters));
+ }
+
+ [Test]
+ public void FindGroup_ReturnsExpectedValue()
+ {
+ // Arrange
+ var r01 = new ORU_R01();
+ r01.MSH.MessageType.MessageStructure.Value = "ORU";
+ r01.MSH.MessageType.TriggerEvent.Value = "R01";
+ r01.MSH.FieldSeparator.Value = "|";
+ r01.MSH.EncodingCharacters.Value = @"^~\&";
+ r01.MSH.VersionID.VersionID.Value = "2.4";
+ r01.MSH.ProcessingID.ProcessingID.Value = "T";
+
+ r01.GetPATIENT_RESULT().PATIENT.PID.SetIDPID.Value = "1";
+ r01.GetPATIENT_RESULT().GetORDER_OBSERVATION(0).OBR.SetIDOBR.Value = "2";
+ r01.GetPATIENT_RESULT().GetORDER_OBSERVATION(1).OBR.SetIDOBR.Value = "3";
+ r01.GetPATIENT_RESULT().GetORDER_OBSERVATION(2).OBR.SetIDOBR.Value = "4";
+
+ var encodingCharacters = EncodingCharacters.FromMessage(r01);
+
+ var finder = new SegmentFinder(r01);
+
+ // Act
+ var pid = (PID)finder.FindSegment("PID", 0);
+ finder = new SegmentFinder(r01);
+ var patient = (ORU_R01_PATIENT)finder.FindGroup("PATIENT", 0);
+
+ var orderObservation = (ORU_R01_ORDER_OBSERVATION)finder.FindGroup("ORDER_OBSERVATION", 0);
+
+ // Assert
+ Assert.AreEqual("1", PipeParser.Encode(pid.SetIDPID, encodingCharacters));
+ Assert.AreEqual("1", PipeParser.Encode(patient.PID.SetIDPID, encodingCharacters));
+
+ Assert.AreEqual("2", PipeParser.Encode(orderObservation.OBR.SetIDOBR, encodingCharacters));
+ }
+
+ [Test]
+ public void TestPID1()
+ {
+ // Arrange
+ var message = LoadMessage();
+ var finder = new SegmentFinder(message);
+
+ // Act
+ var segment = finder.FindSegment("PID", 0);
+
+ // Assert
+ Assert.AreEqual("1", ((IPrimitive)segment.GetField(1, 0)).Value);
+ }
+
+ [Test]
+ public void TestPID2()
+ {
+ // Arrange
+ var message = LoadMessage();
+ var finder = new SegmentFinder(message);
+
+ // Act
+ var segment = finder.FindSegment("PID2", 0);
+
+ // Assert
+ Assert.AreEqual("2", ((IPrimitive)segment.GetField(1, 0)).Value);
+ }
+
+ private static IMessage LoadMessage()
+ {
+ var parser = new PipeParser();
+ var testDataDir = $"{TestContext.CurrentContext.TestDirectory}/TestData/Util/";
+ var messageString = File.ReadAllText($"{testDataDir}/segmentfinder_a24.hl7");
+ return parser.Parse(messageString);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/NHapi.NUnit/Util/TerserTests.cs b/tests/NHapi.NUnit/Util/TerserTests.cs
index 385d64da8..df91c902e 100644
--- a/tests/NHapi.NUnit/Util/TerserTests.cs
+++ b/tests/NHapi.NUnit/Util/TerserTests.cs
@@ -224,6 +224,31 @@ public void TestPatientId()
Assert.AreEqual(expected, terser.Get("/QUERY_RESPONSE(0)/.PID-3-1"));
}
+ ///
+ /// https://github.com/nHapiNET/nHapi/issues/319
+ ///
+ [Test]
+ public void Get_OMD_O03_ValidTerserPathSpecifaction_ReturnsExpectedResult()
+ {
+ var parser = new PipeParser();
+
+ var omdText = "MSH|^~\\&|EDITE|TEST|TEST|TEST|20210519141200||OMD^O03^OMD_O03|202105191412001|P|2.5|||||FRA|8859/1\r" +
+ "PID|1|465 306 5961||407623|Wood^Patrick^^^MR||19700101|1|||High Street^^Oxford^^Ox1 4DP~George St ^^Oxford^^Ox1 5AP|||||||\r" +
+ "ORC|NW|1254481^EDITEUR|||||^^^20210519143000||20210519143000|611014333^PRESCRIPTEUR^TEST1^^^^^^EDITEUR^^^^ADELI~10002129790^PRESCRIPTEUR^TEST1 ^^^^^^EDITEUR ^^^^RPPS~1027^PRESCRIPTEUR^TEST1^^^^^^EDITEUR^^^^EI||||||||||||||||||||\r" +
+ "TQ1|1||||||20210519143000|\r" +
+ "ODS|R||SANSSEL^Sans sel^EDITEUR|";
+
+ var parsed = parser.Parse(omdText);
+
+ var terser = new Terser(parsed);
+
+ var tq17 = terser.Get("/.ORDER_DIET(0)/TIMING_DIET/TQ1-7");
+ var ods1 = terser.Get("/.ORDER_DIET(0)/DIET/ODS(0)-1");
+
+ Assert.AreEqual("20210519143000", tq17);
+ Assert.AreEqual("R", ods1);
+ }
+
#region Static Methods
[Test]
@@ -296,4 +321,4 @@ public void TestMultiArg()
#endregion
}
-}
+}
\ No newline at end of file