From 167c61d2f748aac812ed7d66d2d19b698d143fa8 Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Sun, 26 Mar 2023 17:10:34 +0200 Subject: [PATCH 1/5] Use ordinal string operations Enables CA1310 at error severity --- .editorconfig | 4 ++++ QuickFIXn.sln | 1 + QuickFIXn/DefaultMessageFactory.cs | 2 +- .../Fields/Converters/DateTimeConverter.cs | 6 +++--- QuickFIXn/Message/Message.cs | 4 ++-- QuickFIXn/Session.cs | 20 +++++++++---------- QuickFIXn/SessionFactory.cs | 2 +- QuickFIXn/SessionID.cs | 2 +- QuickFIXn/Transport/StreamFactory.cs | 2 +- UnitTests/DataDictionaryTests.cs | 2 +- UnitTests/ThreadedSocketReactorTests.cs | 2 +- 11 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..07b1ceeb6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# CA1310: Specify StringComparison for correctness +dotnet_diagnostic.CA1310.severity = error diff --git a/QuickFIXn.sln b/QuickFIXn.sln index df35f468d..a7bb35ac6 100644 --- a/QuickFIXn.sln +++ b/QuickFIXn.sln @@ -19,6 +19,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Examples.TradeClient", "Exa EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FD384F84-3F83-4BF9-9238-82C70B74C2EA}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig appveyor.yml = appveyor.yml CONTRIBUTING.md = CONTRIBUTING.md LICENSE = LICENSE diff --git a/QuickFIXn/DefaultMessageFactory.cs b/QuickFIXn/DefaultMessageFactory.cs index a85bb256a..7bf628389 100644 --- a/QuickFIXn/DefaultMessageFactory.cs +++ b/QuickFIXn/DefaultMessageFactory.cs @@ -178,7 +178,7 @@ private static ICollection GetAppDomainAssemblies() var assemblies = AppDomain .CurrentDomain .GetAssemblies() - .Where(assembly => !assembly.IsDynamic && assembly.GetName().Name.StartsWith("QuickFix")) + .Where(assembly => !assembly.IsDynamic && assembly.GetName().Name.StartsWith("QuickFix", StringComparison.Ordinal)) .ToList(); return assemblies; } diff --git a/QuickFIXn/Fields/Converters/DateTimeConverter.cs b/QuickFIXn/Fields/Converters/DateTimeConverter.cs index 59a151e04..cf504f3f1 100644 --- a/QuickFIXn/Fields/Converters/DateTimeConverter.cs +++ b/QuickFIXn/Fields/Converters/DateTimeConverter.cs @@ -61,16 +61,16 @@ private static System.DateTime ConvertFromNanoString(string str, string[] format System.DateTimeKind kind; int offset = 0; - if (dec.EndsWith("Z")) + if (dec.EndsWith('Z')) { // UTC dec = dec.Substring(0, dec.Length - 1); kind = System.DateTimeKind.Utc; } - else if (dec.Contains("+") || dec.Contains("-")) + else if (dec.Contains('+') || dec.Contains('-')) { // GMT offset - int n = dec.Contains("+") ? dec.IndexOf('+') : dec.IndexOf('-'); + int n = dec.Contains('+') ? dec.IndexOf('+') : dec.IndexOf('-'); kind = System.DateTimeKind.Unspecified; offset = int.Parse(dec.Substring(n)); dec = dec.Substring(0, n); diff --git a/QuickFIXn/Message/Message.cs b/QuickFIXn/Message/Message.cs index 4cbb04e39..1c6f528a5 100644 --- a/QuickFIXn/Message/Message.cs +++ b/QuickFIXn/Message/Message.cs @@ -121,7 +121,7 @@ public Message(Message src) public static bool IsAdminMsgType(string msgType) { - return msgType.Length == 1 && "0A12345n".IndexOf(msgType) != -1; + return msgType.Length == 1 && "0A12345n".IndexOf(msgType[0]) != -1; } /// @@ -682,7 +682,7 @@ public void ReverseRoute(Header header) this.Header.RemoveField(Tags.OnBehalfOfLocationID); this.Header.RemoveField(Tags.DeliverToLocationID); - if (StringUtil.InvariantCompareTo(beginString, FixValues.BeginString.FIX41) >= 0) + if (string.CompareOrdinal(beginString, "FIX.4.1") >= 0) { if (header.IsSetField(Tags.OnBehalfOfLocationID)) { diff --git a/QuickFIXn/Session.cs b/QuickFIXn/Session.cs index 5ac632289..86d9f2bed 100755 --- a/QuickFIXn/Session.cs +++ b/QuickFIXn/Session.cs @@ -651,7 +651,7 @@ internal void Next(MessageBuilder msgBuilder) catch (FieldNotFoundException e) { Log.OnEvent("Rejecting invalid message, field not found: " + e.Message); - if (StringUtil.InvariantCompareTo(SessionID.BeginString, FixValues.BeginString.FIX42) >= 0 && (message.IsApp())) + if ((string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX42) >= 0) && (message.IsApp())) { GenerateBusinessMessageReject(message, Fields.BusinessRejectReason.CONDITIONALLY_REQUIRED_FIELD_MISSING, e.Field); } @@ -1045,7 +1045,7 @@ private void initializeResendFields(Message message) protected bool ShouldSendReset() { - return (StringUtil.InvariantCompareTo(this.SessionID.BeginString, FixValues.BeginString.FIX41) >= 0) + return (string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX41) >= 0) && (this.ResetOnLogon || this.ResetOnLogout || this.ResetOnDisconnect) && (_state.NextSenderMsgSeqNum == 1) && (_state.NextTargetMsgSeqNum == 1); @@ -1149,7 +1149,7 @@ protected void GenerateBusinessMessageReject(Message message, int err, int field SeqNumType msgSeqNum = message.Header.GetULong(Tags.MsgSeqNum); string reason = FixValues.BusinessRejectReason.RejText[err]; Message reject; - if (StringUtil.InvariantCompareTo(this.SessionID.BeginString, FixValues.BeginString.FIX42) >= 0) + if (string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX42) >= 0) { reject = _msgFactory.Create(this.SessionID.BeginString, MsgType.BUSINESS_MESSAGE_REJECT); reject.SetField(new RefMsgType(msgType)); @@ -1203,9 +1203,9 @@ protected void GenerateResendRequest(string beginString, SeqNumType msgSeqNum) } else { - if (StringUtil.InvariantCompareTo(beginString, FixValues.BeginString.FIX42) >= 0) + if (string.CompareOrdinal(beginString, FixValues.BeginString.FIX42) >= 0) endRangeSeqNum = 0; - else if (StringUtil.InvariantCompareTo(beginString, FixValues.BeginString.FIX41) <= 0) + else if (string.CompareOrdinal(beginString, FixValues.BeginString.FIX41) <= 0) endRangeSeqNum = 999999; endChunkSeqNum = endRangeSeqNum; } @@ -1392,11 +1392,11 @@ public void GenerateReject(Message message, FixValues.SessionRejectReason reason { } } - if (StringUtil.InvariantCompareTo(beginString, FixValues.BeginString.FIX42) >= 0) + if (string.CompareOrdinal(beginString, FixValues.BeginString.FIX42) >= 0) { if (msgType.Length > 0) reject.SetField(new Fields.RefMsgType(msgType)); - if ((FixValues.BeginString.FIX42.Equals(beginString) && reason.Value <= FixValues.SessionRejectReason.INVALID_MSGTYPE.Value) || StringUtil.InvariantCompareTo(beginString, FixValues.BeginString.FIX42) > 0) + if ((FixValues.BeginString.FIX42.Equals(beginString) && reason.Value <= FixValues.SessionRejectReason.INVALID_MSGTYPE.Value) || (string.CompareOrdinal(beginString, FixValues.BeginString.FIX42) > 0)) { reject.SetField(new Fields.SessionRejectReason(reason.Value)); } @@ -1412,7 +1412,7 @@ public void GenerateReject(Message message, FixValues.SessionRejectReason reason { if (FixValues.SessionRejectReason.INVALID_MSGTYPE.Equals(reason)) { - if (StringUtil.InvariantCompareTo(this.SessionID.BeginString, FixValues.BeginString.FIX43) >= 0) + if (string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX43) >= 0) PopulateRejectReason(reject, reason.Description); else PopulateSessionRejectReason(reject, field, reason.Description, false); @@ -1436,7 +1436,7 @@ public void GenerateReject(Message message, FixValues.SessionRejectReason reason protected void PopulateSessionRejectReason(Message reject, int field, string text, bool includeFieldInfo) { - if (StringUtil.InvariantCompareTo(this.SessionID.BeginString, FixValues.BeginString.FIX42) >= 0) + if (string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX42) >= 0) { reject.SetField(new Fields.RefTagID(field)); reject.SetField(new Fields.Text(text)); @@ -1494,7 +1494,7 @@ protected void InitializeHeader(Message m) private bool IsFix42OrAbove() { return this.SessionID.BeginString == FixValues.BeginString.FIXT11 - || StringUtil.InvariantCompareTo(this.SessionID.BeginString, FixValues.BeginString.FIX42) >= 0; + || string.CompareOrdinal(SessionID.BeginString, FixValues.BeginString.FIX42) >= 0; } protected void InsertSendingTime(FieldMap header) diff --git a/QuickFIXn/SessionFactory.cs b/QuickFIXn/SessionFactory.cs index c5c66a509..7349684ec 100755 --- a/QuickFIXn/SessionFactory.cs +++ b/QuickFIXn/SessionFactory.cs @@ -206,7 +206,7 @@ protected void ProcessFixTDataDictionaries(SessionID sessionID, Dictionary setti } else { - int offset = setting.Key.IndexOf("."); + int offset = setting.Key.IndexOf('.'); if (offset == -1) throw new System.ArgumentException(string.Format("Malformed {0} : {1}", SessionSettings.APP_DATA_DICTIONARY, setting.Key)); diff --git a/QuickFIXn/SessionID.cs b/QuickFIXn/SessionID.cs index e3e816f36..cef7203c0 100755 --- a/QuickFIXn/SessionID.cs +++ b/QuickFIXn/SessionID.cs @@ -103,7 +103,7 @@ public SessionID(string beginString, string senderCompID, string senderSubID, st targetSubID_ = targetSubID; targetLocationID_ = targetLocationID; sessionQualifier_ = sessionQualifier; - isFIXT_ = beginString_.StartsWith("FIXT"); + isFIXT_ = beginString_.StartsWith("FIXT", StringComparison.Ordinal); id_ = beginString_ + ":" diff --git a/QuickFIXn/Transport/StreamFactory.cs b/QuickFIXn/Transport/StreamFactory.cs index 39a79e7b5..a420ed585 100644 --- a/QuickFIXn/Transport/StreamFactory.cs +++ b/QuickFIXn/Transport/StreamFactory.cs @@ -54,7 +54,7 @@ private static Socket CreateTunnelThruProxy(string destIP, int destPort) int msg = socketThruProxy.Receive(buffer12, 500, 0); string data; data = Encoding.ASCII.GetString(buffer12); - int index = data.IndexOf("200"); + int index = data.IndexOf("200", StringComparison.Ordinal); if (index < 0) throw new ApplicationException( diff --git a/UnitTests/DataDictionaryTests.cs b/UnitTests/DataDictionaryTests.cs index b346d32d6..63b8d394b 100644 --- a/UnitTests/DataDictionaryTests.cs +++ b/UnitTests/DataDictionaryTests.cs @@ -707,7 +707,7 @@ public void ParseThroughComments() XmlNode MakeNode(string xmlString) { XmlDocument doc = new XmlDocument(); - if (xmlString.StartsWith("<")) + if (xmlString.StartsWith("<", StringComparison.Ordinal)) { doc.LoadXml(xmlString); return doc.DocumentElement; diff --git a/UnitTests/ThreadedSocketReactorTests.cs b/UnitTests/ThreadedSocketReactorTests.cs index 336e81928..1fc357a2e 100644 --- a/UnitTests/ThreadedSocketReactorTests.cs +++ b/UnitTests/ThreadedSocketReactorTests.cs @@ -66,7 +66,7 @@ public void TestStartOnBusyPort() Assert.IsNotNull(stdOutResult); Assert.AreEqual(typeof(SocketException), exceptionResult.GetType()); - Assert.IsTrue(stdOutResult.StartsWith("Error starting listener: ")); + Assert.IsTrue(stdOutResult.StartsWith("Error starting listener: ", StringComparison.Ordinal)); } [TearDown] From 66f97749208f1ac7cfdc4103674e1ed79b0a91f6 Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Fri, 7 Apr 2023 12:24:36 +0200 Subject: [PATCH 2/5] Fix CA1310 in tests Also use Contains instead of IndexOf --- QuickFIXn/Message/Message.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QuickFIXn/Message/Message.cs b/QuickFIXn/Message/Message.cs index 1c6f528a5..218fe983b 100644 --- a/QuickFIXn/Message/Message.cs +++ b/QuickFIXn/Message/Message.cs @@ -121,7 +121,7 @@ public Message(Message src) public static bool IsAdminMsgType(string msgType) { - return msgType.Length == 1 && "0A12345n".IndexOf(msgType[0]) != -1; + return msgType.Length == 1 && "0A12345n".Contains(msgType[0]); } /// From 7ed7ffc592be05df242b6929949ba048607a416f Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Thu, 21 Dec 2023 16:49:22 +0100 Subject: [PATCH 3/5] Move the .editorconfig down into the source and revert test changes It is unnecessary to have in the tests. --- .editorconfig => QuickFIXn/.editorconfig | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .editorconfig => QuickFIXn/.editorconfig (100%) diff --git a/.editorconfig b/QuickFIXn/.editorconfig similarity index 100% rename from .editorconfig rename to QuickFIXn/.editorconfig From bcaaad95eb5507ed066737493f79b34893cbb473 Mon Sep 17 00:00:00 2001 From: Grant Birchmeier Date: Fri, 19 Jan 2024 17:03:14 -0600 Subject: [PATCH 4/5] delete unused InvariantCompareTo() & usings --- QuickFIXn/Fields/Converters/DateTimeConverter.cs | 1 - QuickFIXn/Message/Message.cs | 1 - QuickFIXn/Session.cs | 1 - QuickFIXn/Util/StringUtil.cs | 5 +---- UnitTests/Util/UtcDateTimeSerializerTests.cs | 3 --- 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/QuickFIXn/Fields/Converters/DateTimeConverter.cs b/QuickFIXn/Fields/Converters/DateTimeConverter.cs index cf504f3f1..cb0b70ee6 100644 --- a/QuickFIXn/Fields/Converters/DateTimeConverter.cs +++ b/QuickFIXn/Fields/Converters/DateTimeConverter.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Text; using System.Globalization; namespace QuickFix.Fields.Converters diff --git a/QuickFIXn/Message/Message.cs b/QuickFIXn/Message/Message.cs index 218fe983b..ed6ac8e3c 100644 --- a/QuickFIXn/Message/Message.cs +++ b/QuickFIXn/Message/Message.cs @@ -4,7 +4,6 @@ using System.Text.RegularExpressions; using System.Text.Json; using System.Collections.Generic; -using QuickFix.Util; namespace QuickFix { diff --git a/QuickFIXn/Session.cs b/QuickFIXn/Session.cs index 86d9f2bed..bb32efb12 100755 --- a/QuickFIXn/Session.cs +++ b/QuickFIXn/Session.cs @@ -3,7 +3,6 @@ using System.Threading; using QuickFix.Fields; using QuickFix.Fields.Converters; -using QuickFix.Util; namespace QuickFix { diff --git a/QuickFIXn/Util/StringUtil.cs b/QuickFIXn/Util/StringUtil.cs index 525458462..89b40b743 100644 --- a/QuickFIXn/Util/StringUtil.cs +++ b/QuickFIXn/Util/StringUtil.cs @@ -11,9 +11,6 @@ public static string FixSlashes(string s) { ? s.Replace('/', '\\') : s.Replace('\\', '/'); } - - public static int InvariantCompareTo(string strA, string strB) { - return string.Compare(strA, strB, StringComparison.InvariantCulture); - } } } + diff --git a/UnitTests/Util/UtcDateTimeSerializerTests.cs b/UnitTests/Util/UtcDateTimeSerializerTests.cs index c50ccef71..a86b78ebc 100644 --- a/UnitTests/Util/UtcDateTimeSerializerTests.cs +++ b/UnitTests/Util/UtcDateTimeSerializerTests.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using NUnit.Framework; using QuickFix.Util; From a5ae6e6011a704c35f854f2ec4fe436e4b6e3ed3 Mon Sep 17 00:00:00 2001 From: Grant Birchmeier Date: Fri, 19 Jan 2024 17:17:59 -0600 Subject: [PATCH 5/5] release notes for #766 --- RELEASE_NOTES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 369c50403..a0c740c1d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -12,7 +12,7 @@ What's New ### NEXT RELEASE -**Breaking change** +**Breaking changes** * #768 - span-ify parser (Rob-Hague) - makes a change to QuickFix.Parser interface, which isn't likely to affect users * #820 - cleanup/nullable-ize files (gbirchmeier) - changed some Session Generate* functions to return void instead of null. Very low likelihood that any user code will be affected. @@ -25,6 +25,7 @@ What's New * #813 - fix incorrect logging of acceptor heartbeat (gbirchmeier) * #815 - update broken/neglected example apps & docs (gbirchmeier) * #764 - fix positive UTC offset parsing in DateTimeConverter (Rob-Hague) +* #766 - use ordinal string operations (Rob-Hague) ### v1.11.2: * same as v1.11.1, but I fixed the readme in the pushed nuget packages