Skip to content

Commit

Permalink
* explicitly setCultureInfo.InvariantCulture & `StringComparison.Or…
Browse files Browse the repository at this point in the history
…dinal` following https://www.meziantou.net/string-comparisons-are-harder-than-it-seems.htm

* enable `TreatWarningsAsErrors` @ Directory.Build.props
* sort `[SuppressMessage]` attributes @ GlobalSuppressions.cs
@ c#
  • Loading branch information
n0099 committed Mar 26, 2024
1 parent 10304cd commit c0378a7
Show file tree
Hide file tree
Showing 12 changed files with 57 additions and 57 deletions.
1 change: 1 addition & 0 deletions c#/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AnalysisMode>Recommended</AnalysisMode>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="$(MSBuildThisFileDirectory)\stylecop.json" />
Expand Down
65 changes: 29 additions & 36 deletions c#/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
@@ -1,59 +1,52 @@
// ReSharper disable once RedundantUsingDirective
using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("Major Code Smell", "S125:Sections of code should not be commented out")]
[assembly: SuppressMessage("Minor Code Smell", "S3604:Member initializer values should not be redundant")]
[assembly: SuppressMessage("Class Design", "AV1008:Class should not be static")]
[assembly: SuppressMessage("Class Design", "AV1010:Member hides inherited member")]
[assembly: SuppressMessage("Correctness", "SS019:Switch should have default label.")]
[assembly: SuppressMessage("Critical Bug", "S6674:Log message template should be syntactically correct")]
[assembly: SuppressMessage("Roslynator", "RCS1001:Add braces (when expression spans over multiple lines).")]
[assembly: SuppressMessage("Roslynator", "RCS1139:Add summary element to documentation comment.")]
[assembly: SuppressMessage("Roslynator", "RCS1156:Use string.Length instead of comparison with empty string.")]
[assembly: SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods")]
[assembly: SuppressMessage("Style", "CC0061:Asynchronous method can be terminated with the 'Async' keyword.")]
[assembly: SuppressMessage("Naming", "AV1755:Name of async method should end with Async or TaskAsync")]
[assembly: SuppressMessage("Naming", "AV1706:Identifier contains an abbreviation or is too short")]
[assembly: SuppressMessage("Maintainability", "AV1580:Method argument calls a nested method")]
[assembly: SuppressMessage("Maintainability", "AV1500:Member or local function contains too many statements")]
[assembly: SuppressMessage("Miscellaneous Design", "AV1210:Catch a specific exception instead of Exception, SystemException or ApplicationException")]
[assembly: SuppressMessage("Design", "CC0021:Use nameof")]
[assembly: SuppressMessage("Design", "CC0031:Check for null before calling a delegate")]
[assembly: SuppressMessage("Maintainability", "AV1561:Signature contains too many parameters")]
[assembly: SuppressMessage("Design", "MA0051:Method is too long")]
[assembly: SuppressMessage("Usage", "MA0004:Use Task.ConfigureAwait")]
[assembly: SuppressMessage("Design", "CC0091:Use static method", Justification = "https://github.com/code-cracker/code-cracker/issues/1087")]
[assembly: SuppressMessage("Design", "CC0120:Your Switch maybe include default clause")]
[assembly: SuppressMessage("Correctness", "SS019:Switch should have default label.")]
[assembly: SuppressMessage("Maintainability", "AV1555:Avoid using non-(nullable-)boolean named arguments")]
[assembly: SuppressMessage("Maintainability", "AV1535:Missing block in case or default clause of switch statement")]
[assembly: SuppressMessage("Maintainability", "CC0097:You have missing/unexistent parameters in Xml Docs")]
[assembly: SuppressMessage("Design", "MA0048:File name must match type name")]
[assembly: SuppressMessage("Design", "MA0051:Method is too long")]
[assembly: SuppressMessage("Documentation", "AV2305:Missing XML comment for internally visible type, member or parameter")]
[assembly: SuppressMessage("Framework", "AV2220:Simple query should be replaced by extension method call")]
[assembly: SuppressMessage("Maintainability", "AV1500:Member or local function contains too many statements")]
[assembly: SuppressMessage("Maintainability", "AV1507:File contains multiple types")]
[assembly: SuppressMessage("Style", "MA0007:Add a comma after the last value")]
[assembly: SuppressMessage("Style", "MA0003:Add parameter name to improve readability")]
[assembly: SuppressMessage("Design", "CC0021:Use nameof")]
[assembly: SuppressMessage("Naming", "AV1704:Identifier contains one or more digits in its name")]
[assembly: SuppressMessage("Usage", "MA0006:Use String.Equals instead of equality operator")]
[assembly: SuppressMessage("Maintainability", "AV1532:Loop statement contains nested loop")]
[assembly: SuppressMessage("Maintainability", "AV1535:Missing block in case or default clause of switch statement")]
[assembly: SuppressMessage("Maintainability", "AV1537:If-else-if construct should end with an unconditional else clause")]
[assembly: SuppressMessage("Maintainability", "AV1554:Method contains optional parameter in type hierarchy")]
[assembly: SuppressMessage("Maintainability", "AV1564:Parameter in public or internal member is of type bool or bool?")]
[assembly: SuppressMessage("Class Design", "AV1010:Member hides inherited member")]
[assembly: SuppressMessage("Maintainability", "AV1555:Avoid using non-(nullable-)boolean named arguments")]
[assembly: SuppressMessage("Maintainability", "AV1561:Signature contains too many parameters")]
[assembly: SuppressMessage("Maintainability", "AV1562:Do not declare a parameter as ref or out")]
[assembly: SuppressMessage("Maintainability", "AV1532:Loop statement contains nested loop")]
[assembly: SuppressMessage("Design", "CC0091:Use static method", Justification = "https://github.com/code-cracker/code-cracker/issues/1087")]
[assembly: SuppressMessage("Usage", "MA0015:Specify the parameter name in ArgumentException")]
[assembly: SuppressMessage("Class Design", "AV1008:Class should not be static")]
[assembly: SuppressMessage("Framework", "AV2220:Simple query should be replaced by extension method call")]
[assembly: SuppressMessage("Maintainability", "AV1564:Parameter in public or internal member is of type bool or bool?")]
[assembly: SuppressMessage("Maintainability", "AV1580:Method argument calls a nested method")]
[assembly: SuppressMessage("Maintainability", "CC0097:You have missing/unexistent parameters in Xml Docs")]
[assembly: SuppressMessage("Major Code Smell", "S125:Sections of code should not be commented out")]
[assembly: SuppressMessage("Minor Code Smell", "S3604:Member initializer values should not be redundant")]
[assembly: SuppressMessage("Miscellaneous Design", "AV1210:Catch a specific exception instead of Exception, SystemException or ApplicationException")]
[assembly: SuppressMessage("Naming", "AV1704:Identifier contains one or more digits in its name")]
[assembly: SuppressMessage("Naming", "AV1706:Identifier contains an abbreviation or is too short")]
[assembly: SuppressMessage("Naming", "AV1755:Name of async method should end with Async or TaskAsync")]
[assembly: SuppressMessage("Naming", "CA1711:Identifiers should not have incorrect suffix")]
[assembly: SuppressMessage("Naming", "CA1716:Identifiers should not match keywords")]
[assembly: SuppressMessage("Performance", "CA1848:Use the LoggerMessage delegates")]
[assembly: SuppressMessage("Roslynator", "RCS1001:Add braces (when expression spans over multiple lines).")]
[assembly: SuppressMessage("Roslynator", "RCS1139:Add summary element to documentation comment.")]
[assembly: SuppressMessage("Roslynator", "RCS1156:Use string.Length instead of comparison with empty string.")]
[assembly: SuppressMessage("Style", "CC0001:You should use 'var' whenever possible.")]
[assembly: SuppressMessage("Style", "CC0037:Remove commented code.")]
[assembly: SuppressMessage("Documentation", "AV2305:Missing XML comment for internally visible type, member or parameter")]
[assembly: SuppressMessage("Style", "CC0061:Asynchronous method can be terminated with the 'Async' keyword.")]
[assembly: SuppressMessage("Style", "MA0003:Add parameter name to improve readability")]
[assembly: SuppressMessage("Style", "MA0007:Add a comma after the last value")]
[assembly: SuppressMessage("Style", "VSTHRD200:Use \"Async\" suffix for async methods")]
[assembly: SuppressMessage("Usage", "CC0057:Unused parameters")]
[assembly: SuppressMessage("Usage", "MA0004:Use Task.ConfigureAwait")]
[assembly: SuppressMessage("Usage", "MA0006:Use String.Equals instead of equality operator")]
[assembly: SuppressMessage("Usage", "MA0015:Specify the parameter name in ArgumentException")]
[assembly: SuppressMessage("Performance", "CA1848:Use the LoggerMessage delegates")]
[assembly: SuppressMessage("Usage", "CC0057:Unused parameters")]
[assembly: SuppressMessage("Naming", "CA1711:Identifiers should not have incorrect suffix")]
[assembly: SuppressMessage("Naming", "CA1716:Identifiers should not match keywords")]

[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:Prefix local calls with this")]
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented")]
Expand Down
1 change: 1 addition & 0 deletions c#/crawler/src/GlobalUsings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
global using System.Data;
global using System.Diagnostics;
global using System.Diagnostics.CodeAnalysis;
global using System.Globalization;
global using System.Linq.Expressions;
global using System.Reflection;
global using System.Text.Json;
Expand Down
3 changes: 2 additions & 1 deletion c#/crawler/src/SonicPusher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public float PushPost(Fid fid, string type, PostId id, RepeatedField<Content>? c
try
{
foreach (var text in contentTexts.Chunk(30000)) // https://github.com/spikensbror-dotnet/nsonic/issues/11
Ingest.Push($"{CollectionPrefix}{type}_content", $"f{fid}", id.ToString(), text.ToString(), "cmn");
Ingest.Push($"{CollectionPrefix}{type}_content", $"f{fid}",
id.ToString(CultureInfo.InvariantCulture), text.ToString(), "cmn");
}
catch (Exception e)
{
Expand Down
3 changes: 2 additions & 1 deletion c#/crawler/src/Tieba/Crawl/CrawlerLocks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ protected override void LogTrace()
lock (_crawling)
lock (_failed)
{
logger.LogTrace("Lock: type={} crawlingIdCount={} crawlingPageCount={} crawlingPageCountsKeyById={} failedIdCount={} failedPageCount={} failures={}", LockType,
logger.LogTrace("Lock: type={} crawlingIdCount={} crawlingPageCount={} crawlingPageCountsKeyById={}"
+ " failedIdCount={} failedPageCount={} failures={}", LockType,
_crawling.Count, _crawling.Values.Sum(d => d.Count),
Helper.UnescapedJsonSerialize(_crawling.ToDictionary(pair => pair.Key.ToString(), pair => pair.Value.Count)),
_failed.Count, _failed.Values.Sum(d => d.Count),
Expand Down
6 changes: 3 additions & 3 deletions c#/crawler/src/Tieba/Crawl/ThreadLateCrawlerAndSaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private async Task<ThreadPost?> CrawlThread
var json = await requester.RequestJson(
$"{ClientRequester.LegacyClientApiDomain}/c/f/pb/page", "8.8.8.8", new()
{
{"kz", tid.ToString()},
{"kz", tid.ToString(CultureInfo.InvariantCulture)},
{"pn", "1"},

// rn have to be at least 2
Expand All @@ -60,7 +60,7 @@ private async Task<ThreadPost?> CrawlThread
},
JsonValueKind.String => () =>
{ // https://stackoverflow.com/questions/62100000/why-doesnt-system-text-json-jsonelement-have-trygetstring-or-trygetboolean/62100246#62100246
var r = int.TryParse(errorCodeProp.GetString(), out var p);
var r = int.TryParse(errorCodeProp.GetString(), CultureInfo.InvariantCulture, out var p);
return (p, r);
},
_ => () => (0, false)
Expand All @@ -85,7 +85,7 @@ private async Task<ThreadPost?> CrawlThread
? threadInfo.TryGetProperty("phone_type", out var phoneType)
? new ThreadPost
{
Tid = Tid.Parse(thread.GetStrProp("id")),
Tid = Tid.Parse(thread.GetStrProp("id"), CultureInfo.InvariantCulture),
AuthorPhoneType = phoneType.GetString().NullIfEmpty()
}
: throw new TiebaException(shouldRetry: false,
Expand Down
2 changes: 1 addition & 1 deletion c#/crawler/src/Tieba/Crawl/UserParserAndSaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void ParseUsers(IEnumerable<TbClient.User> users) =>
{
static (string Portrait, uint? UpdateTime) ExtractPortrait(string portrait) =>
ExtractPortraitRegex().Match(portrait) is {Success: true} m
? (m.Groups["portrait"].Value, Time.Parse(m.Groups["timestamp"].ValueSpan))
? (m.Groups["portrait"].Value, Time.Parse(m.Groups["timestamp"].ValueSpan, CultureInfo.InvariantCulture))
: (portrait, null);

var uid = el.Uid;
Expand Down
3 changes: 2 additions & 1 deletion c#/crawler/src/Worker/ArchiveCrawlWorker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ public class ArchiveCrawlWorker(
public static float GetCumulativeAverage(float currentCa, float previousCa, int currentIndex) =>
(currentCa + ((currentIndex - 1) * previousCa)) / currentIndex;

[SuppressMessage("Correctness", "SS002:DateTime.Now was referenced")]
public static (string Relative, string At) GetEta(int total, int completed, float averageDurationInMs)
{
var etaTimeSpan = TimeSpan.FromMilliseconds((total - completed) * averageDurationInMs);
return (etaTimeSpan.Humanize(precision: 5, minUnit: TimeUnit.Second),
DateTime.Now.Add(etaTimeSpan).ToString("MM-dd HH:mm:ss"));
DateTime.Now.Add(etaTimeSpan).ToString("MM-dd HH:mm:ss", CultureInfo.CurrentCulture));
}

protected override async Task DoWork(CancellationToken stoppingToken)
Expand Down
2 changes: 1 addition & 1 deletion c#/crawler/src/Worker/ForumModeratorRevisionCrawlWorker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ where e.IsCrawling
{
var type = typeEl.QuerySelector("div.title")?.Children
.Select(el => el.ClassList)
.First(classNames => classNames.Any(className => className.EndsWith("_icon")))
.First(classNames => classNames.Any(className => className.EndsWith("_icon", StringComparison.Ordinal)))
.Select(className => className.Split("_")[0])
.First(className => !string.IsNullOrWhiteSpace(className));
if (string.IsNullOrEmpty(type)) throw new TiebaException();
Expand Down
23 changes: 12 additions & 11 deletions c#/imagePipeline/src/Consumer/MetadataConsumer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Globalization;
using System.IO.Hashing;
using System.Text.RegularExpressions;
using NetTopologySuite.Geometries;
Expand Down Expand Up @@ -101,7 +100,7 @@ private Func<ImageWithBytes, ImageMetadata> GetImageMetaData
if (rawBytes == null || rawBytes.Length == 0) return null;
if (rawBytes.Length > 65535)
_logger.LogWarning("Embedded {} in image contains {} bytes",
typeof(TEmbeddedMetadata).Name.ToUpper(), rawBytes.Length);
typeof(TEmbeddedMetadata).Name.ToUpperInvariant(), rawBytes.Length);
var xxHash3 = XxHash3.HashToUInt64(rawBytes);
return new()
{
Expand Down Expand Up @@ -281,7 +280,7 @@ private static partial class ExifDateTimeTagValuesParser
// https://stackoverflow.com/questions/4483886/how-can-i-get-a-count-of-the-total-number-of-digits-in-a-number/51099524#51099524
[SuppressMessage("Major Code Smell", "S3358:Ternary operators should not be nested")]
static int CountDigits(int n) => n == 0 ? 1 : (n > 0 ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));
var hasFractionalSeconds = int.TryParse(exifFractionalSeconds, out var fractionalSeconds);
var hasFractionalSeconds = int.TryParse(exifFractionalSeconds, CultureInfo.InvariantCulture, out var fractionalSeconds);
fractionalSeconds = hasFractionalSeconds ? fractionalSeconds : 0;

if (exifDateTime == "00000" && fractionalSeconds == 0) return null;
Expand All @@ -290,7 +289,8 @@ private static partial class ExifDateTimeTagValuesParser
?? ParseWithOverflowedTimeParts(exifDateTime)
?? ParseAsUnixTimestamp(exifDateTime)
?? throw new ArgumentException(
$"Failed to parse provided EXIF date time \"{exifDateTime}\" with fractional seconds {fractionalSeconds}.");
$"Failed to parse provided EXIF date time \"{exifDateTime}\""
+ $" with fractional seconds {fractionalSeconds.ToString(CultureInfo.InvariantCulture)}.");
return fractionalSeconds == 0 ? ret : ret with
{
DateTime = ret.DateTime.AddSeconds(fractionalSeconds / Math.Pow(10, CountDigits(fractionalSeconds)))
Expand Down Expand Up @@ -333,7 +333,7 @@ private static partial class ExifDateTimeTagValuesParser
: default;
return dateTimeOffset == default
? null
: new(dateTimeOffset.DateTime, dateTimeOffset.ToString("zzz"));
: new(dateTimeOffset.DateTime, dateTimeOffset.ToString("zzz", CultureInfo.InvariantCulture));
}

[GeneratedRegex(
Expand All @@ -349,13 +349,14 @@ private static partial class ExifDateTimeTagValuesParser
ExtractExifDateTimePartsRegex().Match(exifDateTime) is not {Success: true} m
? null
: new(new DateTime(
int.Parse(m.Groups["year"].ValueSpan),
int.Parse(m.Groups["month"].ValueSpan),
int.Parse(m.Groups["day"].ValueSpan),
int.Parse(m.Groups["year"].ValueSpan, CultureInfo.InvariantCulture),
int.Parse(m.Groups["month"].ValueSpan, CultureInfo.InvariantCulture),
int.Parse(m.Groups["day"].ValueSpan, CultureInfo.InvariantCulture),
hour: 0, minute: 0, second: 0, DateTimeKind.Unspecified)
.AddHours(int.Parse(m.Groups["hour"].ValueSpan))
.AddMinutes(int.Parse(m.Groups["minute"].ValueSpan))
.AddSeconds(int.Parse(m.Groups["second"].ValueSpan)), Offset: null);
.AddHours(int.Parse(m.Groups["hour"].ValueSpan, CultureInfo.InvariantCulture))
.AddMinutes(int.Parse(m.Groups["minute"].ValueSpan, CultureInfo.InvariantCulture))
.AddSeconds(int.Parse(m.Groups["second"].ValueSpan, CultureInfo.InvariantCulture)),
Offset: null);

private static DateTimeAndOffset? ParseAsUnixTimestamp(string exifDateTime) =>
long.TryParse(exifDateTime, NumberStyles.Integer,
Expand Down
2 changes: 1 addition & 1 deletion c#/imagePipeline/src/Consumer/OcrConsumer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected override IEnumerable<ImageId> ConsumeInternal(
RotationDegrees = result.TextBox.Angle.RoundToUshort(),
Recognizer = result switch
{
PaddleOcrRecognitionResult r => "PaddleOCR" + Enum.GetName(r.ModelVersion)?.ToLower(),
PaddleOcrRecognitionResult r => "PaddleOCR" + Enum.GetName(r.ModelVersion)?.ToLowerInvariant(),
TesseractRecognitionResult {IsVertical: false} => "TesseractHorizontal",
TesseractRecognitionResult {IsVertical: true} => "TesseractVertical",
_ => throw new ArgumentOutOfRangeException(nameof(result), result, null)
Expand Down
3 changes: 2 additions & 1 deletion c#/imagePipeline/src/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma warning disable SA1210 // Using directives should be ordered alphabetically by namespace
global using System.ComponentModel.DataAnnotations;
global using System.Diagnostics.CodeAnalysis;
global using System.Globalization;
global using System.Linq.Expressions;
global using System.Text.Json;
global using System.Threading.Channels;
Expand All @@ -9,12 +10,12 @@
global using Autofac;
global using Autofac.Features.OwnedInstances;
global using CommunityToolkit.Diagnostics;
global using LanguageExt;
global using Microsoft.EntityFrameworkCore;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Logging;
global using OpenCvSharp;
global using LanguageExt;
global using Polly;
global using Polly.Extensions.Http;
global using Polly.Registry;
Expand Down

0 comments on commit c0378a7

Please sign in to comment.