diff --git a/.editorconfig b/.editorconfig
index 78b36ca..c6ab75a 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1 +1,8 @@
root = true
+
+[*.cs]
+# CSharpier expects adds trailing comma, prevent editor from cleaning it up
+trailing_comma_in_multiline_lists = true
+
+[tests/**/*.cs]
+dotnet_diagnostic.CA2007.severity = none
\ No newline at end of file
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 2647b55..3fe4a53 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -5,6 +5,7 @@
+
@@ -17,6 +18,7 @@
+
diff --git a/src/Usenet/Exceptions/InvalidNzbDataException.cs b/src/Usenet/Exceptions/InvalidNzbDataException.cs
index 453eb23..522de8e 100644
--- a/src/Usenet/Exceptions/InvalidNzbDataException.cs
+++ b/src/Usenet/Exceptions/InvalidNzbDataException.cs
@@ -1,7 +1,10 @@
-namespace Usenet.Exceptions;
+using JetBrains.Annotations;
+
+namespace Usenet.Exceptions;
///
/// The exception that is thrown when a data stream or text is not in a valid nzb format.
+[PublicAPI]
public class InvalidNzbDataException : Exception
{
///
diff --git a/src/Usenet/Exceptions/InvalidYencDataException.cs b/src/Usenet/Exceptions/InvalidYencDataException.cs
index 01ad4ac..0bc3cc3 100644
--- a/src/Usenet/Exceptions/InvalidYencDataException.cs
+++ b/src/Usenet/Exceptions/InvalidYencDataException.cs
@@ -1,7 +1,10 @@
-namespace Usenet.Exceptions;
+using JetBrains.Annotations;
+
+namespace Usenet.Exceptions;
///
/// The exception that is thrown when a data stream or text is not in a valid yEnc format.
+[PublicAPI]
public class InvalidYencDataException : Exception
{
///
diff --git a/src/Usenet/Exceptions/NntpException.cs b/src/Usenet/Exceptions/NntpException.cs
index ff941d4..625ed12 100644
--- a/src/Usenet/Exceptions/NntpException.cs
+++ b/src/Usenet/Exceptions/NntpException.cs
@@ -1,7 +1,10 @@
-namespace Usenet.Exceptions;
+using JetBrains.Annotations;
+
+namespace Usenet.Exceptions;
///
/// The exception that is thrown when communicating using the Network News Transfer Protocol.
+[PublicAPI]
public class NntpException : Exception
{
///
diff --git a/src/Usenet/Logger.cs b/src/Usenet/Logger.cs
index 21980a3..4c6c0d0 100644
--- a/src/Usenet/Logger.cs
+++ b/src/Usenet/Logger.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.Logging;
+using JetBrains.Annotations;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Usenet;
@@ -7,6 +8,7 @@ namespace Usenet;
/// Host for a singleton
/// (Source).
///
+[PublicAPI]
public static class Logger
{
///
diff --git a/src/Usenet/Nntp/Builders/NntpArticleBuilder.cs b/src/Usenet/Nntp/Builders/NntpArticleBuilder.cs
index 72621b0..e6014a9 100644
--- a/src/Usenet/Nntp/Builders/NntpArticleBuilder.cs
+++ b/src/Usenet/Nntp/Builders/NntpArticleBuilder.cs
@@ -1,4 +1,5 @@
using System.Globalization;
+using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Usenet.Exceptions;
using Usenet.Extensions;
@@ -10,6 +11,7 @@ namespace Usenet.Nntp.Builders;
///
/// Represents a mutable .
///
+[PublicAPI]
public class NntpArticleBuilder
{
private readonly ILogger _log = Logger.Create();
@@ -48,7 +50,7 @@ public NntpArticleBuilder InitializeFrom(NntpArticle article)
{
Guard.ThrowIfNull(article);
- _messageId = new(article.MessageId.Value);
+ _messageId = new NntpMessageId(article.MessageId.Value);
_groupsBuilder = new NntpGroupsBuilder().Add(article.Groups);
_headers = [];
_from = string.Empty;
@@ -326,13 +328,13 @@ public NntpArticle Build()
_headers.Add(NntpHeaders.From, _from);
_headers.Add(NntpHeaders.Subject, _subject);
- if (_dateTime.HasValue)
- {
- var formattedDate = _dateTime
- .Value.ToUniversalTime()
- .ToString(DateFormat, CultureInfo.InvariantCulture);
- _headers.Add(NntpHeaders.Date, $"{formattedDate} +0000");
- }
+ if (!_dateTime.HasValue)
+ return new NntpArticle(0, _messageId, groups, _headers, _body);
+
+ var formattedDate = _dateTime
+ .Value.ToUniversalTime()
+ .ToString(DateFormat, CultureInfo.InvariantCulture);
+ _headers.Add(NntpHeaders.Date, $"{formattedDate} +0000");
return new NntpArticle(0, _messageId, groups, _headers, _body);
}
diff --git a/src/Usenet/Nntp/Builders/NntpGroupsBuilder.cs b/src/Usenet/Nntp/Builders/NntpGroupsBuilder.cs
index d55437d..4c14e38 100644
--- a/src/Usenet/Nntp/Builders/NntpGroupsBuilder.cs
+++ b/src/Usenet/Nntp/Builders/NntpGroupsBuilder.cs
@@ -1,4 +1,5 @@
-using Usenet.Nntp.Models;
+using JetBrains.Annotations;
+using Usenet.Nntp.Models;
using Usenet.Nntp.Parsers;
using Usenet.Util;
@@ -7,6 +8,7 @@ namespace Usenet.Nntp.Builders;
///
/// Represents a mutable .
///
+[PublicAPI]
public class NntpGroupsBuilder
{
private readonly List _groups = [];
@@ -82,11 +84,6 @@ public NntpGroupsBuilder Remove(IEnumerable values)
private void AddGroups(IEnumerable values)
{
- if (values == null)
- {
- return;
- }
-
foreach (var group in values)
{
if (!_groups.Contains(group))
@@ -98,11 +95,6 @@ private void AddGroups(IEnumerable values)
private void RemoveGroups(IEnumerable values)
{
- if (values == null)
- {
- return;
- }
-
foreach (var group in values)
{
_groups.RemoveAll(g => g == group);
diff --git a/src/Usenet/Nntp/Contracts/INntpClient.cs b/src/Usenet/Nntp/Contracts/INntpClient.cs
index b121e3d..8f0922f 100644
--- a/src/Usenet/Nntp/Contracts/INntpClient.cs
+++ b/src/Usenet/Nntp/Contracts/INntpClient.cs
@@ -1,5 +1,8 @@
+using JetBrains.Annotations;
+
namespace Usenet.Nntp.Contracts;
+[PublicAPI]
public interface INntpClient
: INntpClientRfc2980,
INntpClientRfc3977,
diff --git a/src/Usenet/Nntp/Contracts/INntpClientCompression.cs b/src/Usenet/Nntp/Contracts/INntpClientCompression.cs
index 0a3d08a..bf13eab 100644
--- a/src/Usenet/Nntp/Contracts/INntpClientCompression.cs
+++ b/src/Usenet/Nntp/Contracts/INntpClientCompression.cs
@@ -1,8 +1,10 @@
+using JetBrains.Annotations;
using Usenet.Nntp.Models;
using Usenet.Nntp.Responses;
namespace Usenet.Nntp.Contracts;
+[PublicAPI]
public interface INntpClientCompression
{
///
diff --git a/src/Usenet/Nntp/Contracts/INntpClientConnection.cs b/src/Usenet/Nntp/Contracts/INntpClientConnection.cs
index f6b7b91..de60cab 100644
--- a/src/Usenet/Nntp/Contracts/INntpClientConnection.cs
+++ b/src/Usenet/Nntp/Contracts/INntpClientConnection.cs
@@ -1,7 +1,9 @@
+using JetBrains.Annotations;
using Usenet.Nntp.Responses;
namespace Usenet.Nntp.Contracts;
+[PublicAPI]
public interface INntpClientConnection
{
///
diff --git a/src/Usenet/Nntp/Contracts/INntpClientPool.cs b/src/Usenet/Nntp/Contracts/INntpClientPool.cs
index 350cbd3..d562c44 100644
--- a/src/Usenet/Nntp/Contracts/INntpClientPool.cs
+++ b/src/Usenet/Nntp/Contracts/INntpClientPool.cs
@@ -1,8 +1,11 @@
+using JetBrains.Annotations;
+
namespace Usenet.Nntp.Contracts;
///
/// Represents a pool of authenticated NNTP clients.
///
+[PublicAPI]
public interface INntpClientPool : IDisposable
{
///
diff --git a/src/Usenet/Nntp/Contracts/INntpClientRfc2980.cs b/src/Usenet/Nntp/Contracts/INntpClientRfc2980.cs
index 61d3442..e32e159 100644
--- a/src/Usenet/Nntp/Contracts/INntpClientRfc2980.cs
+++ b/src/Usenet/Nntp/Contracts/INntpClientRfc2980.cs
@@ -1,8 +1,10 @@
+using JetBrains.Annotations;
using Usenet.Nntp.Models;
using Usenet.Nntp.Responses;
namespace Usenet.Nntp.Contracts;
+[PublicAPI]
public interface INntpClientRfc2980
{
///
diff --git a/src/Usenet/Nntp/Contracts/INntpClientRfc3977.cs b/src/Usenet/Nntp/Contracts/INntpClientRfc3977.cs
index a098f83..bfb4674 100644
--- a/src/Usenet/Nntp/Contracts/INntpClientRfc3977.cs
+++ b/src/Usenet/Nntp/Contracts/INntpClientRfc3977.cs
@@ -1,10 +1,12 @@
using System.Diagnostics.CodeAnalysis;
+using JetBrains.Annotations;
using Usenet.Nntp.Models;
using Usenet.Nntp.Responses;
namespace Usenet.Nntp.Contracts;
[SuppressMessage("Naming", "CA1716:Identifiers should not match keywords")]
+[PublicAPI]
public interface INntpClientRfc3977
{
///
diff --git a/src/Usenet/Nntp/Contracts/INntpClientRfc4643.cs b/src/Usenet/Nntp/Contracts/INntpClientRfc4643.cs
index 03a8e76..e2daa3f 100644
--- a/src/Usenet/Nntp/Contracts/INntpClientRfc4643.cs
+++ b/src/Usenet/Nntp/Contracts/INntpClientRfc4643.cs
@@ -1,5 +1,8 @@
+using JetBrains.Annotations;
+
namespace Usenet.Nntp.Contracts;
+[PublicAPI]
public interface INntpClientRfc4643
{
///
diff --git a/src/Usenet/Nntp/Contracts/INntpClientRfc6048.cs b/src/Usenet/Nntp/Contracts/INntpClientRfc6048.cs
index 82535dd..995ab78 100644
--- a/src/Usenet/Nntp/Contracts/INntpClientRfc6048.cs
+++ b/src/Usenet/Nntp/Contracts/INntpClientRfc6048.cs
@@ -1,7 +1,9 @@
+using JetBrains.Annotations;
using Usenet.Nntp.Responses;
namespace Usenet.Nntp.Contracts;
+[PublicAPI]
public interface INntpClientRfc6048
{
///
diff --git a/src/Usenet/Nntp/Contracts/INntpConnection.cs b/src/Usenet/Nntp/Contracts/INntpConnection.cs
index 304bf1f..91e860d 100644
--- a/src/Usenet/Nntp/Contracts/INntpConnection.cs
+++ b/src/Usenet/Nntp/Contracts/INntpConnection.cs
@@ -1,3 +1,4 @@
+using JetBrains.Annotations;
using Usenet.Nntp.Parsers;
using Usenet.Util;
@@ -7,6 +8,7 @@ namespace Usenet.Nntp.Contracts;
/// Represents an NNTP connection.
/// Based on Kristian Hellang's NntpLib.Net project https://github.com/khellang/NntpLib.Net.
///
+[PublicAPI]
public interface INntpConnection : IDisposable
{
///
diff --git a/src/Usenet/Nntp/Contracts/IPooledNntpClient.cs b/src/Usenet/Nntp/Contracts/IPooledNntpClient.cs
index 9e03061..591954b 100644
--- a/src/Usenet/Nntp/Contracts/IPooledNntpClient.cs
+++ b/src/Usenet/Nntp/Contracts/IPooledNntpClient.cs
@@ -1,8 +1,11 @@
+using JetBrains.Annotations;
+
namespace Usenet.Nntp.Contracts;
///
/// An NNTP client for which connections and authentication are managed by a pool.
///
+[PublicAPI]
public interface IPooledNntpClient
: INntpClientRfc2980,
INntpClientRfc3977,
diff --git a/src/Usenet/Nntp/Contracts/IPooledNntpClientLease.cs b/src/Usenet/Nntp/Contracts/IPooledNntpClientLease.cs
index d20901d..58b5354 100644
--- a/src/Usenet/Nntp/Contracts/IPooledNntpClientLease.cs
+++ b/src/Usenet/Nntp/Contracts/IPooledNntpClientLease.cs
@@ -1,5 +1,8 @@
+using JetBrains.Annotations;
+
namespace Usenet.Nntp.Contracts;
+[PublicAPI]
public interface IPooledNntpClientLease : IDisposable
{
public IPooledNntpClient Client { get; }
diff --git a/src/Usenet/Nntp/Models/NntpArticle.cs b/src/Usenet/Nntp/Models/NntpArticle.cs
index 14980e5..75da9a5 100644
--- a/src/Usenet/Nntp/Models/NntpArticle.cs
+++ b/src/Usenet/Nntp/Models/NntpArticle.cs
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
+using JetBrains.Annotations;
using Usenet.Util;
using HashCode = Usenet.Util.HashCode;
@@ -7,6 +8,7 @@ namespace Usenet.Nntp.Models;
///
/// Represents an NNTP article.
///
+[PublicAPI]
public class NntpArticle : IEquatable
{
///
@@ -42,25 +44,23 @@ public class NntpArticle : IEquatable
/// The NNTP newsgroups this is posted in.
/// The headers of the .
/// The body of the .
- public NntpArticle(
+ internal NntpArticle(
long number,
- NntpMessageId? messageId,
- NntpGroups? groups,
- IDictionary>? headers,
- IList? body
+ NntpMessageId messageId,
+ NntpGroups groups,
+ IDictionary> headers,
+ IList body
)
{
Number = number;
- MessageId = messageId ?? NntpMessageId.Empty;
- Groups = groups ?? NntpGroups.Empty;
- Headers = (
- headers ?? MultiValueDictionary.EmptyIgnoreCase
- ).ToImmutableDictionary(
+ MessageId = messageId;
+ Groups = groups;
+ Headers = headers.ToImmutableDictionary(
x => x.Key,
x => x.Value.ToImmutableList(),
keyComparer: StringComparer.OrdinalIgnoreCase
);
- Body = (body ?? []).ToImmutableList();
+ Body = body.ToImmutableList();
}
///
diff --git a/src/Usenet/Nntp/Models/NntpArticleRange.cs b/src/Usenet/Nntp/Models/NntpArticleRange.cs
index 95b7230..d78534a 100644
--- a/src/Usenet/Nntp/Models/NntpArticleRange.cs
+++ b/src/Usenet/Nntp/Models/NntpArticleRange.cs
@@ -1,4 +1,5 @@
using System.Globalization;
+using JetBrains.Annotations;
using Usenet.Util;
using HashCode = Usenet.Util.HashCode;
@@ -12,6 +13,7 @@ namespace Usenet.Nntp.Models;
/// XPAT and
/// XROVER commands.
///
+[PublicAPI]
public class NntpArticleRange : IEquatable
{
///
@@ -29,7 +31,7 @@ public class NntpArticleRange : IEquatable
///
/// The article number to start the range from.
/// The optional article number to end the range with.
- public NntpArticleRange(long from, long? to)
+ private NntpArticleRange(long from, long? to)
{
From = from;
To = to;
@@ -47,7 +49,7 @@ public NntpArticleRange(long from, long? to)
///
/// The article number to start the range from.
/// A new range containing the given article and all following.
- public static NntpArticleRange AllFollowing(long from) => new(@from, null);
+ public static NntpArticleRange AllFollowing(long from) => new(from, null);
///
/// Creates a range containing all articles between and including and .
@@ -55,20 +57,16 @@ public NntpArticleRange(long from, long? to)
/// The article number to start the range from.
/// The article number to end the range with.
/// A new range containg all articles between and including and .
- public static NntpArticleRange Range(long from, long to) => new(@from, to);
+ public static NntpArticleRange Range(long from, long to) => new(from, to);
///
/// Returns the text representation of the value formatted according to the NNTP specifications.
///
/// The text representation of the value formatted according to the NNTP specifications
public override string ToString() =>
- To == null
- ? $"{From}-"
- : (
- To.Value == From
- ? From.ToString(CultureInfo.InvariantCulture)
- : $"{From}-{To.Value}"
- );
+ To == null ? $"{From}-"
+ : To.Value == From ? From.ToString(CultureInfo.InvariantCulture)
+ : $"{From}-{To.Value}";
///
/// Returns the hash code for this instance.
diff --git a/src/Usenet/Nntp/Models/NntpDateTime.cs b/src/Usenet/Nntp/Models/NntpDateTime.cs
index da646e1..d05a4b1 100644
--- a/src/Usenet/Nntp/Models/NntpDateTime.cs
+++ b/src/Usenet/Nntp/Models/NntpDateTime.cs
@@ -1,3 +1,4 @@
+using JetBrains.Annotations;
using Usenet.Util;
namespace Usenet.Nntp.Models;
@@ -5,6 +6,7 @@ namespace Usenet.Nntp.Models;
///
/// Represents an NNTP datetime object.
///
+[PublicAPI]
public class NntpDateTime : IEquatable
{
///
diff --git a/src/Usenet/Nntp/Models/NntpGroup.cs b/src/Usenet/Nntp/Models/NntpGroup.cs
index 45a72db..31685d8 100644
--- a/src/Usenet/Nntp/Models/NntpGroup.cs
+++ b/src/Usenet/Nntp/Models/NntpGroup.cs
@@ -1,4 +1,6 @@
using System.Collections.Immutable;
+using System.Text.Json.Serialization;
+using JetBrains.Annotations;
using Usenet.Util;
using Usenet.Util.Compatibility;
using HashCode = Usenet.Util.HashCode;
@@ -8,6 +10,7 @@ namespace Usenet.Nntp.Models;
///
/// Represents an NNTP newsgroup.
///
+[PublicAPI]
public class NntpGroup : IEquatable
{
///
@@ -57,7 +60,8 @@ public class NntpGroup : IEquatable
/// The name of the other under which the articles are filed when the
/// is .
/// A list of numbers in the .
- public NntpGroup(
+ [JsonConstructor]
+ internal NntpGroup(
string name,
long articleCount,
long lowWaterMark,
@@ -67,15 +71,15 @@ public NntpGroup(
IImmutableList articleNumbers
)
{
- Name = name ?? string.Empty;
+ Name = name;
ArticleCount = articleCount;
LowWaterMark = lowWaterMark;
HighWaterMark = highWaterMark;
PostingStatus = EnumShim.IsDefined(postingStatus)
? postingStatus
: NntpPostingStatus.Unknown;
- OtherGroup = otherGroup ?? string.Empty;
- ArticleNumbers = (articleNumbers ?? []).OrderBy(n => n).ToImmutableList();
+ OtherGroup = otherGroup;
+ ArticleNumbers = articleNumbers.OrderBy(n => n).ToImmutableList();
}
///
diff --git a/src/Usenet/Nntp/Models/NntpGroupOrigin.cs b/src/Usenet/Nntp/Models/NntpGroupOrigin.cs
index 000d20a..d601cd7 100644
--- a/src/Usenet/Nntp/Models/NntpGroupOrigin.cs
+++ b/src/Usenet/Nntp/Models/NntpGroupOrigin.cs
@@ -1,3 +1,4 @@
+using JetBrains.Annotations;
using Usenet.Util;
using HashCode = Usenet.Util.HashCode;
@@ -9,6 +10,7 @@ namespace Usenet.Nntp.Models;
/// LIST ACTIVE.TIMES command.
/// (Some older information).
///
+[PublicAPI]
public class NntpGroupOrigin : IEquatable
{
///
@@ -34,11 +36,11 @@ public class NntpGroupOrigin : IEquatable
/// The date and time the was created.
/// A description of the entity that created the ;
/// it is often a mailbox as described in RFC 2822.
- public NntpGroupOrigin(string name, DateTimeOffset createdAt, string createdBy)
+ internal NntpGroupOrigin(string name, DateTimeOffset createdAt, string createdBy)
{
- Name = name ?? string.Empty;
+ Name = name;
CreatedAt = createdAt;
- CreatedBy = createdBy ?? string.Empty;
+ CreatedBy = createdBy;
}
///
diff --git a/src/Usenet/Nntp/Models/NntpGroups.cs b/src/Usenet/Nntp/Models/NntpGroups.cs
index f10b741..01a2e98 100644
--- a/src/Usenet/Nntp/Models/NntpGroups.cs
+++ b/src/Usenet/Nntp/Models/NntpGroups.cs
@@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Immutable;
+using JetBrains.Annotations;
using Usenet.Nntp.Builders;
using Usenet.Nntp.Parsers;
using Usenet.Util;
@@ -10,6 +11,7 @@ namespace Usenet.Nntp.Models;
///
/// Represent a list of NNTP newsgroups.
///
+[PublicAPI]
public class NntpGroups : IEnumerable, IEquatable
{
///
@@ -22,7 +24,7 @@ public class NntpGroups : IEnumerable, IEquatable
///
/// Creates a new object.
///
- public NntpGroups(string groups)
+ internal NntpGroups(string groups)
{
Guard.ThrowIfNull(groups);
_groups = GroupsParser.Parse(groups).OrderBy(g => g).ToImmutableList();
@@ -31,7 +33,7 @@ public NntpGroups(string groups)
///
/// Creates a new object.
///
- public NntpGroups(IEnumerable groups)
+ internal NntpGroups(IEnumerable groups)
{
Guard.ThrowIfNull(groups);
_groups = GroupsParser.Parse(groups).OrderBy(g => g).ToImmutableList();
diff --git a/src/Usenet/Nntp/Models/NntpMessageId.cs b/src/Usenet/Nntp/Models/NntpMessageId.cs
index e69f2ea..5705ad4 100644
--- a/src/Usenet/Nntp/Models/NntpMessageId.cs
+++ b/src/Usenet/Nntp/Models/NntpMessageId.cs
@@ -1,3 +1,4 @@
+using JetBrains.Annotations;
using Usenet.Extensions;
using Usenet.Util;
@@ -7,6 +8,7 @@ namespace Usenet.Nntp.Models;
/// Represents an NNTP Message-ID.
/// (More information).
///
+[PublicAPI]
public class NntpMessageId : IEquatable
{
///
diff --git a/src/Usenet/Nntp/Models/NntpPostingStatus.cs b/src/Usenet/Nntp/Models/NntpPostingStatus.cs
index 845ae9f..2fac9ec 100644
--- a/src/Usenet/Nntp/Models/NntpPostingStatus.cs
+++ b/src/Usenet/Nntp/Models/NntpPostingStatus.cs
@@ -1,10 +1,13 @@
-namespace Usenet.Nntp.Models;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp.Models;
///
/// Represents the status a can have on the server. Can be retrieved with
/// the LIST ACTIVE command.
/// (More information).
///
+[PublicAPI]
public enum NntpPostingStatus
{
///
diff --git a/src/Usenet/Nntp/NntpClient.cs b/src/Usenet/Nntp/NntpClient.cs
index 55c3739..35eadbf 100644
--- a/src/Usenet/Nntp/NntpClient.cs
+++ b/src/Usenet/Nntp/NntpClient.cs
@@ -1,3 +1,4 @@
+using JetBrains.Annotations;
using Usenet.Extensions;
using Usenet.Nntp.Contracts;
using Usenet.Nntp.Models;
@@ -16,10 +17,10 @@ namespace Usenet.Nntp;
/// RFC 6048.
/// Based on Kristian Hellang's NntpLib.Net project https://github.com/khellang/NntpLib.Net.
///
+[PublicAPI]
public partial class NntpClient : INntpClient
{
- private readonly INntpConnection _connection;
- protected INntpConnection Connection => _connection;
+ protected INntpConnection Connection { get; }
///
/// Creates a new instance of the class.
@@ -28,25 +29,25 @@ public partial class NntpClient : INntpClient
public NntpClient(INntpConnection connection)
{
Guard.ThrowIfNull(connection);
- _connection = connection;
+ Connection = connection;
}
///
/// The number of bytes read.
///
- public long BytesRead => _connection.Stream?.BytesRead ?? 0;
+ public long BytesRead => Connection.Stream?.BytesRead ?? 0;
///
/// The number of bytes written.
///
- public long BytesWritten => _connection.Stream?.BytesWritten ?? 0;
+ public long BytesWritten => Connection.Stream?.BytesWritten ?? 0;
///
/// Resets the counters.
///
public void ResetCounters()
{
- _connection.Stream?.ResetCounters();
+ Connection.Stream?.ResetCounters();
}
///
@@ -58,7 +59,7 @@ CancellationToken cancellationToken
)
{
Guard.ThrowIfNullOrWhiteSpace(hostname, nameof(hostname));
- var response = await _connection
+ var response = await Connection
.ConnectAsync(hostname, port, useSsl, new ResponseParser(200, 201), cancellationToken)
.ConfigureAwait(false);
return response.Success;
@@ -72,7 +73,7 @@ CancellationToken cancellationToken
)
{
Guard.ThrowIfNullOrWhiteSpace(username, nameof(username));
- var userResponse = await _connection
+ var userResponse = await Connection
.CommandAsync($"AUTHINFO USER {username}", new ResponseParser(281), cancellationToken)
.ConfigureAwait(false);
if (userResponse.Success)
@@ -85,7 +86,7 @@ CancellationToken cancellationToken
return false;
}
- var passResponse = await _connection
+ var passResponse = await Connection
.CommandAsync($"AUTHINFO PASS {password}", new ResponseParser(281), cancellationToken)
.ConfigureAwait(false);
return passResponse.Success;
@@ -93,7 +94,7 @@ CancellationToken cancellationToken
///
public Task CapabilitiesAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"CAPABILITIES",
new MultiLineResponseParser(101),
cancellationToken
@@ -104,7 +105,7 @@ public Task CapabilitiesAsync(
string keyword,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"CAPABILITIES {keyword.ThrowIfNullOrWhiteSpace(nameof(keyword))}",
new MultiLineResponseParser(101),
cancellationToken
@@ -112,15 +113,15 @@ CancellationToken cancellationToken
///
public Task ModeReaderAsync(CancellationToken cancellationToken) =>
- _connection.CommandAsync("MODE READER", new ModeReaderResponseParser(), cancellationToken);
+ Connection.CommandAsync("MODE READER", new ModeReaderResponseParser(), cancellationToken);
///
public Task QuitAsync(CancellationToken cancellationToken) =>
- _connection.CommandAsync("QUIT", new ResponseParser(205), cancellationToken);
+ Connection.CommandAsync("QUIT", new ResponseParser(205), cancellationToken);
///
public Task GroupAsync(string group, CancellationToken cancellationToken) =>
- _connection.CommandAsync(
+ Connection.CommandAsync(
$"GROUP {group.ThrowIfNullOrWhiteSpace(nameof(group))}",
new GroupResponseParser(),
cancellationToken
@@ -132,7 +133,7 @@ public Task ListGroupAsync(
NntpArticleRange range,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"LISTGROUP {group.ThrowIfNullOrWhiteSpace(nameof(group))} {range}",
new ListGroupResponseParser(),
cancellationToken
@@ -143,7 +144,7 @@ public Task ListGroupAsync(
string group,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"LISTGROUP {group.ThrowIfNullOrWhiteSpace(nameof(group))}",
new ListGroupResponseParser(),
cancellationToken
@@ -151,7 +152,7 @@ CancellationToken cancellationToken
///
public Task ListGroupAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LISTGROUP",
new ListGroupResponseParser(),
cancellationToken
@@ -159,18 +160,18 @@ public Task ListGroupAsync(CancellationToken cancellationToke
///
public Task LastAsync(CancellationToken cancellationToken) =>
- _connection.CommandAsync("LAST", new LastResponseParser(), cancellationToken);
+ Connection.CommandAsync("LAST", new LastResponseParser(), cancellationToken);
///
public Task NextAsync(CancellationToken cancellationToken) =>
- _connection.CommandAsync("NEXT", new NextResponseParser(), cancellationToken);
+ Connection.CommandAsync("NEXT", new NextResponseParser(), cancellationToken);
///
public Task ArticleAsync(
NntpMessageId messageId,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"ARTICLE {messageId.ThrowIfNullOrWhiteSpace(nameof(messageId))}",
new ArticleResponseParser(ArticleRequestType.Article),
cancellationToken
@@ -181,7 +182,7 @@ public Task ArticleAsync(
long number,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"ARTICLE {number}",
new ArticleResponseParser(ArticleRequestType.Article),
cancellationToken
@@ -189,7 +190,7 @@ CancellationToken cancellationToken
///
public Task ArticleAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"ARTICLE",
new ArticleResponseParser(ArticleRequestType.Article),
cancellationToken
@@ -200,7 +201,7 @@ public Task HeadAsync(
NntpMessageId messageId,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"HEAD {messageId.ThrowIfNullOrWhiteSpace(nameof(messageId))}",
new ArticleResponseParser(ArticleRequestType.Head),
cancellationToken
@@ -208,7 +209,7 @@ CancellationToken cancellationToken
///
public Task HeadAsync(long number, CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"HEAD {number}",
new ArticleResponseParser(ArticleRequestType.Head),
cancellationToken
@@ -216,7 +217,7 @@ public Task HeadAsync(long number, CancellationToken cancel
///
public Task HeadAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"HEAD",
new ArticleResponseParser(ArticleRequestType.Head),
cancellationToken
@@ -227,7 +228,7 @@ public Task BodyAsync(
NntpMessageId messageId,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"BODY {messageId.ThrowIfNullOrWhiteSpace(nameof(messageId))}",
new ArticleResponseParser(ArticleRequestType.Body),
cancellationToken
@@ -235,7 +236,7 @@ CancellationToken cancellationToken
///
public Task BodyAsync(long number, CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"BODY {number}",
new ArticleResponseParser(ArticleRequestType.Body),
cancellationToken
@@ -243,7 +244,7 @@ public Task BodyAsync(long number, CancellationToken cancel
///
public Task BodyAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"BODY",
new ArticleResponseParser(ArticleRequestType.Body),
cancellationToken
@@ -254,7 +255,7 @@ public Task StatAsync(
NntpMessageId messageId,
CancellationToken cancellationToken
) =>
- _connection.CommandAsync(
+ Connection.CommandAsync(
$"STAT {messageId.ThrowIfNullOrWhiteSpace(nameof(messageId))}",
new StatResponseParser(),
cancellationToken
@@ -262,16 +263,16 @@ CancellationToken cancellationToken
///
public Task StatAsync(long number, CancellationToken cancellationToken) =>
- _connection.CommandAsync($"STAT {number}", new StatResponseParser(), cancellationToken);
+ Connection.CommandAsync($"STAT {number}", new StatResponseParser(), cancellationToken);
///
public Task StatAsync(CancellationToken cancellationToken) =>
- _connection.CommandAsync("STAT", new StatResponseParser(), cancellationToken);
+ Connection.CommandAsync("STAT", new StatResponseParser(), cancellationToken);
///
public async Task PostAsync(NntpArticle article, CancellationToken cancellationToken)
{
- var initialResponse = await _connection
+ var initialResponse = await Connection
.CommandAsync("POST", new ResponseParser(340), cancellationToken)
.ConfigureAwait(false);
if (!initialResponse.Success)
@@ -280,9 +281,9 @@ public async Task PostAsync(NntpArticle article, CancellationToken cancell
}
await ArticleWriter
- .WriteAsync(_connection, article, cancellationToken)
+ .WriteAsync(Connection, article, cancellationToken)
.ConfigureAwait(false);
- var subsequentResponse = await _connection
+ var subsequentResponse = await Connection
.GetResponseAsync(new ResponseParser(240), cancellationToken)
.ConfigureAwait(false);
return subsequentResponse.Success;
@@ -291,7 +292,7 @@ await ArticleWriter
///
public async Task IhaveAsync(NntpArticle article, CancellationToken cancellationToken)
{
- var initialResponse = await _connection
+ var initialResponse = await Connection
.CommandAsync("IHAVE", new ResponseParser(335), cancellationToken)
.ConfigureAwait(false);
if (!initialResponse.Success)
@@ -300,9 +301,9 @@ public async Task IhaveAsync(NntpArticle article, CancellationToken cancel
}
await ArticleWriter
- .WriteAsync(_connection, article, cancellationToken)
+ .WriteAsync(Connection, article, cancellationToken)
.ConfigureAwait(false);
- var subsequentResponse = await _connection
+ var subsequentResponse = await Connection
.GetResponseAsync(new ResponseParser(235), cancellationToken)
.ConfigureAwait(false);
return subsequentResponse.Success;
@@ -310,11 +311,11 @@ await ArticleWriter
///
public Task DateAsync(CancellationToken cancellationToken) =>
- _connection.CommandAsync("DATE", new DateResponseParser(), cancellationToken);
+ Connection.CommandAsync("DATE", new DateResponseParser(), cancellationToken);
///
public Task HelpAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"HELP",
new MultiLineResponseParser(100),
cancellationToken
@@ -325,7 +326,7 @@ public Task NewGroupsAsync(
NntpDateTime sinceDateTime,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"NEWGROUPS {sinceDateTime}",
new GroupsResponseParser(231, GroupStatusRequestType.Basic),
cancellationToken
@@ -337,7 +338,7 @@ public Task NewNewsAsync(
NntpDateTime sinceDateTime,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"NEWNEWS {wildmat} {sinceDateTime}",
new MultiLineResponseParser(230),
cancellationToken
@@ -347,7 +348,7 @@ CancellationToken cancellationToken
public Task ListActiveTimesAsync(
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST ACTIVE.TIMES",
new GroupOriginsResponseParser(),
cancellationToken
@@ -358,7 +359,7 @@ public Task ListActiveTimesAsync(
string wildmat,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"LIST ACTIVE.TIMES {wildmat}",
new GroupOriginsResponseParser(),
cancellationToken
@@ -366,7 +367,7 @@ CancellationToken cancellationToken
///
public Task ListDistribPatsAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST DISTRIB.PATS",
new MultiLineResponseParser(215),
cancellationToken
@@ -374,7 +375,7 @@ public Task ListDistribPatsAsync(CancellationToken cancel
///
public Task ListNewsgroupsAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST NEWSGROUPS",
new MultiLineResponseParser(215),
cancellationToken
@@ -385,7 +386,7 @@ public Task ListNewsgroupsAsync(
string wildmat,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"LIST NEWSGROUPS {wildmat}",
new MultiLineResponseParser(215),
cancellationToken
@@ -396,7 +397,7 @@ public Task OverAsync(
NntpMessageId messageId,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"OVER {messageId}",
new MultiLineResponseParser(224),
cancellationToken
@@ -407,7 +408,7 @@ public Task OverAsync(
NntpArticleRange range,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"OVER {range}",
new MultiLineResponseParser(224),
cancellationToken
@@ -415,7 +416,7 @@ CancellationToken cancellationToken
///
public Task OverAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"OVER",
new MultiLineResponseParser(224),
cancellationToken
@@ -425,7 +426,7 @@ public Task OverAsync(CancellationToken cancellationToken
public Task ListOverviewFormatAsync(
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST OVERVIEW.FMT",
new MultiLineResponseParser(215),
cancellationToken
@@ -437,7 +438,7 @@ public Task HdrAsync(
NntpMessageId messageId,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"HDR {field} {messageId}",
new MultiLineResponseParser(225),
cancellationToken
@@ -449,7 +450,7 @@ public Task HdrAsync(
NntpArticleRange range,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"HDR {field} {range}",
new MultiLineResponseParser(225),
cancellationToken
@@ -460,7 +461,7 @@ public Task HdrAsync(
string field,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"HDR {field}",
new MultiLineResponseParser(225),
cancellationToken
@@ -471,7 +472,7 @@ public Task ListHeadersAsync(
NntpMessageId messageId,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"LIST HEADERS {messageId}",
new MultiLineResponseParser(215),
cancellationToken
@@ -482,7 +483,7 @@ public Task ListHeadersAsync(
NntpArticleRange range,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"LIST HEADERS {range}",
new MultiLineResponseParser(215),
cancellationToken
@@ -490,7 +491,7 @@ CancellationToken cancellationToken
///
public Task ListHeadersAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST HEADERS",
new MultiLineResponseParser(215),
cancellationToken
@@ -502,7 +503,7 @@ public Task XhdrAsync(
NntpMessageId messageId,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"XHDR {field} {messageId}",
new MultiLineResponseParser(221),
cancellationToken
@@ -514,7 +515,7 @@ public Task XhdrAsync(
NntpArticleRange range,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"XHDR {field} {range}",
new MultiLineResponseParser(221),
cancellationToken
@@ -525,7 +526,7 @@ public Task XhdrAsync(
string field,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"XHDR {field}",
new MultiLineResponseParser(221),
cancellationToken
@@ -536,7 +537,7 @@ public Task XoverAsync(
NntpArticleRange range,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"XOVER {range}",
new MultiLineResponseParser(224),
cancellationToken
@@ -544,7 +545,7 @@ CancellationToken cancellationToken
///
public Task XoverAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"XOVER",
new MultiLineResponseParser(224),
cancellationToken
@@ -552,7 +553,7 @@ public Task XoverAsync(CancellationToken cancellationToke
///
public Task ListCountsAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST COUNTS",
new GroupsResponseParser(215, GroupStatusRequestType.Extended),
cancellationToken
@@ -563,7 +564,7 @@ public Task ListCountsAsync(
string wildmat,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"LIST COUNTS {wildmat}",
new GroupsResponseParser(215, GroupStatusRequestType.Extended),
cancellationToken
@@ -573,7 +574,7 @@ CancellationToken cancellationToken
public Task ListDistributionsAsync(
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST DISTRIBUTIONS",
new MultiLineResponseParser(215),
cancellationToken
@@ -581,7 +582,7 @@ CancellationToken cancellationToken
///
public Task ListModeratorsAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST MODERATORS",
new MultiLineResponseParser(215),
cancellationToken
@@ -589,7 +590,7 @@ public Task ListModeratorsAsync(CancellationToken cancell
///
public Task ListMotdAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST MOTD",
new MultiLineResponseParser(215),
cancellationToken
@@ -599,7 +600,7 @@ public Task ListMotdAsync(CancellationToken cancellationT
public Task ListSubscriptionsAsync(
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST SUBSCRIPTIONS",
new MultiLineResponseParser(215),
cancellationToken
@@ -607,7 +608,7 @@ CancellationToken cancellationToken
///
public Task ListActiveAsync(CancellationToken cancellationToken) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
"LIST ACTIVE",
new GroupsResponseParser(215, GroupStatusRequestType.Basic),
cancellationToken
@@ -618,7 +619,7 @@ public Task ListActiveAsync(
string wildmat,
CancellationToken cancellationToken
) =>
- _connection.MultiLineCommandAsync(
+ Connection.MultiLineCommandAsync(
$"LIST ACTIVE {wildmat}",
new GroupsResponseParser(215, GroupStatusRequestType.Basic),
cancellationToken
diff --git a/src/Usenet/Nntp/NntpClientPool.cs b/src/Usenet/Nntp/NntpClientPool.cs
index 23cb466..a641c06 100644
--- a/src/Usenet/Nntp/NntpClientPool.cs
+++ b/src/Usenet/Nntp/NntpClientPool.cs
@@ -1,3 +1,4 @@
+using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Usenet.Extensions;
using Usenet.Nntp.Contracts;
@@ -7,6 +8,7 @@
namespace Usenet.Nntp;
///
+[PublicAPI]
public sealed class NntpClientPool : INntpClientPool
{
#if NET9_0_OR_GREATER
@@ -83,7 +85,7 @@ private async Task BorrowClient(CancellationToken can
var client = BorrowClientInternal();
- if (client.Connected && client.Authenticated)
+ if (client is { Connected: true, Authenticated: true })
return client;
if (!client.Connected)
diff --git a/src/Usenet/Nntp/NntpConnection.cs b/src/Usenet/Nntp/NntpConnection.cs
index 697e68f..3cc7401 100644
--- a/src/Usenet/Nntp/NntpConnection.cs
+++ b/src/Usenet/Nntp/NntpConnection.cs
@@ -1,6 +1,7 @@
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
+using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Usenet.Exceptions;
using Usenet.Extensions;
@@ -17,6 +18,7 @@ namespace Usenet.Nntp;
///
/// This implementation of the interface does support SSL encryption but
/// does not support compressed multi-line results.
+[PublicAPI]
public sealed partial class NntpConnection : INntpConnection
{
private readonly ILogger _log = Logger.Create();
@@ -157,7 +159,7 @@ [EnumeratorCancellation] CancellationToken cancellationToken
///
public void Dispose()
{
- _client?.Dispose();
+ _client.Dispose();
_writer?.Dispose();
_reader?.Dispose();
}
diff --git a/src/Usenet/Nntp/NntpHeaders.cs b/src/Usenet/Nntp/NntpHeaders.cs
index a75875c..2078451 100644
--- a/src/Usenet/Nntp/NntpHeaders.cs
+++ b/src/Usenet/Nntp/NntpHeaders.cs
@@ -1,8 +1,11 @@
-namespace Usenet.Nntp;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp;
///
/// Defines NNTP news header fields.
///
+[PublicAPI]
public static class NntpHeaders
{
///
diff --git a/src/Usenet/Nntp/Parsers/ArticleResponseParser.cs b/src/Usenet/Nntp/Parsers/ArticleResponseParser.cs
index 067836f..a3764f3 100644
--- a/src/Usenet/Nntp/Parsers/ArticleResponseParser.cs
+++ b/src/Usenet/Nntp/Parsers/ArticleResponseParser.cs
@@ -49,18 +49,7 @@ public NntpArticleResponse Parse(int code, string message, IEnumerable d
}
_ = long.TryParse(responseSplit.Length > 0 ? responseSplit[0] : null, out var number);
- var messageId = responseSplit.Length > 1 ? responseSplit[1] : string.Empty;
-
- if (dataBlock == null)
- {
- // no headers and no body
- return new NntpArticleResponse(
- code,
- message,
- true,
- new NntpArticle(number, messageId, null, null, null)
- );
- }
+ NntpMessageId messageId = responseSplit.Length > 1 ? responseSplit[1] : NntpMessageId.Empty;
using var enumerator = dataBlock.GetEnumerator();
@@ -73,7 +62,7 @@ public NntpArticleResponse Parse(int code, string message, IEnumerable d
// get groups
var groups = headers.TryGetValue(NntpHeaders.Newsgroups, out var values)
? new NntpGroupsBuilder().Add(values).Build()
- : null;
+ : NntpGroups.Empty;
// get body if requested
var bodyLines =
@@ -133,7 +122,10 @@ private MultiValueDictionary GetHeaders(IEnumerator enum
private static IEnumerable GetBody(IEnumerator enumerator)
{
while (enumerator.MoveNext())
- yield return enumerator.Current;
+ {
+ if (enumerator.Current is not null)
+ yield return enumerator.Current;
+ }
}
private class Header
diff --git a/src/Usenet/Nntp/Parsers/GroupOriginsResponseParser.cs b/src/Usenet/Nntp/Parsers/GroupOriginsResponseParser.cs
index 6678a76..fc8bbfb 100644
--- a/src/Usenet/Nntp/Parsers/GroupOriginsResponseParser.cs
+++ b/src/Usenet/Nntp/Parsers/GroupOriginsResponseParser.cs
@@ -14,7 +14,7 @@ internal class GroupOriginsResponseParser : IMultiLineResponseParser dataBlock)
{
- if (!IsSuccessResponse(code) || dataBlock == null)
+ if (!IsSuccessResponse(code))
{
return new NntpGroupOriginsResponse(code, message, false, []);
}
@@ -26,11 +26,6 @@ public NntpGroupOriginsResponse Parse(int code, string message, IEnumerable EnumerateGroupOrigins(IEnumerable dataBlock)
{
- if (dataBlock == null)
- {
- yield break;
- }
-
foreach (var line in dataBlock)
{
var lineSplit = line.Split(' ');
diff --git a/src/Usenet/Nntp/Parsers/GroupsParser.cs b/src/Usenet/Nntp/Parsers/GroupsParser.cs
index 28f981d..05175e0 100644
--- a/src/Usenet/Nntp/Parsers/GroupsParser.cs
+++ b/src/Usenet/Nntp/Parsers/GroupsParser.cs
@@ -1,6 +1,8 @@
using Usenet.Extensions;
using Usenet.Nntp.Models;
+#if NETSTANDARD2_0
using Usenet.Util.Compatibility;
+#endif
namespace Usenet.Nntp.Parsers;
diff --git a/src/Usenet/Nntp/Parsers/GroupsResponseParser.cs b/src/Usenet/Nntp/Parsers/GroupsResponseParser.cs
index e5b8209..6ccc956 100644
--- a/src/Usenet/Nntp/Parsers/GroupsResponseParser.cs
+++ b/src/Usenet/Nntp/Parsers/GroupsResponseParser.cs
@@ -27,7 +27,7 @@ public GroupsResponseParser(int successCode, GroupStatusRequestType requestType)
public NntpGroupsResponse Parse(int code, string message, IEnumerable dataBlock)
{
- if (!IsSuccessResponse(code) || dataBlock == null)
+ if (!IsSuccessResponse(code))
{
return new NntpGroupsResponse(code, message, false, []);
}
@@ -39,11 +39,6 @@ public NntpGroupsResponse Parse(int code, string message, IEnumerable da
private IEnumerable EnumerateGroups(IEnumerable dataBlock)
{
- if (dataBlock == null)
- {
- yield break;
- }
-
var checkParameterCount = _requestType == GroupStatusRequestType.Basic ? 4 : 5;
foreach (var line in dataBlock)
diff --git a/src/Usenet/Nntp/Parsers/HeaderDateParser.cs b/src/Usenet/Nntp/Parsers/HeaderDateParser.cs
index 3ae0e78..1b00900 100644
--- a/src/Usenet/Nntp/Parsers/HeaderDateParser.cs
+++ b/src/Usenet/Nntp/Parsers/HeaderDateParser.cs
@@ -1,8 +1,10 @@
using System.Globalization;
using System.Text.RegularExpressions;
+using JetBrains.Annotations;
namespace Usenet.Nntp.Parsers;
+[PublicAPI]
public static class HeaderDateParser
{
private const string DateTimeRegexString =
diff --git a/src/Usenet/Nntp/Parsers/IMultiLineResponseParser.cs b/src/Usenet/Nntp/Parsers/IMultiLineResponseParser.cs
index c3f479b..e778469 100644
--- a/src/Usenet/Nntp/Parsers/IMultiLineResponseParser.cs
+++ b/src/Usenet/Nntp/Parsers/IMultiLineResponseParser.cs
@@ -1,9 +1,12 @@
-namespace Usenet.Nntp.Parsers;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp.Parsers;
///
/// Represents a multi-line response parser.
///
///
+[PublicAPI]
public interface IMultiLineResponseParser
{
///
diff --git a/src/Usenet/Nntp/Parsers/IResponseParser.cs b/src/Usenet/Nntp/Parsers/IResponseParser.cs
index 2288d1e..32d45eb 100644
--- a/src/Usenet/Nntp/Parsers/IResponseParser.cs
+++ b/src/Usenet/Nntp/Parsers/IResponseParser.cs
@@ -1,9 +1,12 @@
-namespace Usenet.Nntp.Parsers;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp.Parsers;
///
/// Represents a single-line response parser.
///
///
+[PublicAPI]
public interface IResponseParser
{
///
diff --git a/src/Usenet/Nntp/Parsers/ListGroupResponseParser.cs b/src/Usenet/Nntp/Parsers/ListGroupResponseParser.cs
index a2bfee8..6b20d80 100644
--- a/src/Usenet/Nntp/Parsers/ListGroupResponseParser.cs
+++ b/src/Usenet/Nntp/Parsers/ListGroupResponseParser.cs
@@ -58,11 +58,6 @@ out var highWaterMark
private static IEnumerable EnumerateArticleNumbers(IEnumerable dataBlock)
{
- if (dataBlock == null)
- {
- yield break;
- }
-
foreach (var line in dataBlock)
{
if (!long.TryParse(line, out var number))
diff --git a/src/Usenet/Nntp/Parsers/MultiLineResponseParser.cs b/src/Usenet/Nntp/Parsers/MultiLineResponseParser.cs
index 676006f..0762c04 100644
--- a/src/Usenet/Nntp/Parsers/MultiLineResponseParser.cs
+++ b/src/Usenet/Nntp/Parsers/MultiLineResponseParser.cs
@@ -6,10 +6,7 @@ internal class MultiLineResponseParser : IMultiLineResponseParser _successCodes = successCodes;
public bool IsSuccessResponse(int code) => _successCodes.Contains(code);
diff --git a/src/Usenet/Nntp/Parsers/ResponseParser.cs b/src/Usenet/Nntp/Parsers/ResponseParser.cs
index 1b1a12f..0f8f365 100644
--- a/src/Usenet/Nntp/Parsers/ResponseParser.cs
+++ b/src/Usenet/Nntp/Parsers/ResponseParser.cs
@@ -6,10 +6,7 @@ internal class ResponseParser : IResponseParser
{
private readonly int[] _successCodes;
- public ResponseParser(params int[] successCodes)
- {
- _successCodes = successCodes ?? [];
- }
+ public ResponseParser(params int[] successCodes) => _successCodes = successCodes;
public bool IsSuccessResponse(int code) => _successCodes.Contains(code);
diff --git a/src/Usenet/Nntp/Responses/NntpArticleResponse.cs b/src/Usenet/Nntp/Responses/NntpArticleResponse.cs
index e1539ab..7b7e62b 100644
--- a/src/Usenet/Nntp/Responses/NntpArticleResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpArticleResponse.cs
@@ -1,4 +1,5 @@
-using Usenet.Nntp.Models;
+using JetBrains.Annotations;
+using Usenet.Nntp.Models;
namespace Usenet.Nntp.Responses;
@@ -8,6 +9,7 @@ namespace Usenet.Nntp.Responses;
/// HEAD and
/// BODY commands.
///
+[PublicAPI]
public class NntpArticleResponse : NntpResponse
{
///
@@ -22,7 +24,7 @@ public class NntpArticleResponse : NntpResponse
/// The response message received from the server.
/// A value indicating whether the command succeeded or failed.
/// The received from the server.
- public NntpArticleResponse(int code, string message, bool success, NntpArticle? article)
+ internal NntpArticleResponse(int code, string message, bool success, NntpArticle? article)
: base(code, message, success)
{
Article = article;
diff --git a/src/Usenet/Nntp/Responses/NntpDateResponse.cs b/src/Usenet/Nntp/Responses/NntpDateResponse.cs
index 8382e2c..f557f84 100644
--- a/src/Usenet/Nntp/Responses/NntpDateResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpDateResponse.cs
@@ -1,9 +1,12 @@
-namespace Usenet.Nntp.Responses;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp.Responses;
///
/// Represents a response to the
/// DATE command.
///
+[PublicAPI]
public class NntpDateResponse : NntpResponse
{
///
@@ -18,7 +21,7 @@ public class NntpDateResponse : NntpResponse
/// The response message received from the server.
/// A value indicating whether the command succeeded or failed.
/// The date and time received from the server.
- public NntpDateResponse(int code, string message, bool success, DateTimeOffset dateTime)
+ internal NntpDateResponse(int code, string message, bool success, DateTimeOffset dateTime)
: base(code, message, success)
{
DateTime = dateTime;
diff --git a/src/Usenet/Nntp/Responses/NntpGroupOriginsResponse.cs b/src/Usenet/Nntp/Responses/NntpGroupOriginsResponse.cs
index 5ea377a..975a7d9 100644
--- a/src/Usenet/Nntp/Responses/NntpGroupOriginsResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpGroupOriginsResponse.cs
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
+using JetBrains.Annotations;
using Usenet.Nntp.Models;
namespace Usenet.Nntp.Responses;
@@ -8,6 +9,7 @@ namespace Usenet.Nntp.Responses;
/// LIST ACTIVE.TIMES
/// (ad 1) command.
///
+[PublicAPI]
public class NntpGroupOriginsResponse : NntpResponse
{
///
@@ -22,7 +24,7 @@ public class NntpGroupOriginsResponse : NntpResponse
/// The response message received from the server.
/// A value indicating whether the command succeeded or failed.
/// The list of objects received from the server.
- public NntpGroupOriginsResponse(
+ internal NntpGroupOriginsResponse(
int code,
string message,
bool success,
@@ -30,6 +32,6 @@ IList groupOrigins
)
: base(code, message, success)
{
- GroupOrigins = (groupOrigins ?? []).ToImmutableList();
+ GroupOrigins = groupOrigins.ToImmutableList();
}
}
diff --git a/src/Usenet/Nntp/Responses/NntpGroupResponse.cs b/src/Usenet/Nntp/Responses/NntpGroupResponse.cs
index f972ea5..37290f7 100644
--- a/src/Usenet/Nntp/Responses/NntpGroupResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpGroupResponse.cs
@@ -1,4 +1,5 @@
-using Usenet.Nntp.Models;
+using JetBrains.Annotations;
+using Usenet.Nntp.Models;
namespace Usenet.Nntp.Responses;
@@ -7,6 +8,7 @@ namespace Usenet.Nntp.Responses;
/// GROUP and
/// LISTGROUP commands.
///
+[PublicAPI]
public class NntpGroupResponse : NntpResponse
{
///
@@ -21,7 +23,7 @@ public class NntpGroupResponse : NntpResponse
/// The response message received from the server.
/// A value indicating whether the command succeeded or failed.
/// The received from the server.
- public NntpGroupResponse(int code, string message, bool success, NntpGroup group)
+ internal NntpGroupResponse(int code, string message, bool success, NntpGroup group)
: base(code, message, success)
{
Group = group;
diff --git a/src/Usenet/Nntp/Responses/NntpGroupsResponse.cs b/src/Usenet/Nntp/Responses/NntpGroupsResponse.cs
index 649be5d..978daab 100644
--- a/src/Usenet/Nntp/Responses/NntpGroupsResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpGroupsResponse.cs
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
+using JetBrains.Annotations;
using Usenet.Nntp.Models;
namespace Usenet.Nntp.Responses;
@@ -11,6 +12,7 @@ namespace Usenet.Nntp.Responses;
/// ad 2) and
/// NEWGROUPS commands.
///
+[PublicAPI]
public class NntpGroupsResponse : NntpResponse
{
///
@@ -25,9 +27,9 @@ public class NntpGroupsResponse : NntpResponse
/// The response message received from the server.
/// A value indicating whether the command succeeded or failed.
/// The list of objects received from the server.
- public NntpGroupsResponse(int code, string message, bool success, IList groups)
+ internal NntpGroupsResponse(int code, string message, bool success, IList groups)
: base(code, message, success)
{
- Groups = (groups ?? []).ToImmutableList();
+ Groups = groups.ToImmutableList();
}
}
diff --git a/src/Usenet/Nntp/Responses/NntpLastResponse.cs b/src/Usenet/Nntp/Responses/NntpLastResponse.cs
index e82b158..f8d3d80 100644
--- a/src/Usenet/Nntp/Responses/NntpLastResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpLastResponse.cs
@@ -1,4 +1,5 @@
-using Usenet.Nntp.Models;
+using JetBrains.Annotations;
+using Usenet.Nntp.Models;
namespace Usenet.Nntp.Responses;
@@ -6,6 +7,7 @@ namespace Usenet.Nntp.Responses;
/// Represents a response to the
/// LAST command.
///
+[PublicAPI]
public class NntpLastResponse : NntpResponse
{
///
@@ -34,7 +36,7 @@ public class NntpLastResponse : NntpResponse
/// The type of the response received from the server.
/// The number received from the server.
/// The received from the server.
- public NntpLastResponse(
+ internal NntpLastResponse(
int code,
string message,
bool success,
@@ -46,6 +48,6 @@ NntpMessageId messageId
{
ResponseType = responseType;
Number = number;
- MessageId = messageId ?? NntpMessageId.Empty;
+ MessageId = messageId;
}
}
diff --git a/src/Usenet/Nntp/Responses/NntpLastResponseType.cs b/src/Usenet/Nntp/Responses/NntpLastResponseType.cs
index b2dca53..7e80d45 100644
--- a/src/Usenet/Nntp/Responses/NntpLastResponseType.cs
+++ b/src/Usenet/Nntp/Responses/NntpLastResponseType.cs
@@ -1,9 +1,12 @@
-namespace Usenet.Nntp.Responses;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp.Responses;
///
/// Represents all possible response codes for the
/// LAST command.
///
+[PublicAPI]
public enum NntpLastResponseType
{
///
diff --git a/src/Usenet/Nntp/Responses/NntpModeReaderResponse.cs b/src/Usenet/Nntp/Responses/NntpModeReaderResponse.cs
index a5d325d..3af303e 100644
--- a/src/Usenet/Nntp/Responses/NntpModeReaderResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpModeReaderResponse.cs
@@ -1,10 +1,13 @@
-namespace Usenet.Nntp.Responses;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp.Responses;
///
/// Represents the response to the
/// MODE READER
/// (ad 1) command.
///
+[PublicAPI]
public class NntpModeReaderResponse : NntpResponse
{
///
@@ -19,7 +22,7 @@ public class NntpModeReaderResponse : NntpResponse
/// The response message received from the server.
/// A value indicating whether the command succeeded or failed.
/// The type of the response received from the server.
- public NntpModeReaderResponse(
+ internal NntpModeReaderResponse(
int code,
string message,
bool success,
diff --git a/src/Usenet/Nntp/Responses/NntpModeReaderResponseType.cs b/src/Usenet/Nntp/Responses/NntpModeReaderResponseType.cs
index 27bd037..01c6738 100644
--- a/src/Usenet/Nntp/Responses/NntpModeReaderResponseType.cs
+++ b/src/Usenet/Nntp/Responses/NntpModeReaderResponseType.cs
@@ -1,10 +1,13 @@
-namespace Usenet.Nntp.Responses;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp.Responses;
///
/// Represents all possible response codes for the
/// MODE READER
/// (ad 1) command.
///
+[PublicAPI]
public enum NntpModeReaderResponseType
{
///
diff --git a/src/Usenet/Nntp/Responses/NntpMultiLineResponse.cs b/src/Usenet/Nntp/Responses/NntpMultiLineResponse.cs
index 3f940bb..72a799e 100644
--- a/src/Usenet/Nntp/Responses/NntpMultiLineResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpMultiLineResponse.cs
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
+using JetBrains.Annotations;
namespace Usenet.Nntp.Responses;
@@ -6,6 +7,7 @@ namespace Usenet.Nntp.Responses;
/// Represents a generic multi-line response.
/// Based on Kristian Hellang's NntpLib.Net project https://github.com/khellang/NntpLib.Net.
///
+[PublicAPI]
public class NntpMultiLineResponse : NntpResponse
{
///
@@ -20,9 +22,14 @@ public class NntpMultiLineResponse : NntpResponse
/// The response message received from the server.
/// A value indicating whether the command succeeded or failed.
/// The lines received from the server.
- public NntpMultiLineResponse(int code, string message, bool success, IEnumerable lines)
+ internal NntpMultiLineResponse(
+ int code,
+ string message,
+ bool success,
+ IEnumerable lines
+ )
: base(code, message, success)
{
- Lines = (lines ?? []).ToImmutableList();
+ Lines = lines.ToImmutableList();
}
}
diff --git a/src/Usenet/Nntp/Responses/NntpNextResponse.cs b/src/Usenet/Nntp/Responses/NntpNextResponse.cs
index cf1ab00..72fbb12 100644
--- a/src/Usenet/Nntp/Responses/NntpNextResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpNextResponse.cs
@@ -1,4 +1,5 @@
-using Usenet.Nntp.Models;
+using JetBrains.Annotations;
+using Usenet.Nntp.Models;
namespace Usenet.Nntp.Responses;
@@ -6,6 +7,7 @@ namespace Usenet.Nntp.Responses;
/// Represents a response to the
/// NEXT command.
///
+[PublicAPI]
public class NntpNextResponse : NntpResponse
{
///
@@ -34,7 +36,7 @@ public class NntpNextResponse : NntpResponse
/// The type of the response received from the server.
/// The number received from the server.
/// The received from the server.
- public NntpNextResponse(
+ internal NntpNextResponse(
int code,
string message,
bool success,
@@ -46,6 +48,6 @@ NntpMessageId messageId
{
ResponseType = responseType;
Number = number;
- MessageId = messageId ?? NntpMessageId.Empty;
+ MessageId = messageId;
}
}
diff --git a/src/Usenet/Nntp/Responses/NntpNextResponseType.cs b/src/Usenet/Nntp/Responses/NntpNextResponseType.cs
index 68c9337..fe38b46 100644
--- a/src/Usenet/Nntp/Responses/NntpNextResponseType.cs
+++ b/src/Usenet/Nntp/Responses/NntpNextResponseType.cs
@@ -1,9 +1,12 @@
-namespace Usenet.Nntp.Responses;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp.Responses;
///
/// Represents all possible response codes for the
/// NEXT command.
///
+[PublicAPI]
public enum NntpNextResponseType
{
///
diff --git a/src/Usenet/Nntp/Responses/NntpResponse.cs b/src/Usenet/Nntp/Responses/NntpResponse.cs
index 1118250..8b002ea 100644
--- a/src/Usenet/Nntp/Responses/NntpResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpResponse.cs
@@ -1,9 +1,12 @@
-namespace Usenet.Nntp.Responses;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp.Responses;
///
/// Represents a single-line response.
/// Based on Kristian Hellang's NntpLib.Net project https://github.com/khellang/NntpLib.Net.
///
+[PublicAPI]
public class NntpResponse
{
///
@@ -27,7 +30,7 @@ public class NntpResponse
/// The response code received from the server.
/// The response message received from the server.
/// A value indicating whether the command succeeded or failed.
- public NntpResponse(int code, string message, bool success)
+ internal NntpResponse(int code, string message, bool success)
{
Code = code;
Message = message;
diff --git a/src/Usenet/Nntp/Responses/NntpStatResponse.cs b/src/Usenet/Nntp/Responses/NntpStatResponse.cs
index c705b11..e1fa4ec 100644
--- a/src/Usenet/Nntp/Responses/NntpStatResponse.cs
+++ b/src/Usenet/Nntp/Responses/NntpStatResponse.cs
@@ -1,4 +1,5 @@
-using Usenet.Nntp.Models;
+using JetBrains.Annotations;
+using Usenet.Nntp.Models;
namespace Usenet.Nntp.Responses;
@@ -6,6 +7,7 @@ namespace Usenet.Nntp.Responses;
/// Represents a response to the
/// STAT command.
///
+[PublicAPI]
public class NntpStatResponse : NntpResponse
{
///
@@ -32,7 +34,7 @@ public class NntpStatResponse : NntpResponse
/// The type of the response received from the server.
/// The number received from the server.
/// The received from the server.
- public NntpStatResponse(
+ internal NntpStatResponse(
int code,
string message,
bool success,
@@ -44,6 +46,6 @@ NntpMessageId messageId
{
ResponseType = responseType;
Number = number;
- MessageId = messageId ?? NntpMessageId.Empty;
+ MessageId = messageId;
}
}
diff --git a/src/Usenet/Nntp/Responses/NntpStatResponseType.cs b/src/Usenet/Nntp/Responses/NntpStatResponseType.cs
index 0f32550..c4b7249 100644
--- a/src/Usenet/Nntp/Responses/NntpStatResponseType.cs
+++ b/src/Usenet/Nntp/Responses/NntpStatResponseType.cs
@@ -1,9 +1,12 @@
-namespace Usenet.Nntp.Responses;
+using JetBrains.Annotations;
+
+namespace Usenet.Nntp.Responses;
///
/// Represents all possible response codes for the
/// STAT command.
///
+[PublicAPI]
public enum NntpStatResponseType
{
///
diff --git a/src/Usenet/Nzb/NzbBuilder.cs b/src/Usenet/Nzb/NzbBuilder.cs
index e8991b8..f2cbdb5 100644
--- a/src/Usenet/Nzb/NzbBuilder.cs
+++ b/src/Usenet/Nzb/NzbBuilder.cs
@@ -1,4 +1,5 @@
using System.Globalization;
+using JetBrains.Annotations;
using Microsoft.Extensions.FileProviders;
using Usenet.Nntp.Builders;
using Usenet.Nntp.Models;
@@ -9,6 +10,7 @@ namespace Usenet.Nzb;
///
/// Represents a mutable .
///
+[PublicAPI]
public class NzbBuilder
{
private readonly List _files = [];
diff --git a/src/Usenet/Nzb/NzbDocument.cs b/src/Usenet/Nzb/NzbDocument.cs
index e16bf58..523ad27 100644
--- a/src/Usenet/Nzb/NzbDocument.cs
+++ b/src/Usenet/Nzb/NzbDocument.cs
@@ -1,5 +1,6 @@
using System.Collections.Immutable;
using System.Text;
+using JetBrains.Annotations;
using Usenet.Extensions;
using Usenet.Util;
using HashCode = Usenet.Util.HashCode;
@@ -10,6 +11,7 @@ namespace Usenet.Nzb;
/// Represents a NZB document.
/// Based on Kristian Hellang's Nzb project https://github.com/khellang/Nzb.
///
+[PublicAPI]
public class NzbDocument : IEquatable
{
///
@@ -32,15 +34,13 @@ public class NzbDocument : IEquatable
///
/// A collection of metadata elements found in the NZB file.
/// A collection of files found in the NZB file.
- public NzbDocument(
- IDictionary>? metaData,
- IEnumerable? files
+ internal NzbDocument(
+ IDictionary> metaData,
+ IEnumerable files
)
{
- MetaData = (
- metaData ?? MultiValueDictionary.Empty
- ).ToImmutableDictionaryWithHashSets();
- Files = (files ?? []).OrderBy(f => f.FileName).ToImmutableList();
+ MetaData = metaData.ToImmutableDictionaryWithHashSets();
+ Files = files.OrderBy(f => f.FileName).ToImmutableList();
Size = Files.Sum(f => f.Size);
}
diff --git a/src/Usenet/Nzb/NzbFile.cs b/src/Usenet/Nzb/NzbFile.cs
index c3a9431..4977b74 100644
--- a/src/Usenet/Nzb/NzbFile.cs
+++ b/src/Usenet/Nzb/NzbFile.cs
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
+using JetBrains.Annotations;
using Usenet.Nntp.Models;
using Usenet.Util;
using HashCode = Usenet.Util.HashCode;
@@ -9,6 +10,7 @@ namespace Usenet.Nzb;
/// Represents a file in a NZB document.
/// Based on Kristian Hellang's Nzb project https://github.com/khellang/Nzb.
///
+[PublicAPI]
public class NzbFile : IEquatable
{
///
@@ -59,7 +61,7 @@ public class NzbFile : IEquatable
/// The date the server saw this article.
/// The list of groups that reference this file.
/// The list of segments that make up this file.
- public NzbFile(
+ internal NzbFile(
string poster,
string subject,
string fileName,
@@ -72,8 +74,8 @@ IEnumerable segments
Subject = subject;
FileName = fileName;
Date = date;
- Groups = groups ?? NntpGroups.Empty;
- Segments = (segments ?? new List(0)).OrderBy(s => s.Number).ToImmutableList();
+ Groups = groups;
+ Segments = segments.OrderBy(s => s.Number).ToImmutableList();
Size = Segments.Sum(s => s.Size);
}
diff --git a/src/Usenet/Nzb/NzbKeywords.cs b/src/Usenet/Nzb/NzbKeywords.cs
index 86b7a6b..2a40e99 100644
--- a/src/Usenet/Nzb/NzbKeywords.cs
+++ b/src/Usenet/Nzb/NzbKeywords.cs
@@ -4,7 +4,7 @@
/// Defines NZB xml elements and attributes.
/// Based on Kristian Hellang's Nzb project https://github.com/khellang/Nzb.
///
-internal class NzbKeywords
+internal static class NzbKeywords
{
///
/// NZB document public identifier.
diff --git a/src/Usenet/Nzb/NzbParser.cs b/src/Usenet/Nzb/NzbParser.cs
index 8d63a3a..8fd2f60 100644
--- a/src/Usenet/Nzb/NzbParser.cs
+++ b/src/Usenet/Nzb/NzbParser.cs
@@ -1,5 +1,6 @@
using System.Text.RegularExpressions;
using System.Xml.Linq;
+using JetBrains.Annotations;
using Usenet.Exceptions;
using Usenet.Extensions;
using Usenet.Nntp.Models;
@@ -13,6 +14,7 @@ namespace Usenet.Nzb;
/// It takes an xml string as input and parses it into an instance of the class.
/// Based on Kristian Hellang's Nzb project https://github.com/khellang/Nzb.
///
+[PublicAPI]
public static class NzbParser
{
private static readonly Regex FileNameRegex = new("\"([^\"]*)\"", RegexOptions.Compiled);
@@ -131,7 +133,7 @@ private static NzbDocument ParseDocument(XDocument doc)
return new NzbDocument(metaData, files);
}
- private static MultiValueDictionary? GetMetaData(
+ private static MultiValueDictionary GetMetaData(
NzbParserContext context,
XContainer nzbElement
)
@@ -139,7 +141,7 @@ XContainer nzbElement
var headElement = nzbElement.Element(context.Namespace + NzbKeywords.Head);
if (headElement == null)
{
- return null;
+ return [];
}
var headers =
@@ -236,15 +238,10 @@ XContainer segmentsElement
private static NzbSegment GetSegment(XElement element, long offset)
{
if (!int.TryParse((string?)element.Attribute(NzbKeywords.Number), out var number))
- {
throw new InvalidNzbDataException(Resources.Nzb.InvalidOrMissingNumberAttribute);
- }
-
- if (!long.TryParse((string?)element.Attribute(NzbKeywords.Bytes), out var size))
- {
- throw new InvalidNzbDataException(Resources.Nzb.InvalidOrMissingBytesAttribute);
- }
- return new NzbSegment(number, offset, size, element.Value);
+ return !long.TryParse((string?)element.Attribute(NzbKeywords.Bytes), out var size)
+ ? throw new InvalidNzbDataException(Resources.Nzb.InvalidOrMissingBytesAttribute)
+ : new NzbSegment(number, offset, size, element.Value);
}
}
diff --git a/src/Usenet/Nzb/NzbSegment.cs b/src/Usenet/Nzb/NzbSegment.cs
index ec9f67e..a4dc6e2 100644
--- a/src/Usenet/Nzb/NzbSegment.cs
+++ b/src/Usenet/Nzb/NzbSegment.cs
@@ -1,3 +1,4 @@
+using JetBrains.Annotations;
using Usenet.Nntp.Models;
using Usenet.Util;
using HashCode = Usenet.Util.HashCode;
@@ -8,6 +9,7 @@ namespace Usenet.Nzb;
/// Represents a segment of a file in a NZB document.
/// Based on Kristian Hellang's Nzb project https://github.com/khellang/Nzb.
///
+[PublicAPI]
public class NzbSegment : IEquatable
{
///
@@ -38,12 +40,12 @@ public class NzbSegment : IEquatable
/// Offset of the segment in the file.
/// Size of the article, in bytes, as a number, with no comma separation.
/// The Message-ID of this article.
- public NzbSegment(int number, long offset, long size, NntpMessageId messageId)
+ internal NzbSegment(int number, long offset, long size, NntpMessageId messageId)
{
Number = number;
Offset = offset;
Size = size;
- MessageId = messageId ?? NntpMessageId.Empty;
+ MessageId = messageId;
}
///
diff --git a/src/Usenet/Nzb/NzbWriter.cs b/src/Usenet/Nzb/NzbWriter.cs
index 43678a7..11d645d 100644
--- a/src/Usenet/Nzb/NzbWriter.cs
+++ b/src/Usenet/Nzb/NzbWriter.cs
@@ -1,5 +1,6 @@
using System.Globalization;
using System.Xml;
+using JetBrains.Annotations;
using Usenet.Util;
namespace Usenet.Nzb;
@@ -7,6 +8,7 @@ namespace Usenet.Nzb;
///
/// Represents an NZB document writer.
///
+[PublicAPI]
public class NzbWriter
{
private readonly TextWriter _textWriter;
diff --git a/src/Usenet/Nzb/TextWriterExtensions.cs b/src/Usenet/Nzb/TextWriterExtensions.cs
index fe51c85..cd4c44c 100644
--- a/src/Usenet/Nzb/TextWriterExtensions.cs
+++ b/src/Usenet/Nzb/TextWriterExtensions.cs
@@ -1,8 +1,11 @@
+using JetBrains.Annotations;
+
namespace Usenet.Nzb;
///
/// TextWriter extension methods.
///
+[PublicAPI]
public static class TextWriterExtensions
{
///
@@ -12,7 +15,7 @@ public static class TextWriterExtensions
/// The to write.
/// A that can be awaited.
public static Task WriteNzbDocumentAsync(this TextWriter textWriter, NzbDocument nzbDocument) =>
- WriteNzbDocumentAsync(textWriter, nzbDocument, CancellationToken.None);
+ textWriter.WriteNzbDocumentAsync(nzbDocument, CancellationToken.None);
///
/// Writes the specified asynchronously to the stream.
diff --git a/src/Usenet/PublicAPI.Shipped.txt b/src/Usenet/PublicAPI.Shipped.txt
index a2c0805..a4c3fee 100644
--- a/src/Usenet/PublicAPI.Shipped.txt
+++ b/src/Usenet/PublicAPI.Shipped.txt
@@ -329,12 +329,10 @@ Usenet.Nntp.Models.NntpArticle.Equals(Usenet.Nntp.Models.NntpArticle? other) ->
Usenet.Nntp.Models.NntpArticle.Groups.get -> Usenet.Nntp.Models.NntpGroups!
Usenet.Nntp.Models.NntpArticle.Headers.get -> System.Collections.Immutable.ImmutableDictionary!>!
Usenet.Nntp.Models.NntpArticle.MessageId.get -> Usenet.Nntp.Models.NntpMessageId!
-Usenet.Nntp.Models.NntpArticle.NntpArticle(long number, Usenet.Nntp.Models.NntpMessageId? messageId, Usenet.Nntp.Models.NntpGroups? groups, System.Collections.Generic.IDictionary!>? headers, System.Collections.Generic.IList? body) -> void
Usenet.Nntp.Models.NntpArticle.Number.get -> long
Usenet.Nntp.Models.NntpArticleRange
Usenet.Nntp.Models.NntpArticleRange.Equals(Usenet.Nntp.Models.NntpArticleRange? other) -> bool
Usenet.Nntp.Models.NntpArticleRange.From.get -> long
-Usenet.Nntp.Models.NntpArticleRange.NntpArticleRange(long from, long? to) -> void
Usenet.Nntp.Models.NntpArticleRange.To.get -> long?
Usenet.Nntp.Models.NntpDateTime
Usenet.Nntp.Models.NntpDateTime.Equals(Usenet.Nntp.Models.NntpDateTime? other) -> bool
@@ -348,7 +346,6 @@ Usenet.Nntp.Models.NntpGroup.Equals(Usenet.Nntp.Models.NntpGroup? other) -> bool
Usenet.Nntp.Models.NntpGroup.HighWaterMark.get -> long
Usenet.Nntp.Models.NntpGroup.LowWaterMark.get -> long
Usenet.Nntp.Models.NntpGroup.Name.get -> string!
-Usenet.Nntp.Models.NntpGroup.NntpGroup(string! name, long articleCount, long lowWaterMark, long highWaterMark, Usenet.Nntp.Models.NntpPostingStatus postingStatus, string! otherGroup, System.Collections.Immutable.IImmutableList! articleNumbers) -> void
Usenet.Nntp.Models.NntpGroup.OtherGroup.get -> string!
Usenet.Nntp.Models.NntpGroup.PostingStatus.get -> Usenet.Nntp.Models.NntpPostingStatus
Usenet.Nntp.Models.NntpGroupOrigin
@@ -356,13 +353,10 @@ Usenet.Nntp.Models.NntpGroupOrigin.CreatedAt.get -> System.DateTimeOffset
Usenet.Nntp.Models.NntpGroupOrigin.CreatedBy.get -> string!
Usenet.Nntp.Models.NntpGroupOrigin.Equals(Usenet.Nntp.Models.NntpGroupOrigin? other) -> bool
Usenet.Nntp.Models.NntpGroupOrigin.Name.get -> string!
-Usenet.Nntp.Models.NntpGroupOrigin.NntpGroupOrigin(string! name, System.DateTimeOffset createdAt, string! createdBy) -> void
Usenet.Nntp.Models.NntpGroups
Usenet.Nntp.Models.NntpGroups.Equals(Usenet.Nntp.Models.NntpGroups? other) -> bool
Usenet.Nntp.Models.NntpGroups.GetEnumerator() -> System.Collections.Generic.IEnumerator!
Usenet.Nntp.Models.NntpGroups.IsEmpty.get -> bool
-Usenet.Nntp.Models.NntpGroups.NntpGroups(string! groups) -> void
-Usenet.Nntp.Models.NntpGroups.NntpGroups(System.Collections.Generic.IEnumerable! groups) -> void
Usenet.Nntp.Models.NntpMessageId
Usenet.Nntp.Models.NntpMessageId.Equals(Usenet.Nntp.Models.NntpMessageId? other) -> bool
Usenet.Nntp.Models.NntpMessageId.HasValue.get -> bool
@@ -545,22 +539,16 @@ Usenet.Nntp.Parsers.IResponseParser.IsSuccessResponse(int code) -> bo
Usenet.Nntp.Parsers.IResponseParser.Parse(int code, string! message) -> TResponse
Usenet.Nntp.Responses.NntpArticleResponse
Usenet.Nntp.Responses.NntpArticleResponse.Article.get -> Usenet.Nntp.Models.NntpArticle?
-Usenet.Nntp.Responses.NntpArticleResponse.NntpArticleResponse(int code, string! message, bool success, Usenet.Nntp.Models.NntpArticle? article) -> void
Usenet.Nntp.Responses.NntpDateResponse
Usenet.Nntp.Responses.NntpDateResponse.DateTime.get -> System.DateTimeOffset
-Usenet.Nntp.Responses.NntpDateResponse.NntpDateResponse(int code, string! message, bool success, System.DateTimeOffset dateTime) -> void
Usenet.Nntp.Responses.NntpGroupOriginsResponse
Usenet.Nntp.Responses.NntpGroupOriginsResponse.GroupOrigins.get -> System.Collections.Immutable.IImmutableList!
-Usenet.Nntp.Responses.NntpGroupOriginsResponse.NntpGroupOriginsResponse(int code, string! message, bool success, System.Collections.Generic.IList! groupOrigins) -> void
Usenet.Nntp.Responses.NntpGroupResponse
Usenet.Nntp.Responses.NntpGroupResponse.Group.get -> Usenet.Nntp.Models.NntpGroup!
-Usenet.Nntp.Responses.NntpGroupResponse.NntpGroupResponse(int code, string! message, bool success, Usenet.Nntp.Models.NntpGroup! group) -> void
Usenet.Nntp.Responses.NntpGroupsResponse
Usenet.Nntp.Responses.NntpGroupsResponse.Groups.get -> System.Collections.Immutable.IImmutableList!
-Usenet.Nntp.Responses.NntpGroupsResponse.NntpGroupsResponse(int code, string! message, bool success, System.Collections.Generic.IList! groups) -> void
Usenet.Nntp.Responses.NntpLastResponse
Usenet.Nntp.Responses.NntpLastResponse.MessageId.get -> Usenet.Nntp.Models.NntpMessageId!
-Usenet.Nntp.Responses.NntpLastResponse.NntpLastResponse(int code, string! message, bool success, Usenet.Nntp.Responses.NntpLastResponseType responseType, long number, Usenet.Nntp.Models.NntpMessageId! messageId) -> void
Usenet.Nntp.Responses.NntpLastResponse.Number.get -> long
Usenet.Nntp.Responses.NntpLastResponse.ResponseType.get -> Usenet.Nntp.Responses.NntpLastResponseType
Usenet.Nntp.Responses.NntpLastResponseType
@@ -570,7 +558,6 @@ Usenet.Nntp.Responses.NntpLastResponseType.NoGroupSelected = 412 -> Usenet.Nntp.
Usenet.Nntp.Responses.NntpLastResponseType.NoPreviousArticleInGroup = 422 -> Usenet.Nntp.Responses.NntpLastResponseType
Usenet.Nntp.Responses.NntpLastResponseType.Unknown = 0 -> Usenet.Nntp.Responses.NntpLastResponseType
Usenet.Nntp.Responses.NntpModeReaderResponse
-Usenet.Nntp.Responses.NntpModeReaderResponse.NntpModeReaderResponse(int code, string! message, bool success, Usenet.Nntp.Responses.NntpModeReaderResponseType responseType) -> void
Usenet.Nntp.Responses.NntpModeReaderResponse.ResponseType.get -> Usenet.Nntp.Responses.NntpModeReaderResponseType
Usenet.Nntp.Responses.NntpModeReaderResponseType
Usenet.Nntp.Responses.NntpModeReaderResponseType.PostingAllowed = 200 -> Usenet.Nntp.Responses.NntpModeReaderResponseType
@@ -579,10 +566,8 @@ Usenet.Nntp.Responses.NntpModeReaderResponseType.ReadingServiceUnavailable = 502
Usenet.Nntp.Responses.NntpModeReaderResponseType.Unknown = 0 -> Usenet.Nntp.Responses.NntpModeReaderResponseType
Usenet.Nntp.Responses.NntpMultiLineResponse
Usenet.Nntp.Responses.NntpMultiLineResponse.Lines.get -> System.Collections.Immutable.IImmutableList!
-Usenet.Nntp.Responses.NntpMultiLineResponse.NntpMultiLineResponse(int code, string! message, bool success, System.Collections.Generic.IEnumerable! lines) -> void
Usenet.Nntp.Responses.NntpNextResponse
Usenet.Nntp.Responses.NntpNextResponse.MessageId.get -> Usenet.Nntp.Models.NntpMessageId!
-Usenet.Nntp.Responses.NntpNextResponse.NntpNextResponse(int code, string! message, bool success, Usenet.Nntp.Responses.NntpNextResponseType responseType, long number, Usenet.Nntp.Models.NntpMessageId! messageId) -> void
Usenet.Nntp.Responses.NntpNextResponse.Number.get -> long
Usenet.Nntp.Responses.NntpNextResponse.ResponseType.get -> Usenet.Nntp.Responses.NntpNextResponseType
Usenet.Nntp.Responses.NntpNextResponseType
@@ -594,11 +579,9 @@ Usenet.Nntp.Responses.NntpNextResponseType.Unknown = 0 -> Usenet.Nntp.Responses.
Usenet.Nntp.Responses.NntpResponse
Usenet.Nntp.Responses.NntpResponse.Code.get -> int
Usenet.Nntp.Responses.NntpResponse.Message.get -> string!
-Usenet.Nntp.Responses.NntpResponse.NntpResponse(int code, string! message, bool success) -> void
Usenet.Nntp.Responses.NntpResponse.Success.get -> bool
Usenet.Nntp.Responses.NntpStatResponse
Usenet.Nntp.Responses.NntpStatResponse.MessageId.get -> Usenet.Nntp.Models.NntpMessageId!
-Usenet.Nntp.Responses.NntpStatResponse.NntpStatResponse(int code, string! message, bool success, Usenet.Nntp.Responses.NntpStatResponseType responseType, long number, Usenet.Nntp.Models.NntpMessageId! messageId) -> void
Usenet.Nntp.Responses.NntpStatResponse.Number.get -> long
Usenet.Nntp.Responses.NntpStatResponse.ResponseType.get -> Usenet.Nntp.Responses.NntpStatResponseType
Usenet.Nntp.Responses.NntpStatResponseType
@@ -621,14 +604,12 @@ Usenet.Nzb.NzbDocument
Usenet.Nzb.NzbDocument.Equals(Usenet.Nzb.NzbDocument? other) -> bool
Usenet.Nzb.NzbDocument.Files.get -> System.Collections.Immutable.ImmutableList!
Usenet.Nzb.NzbDocument.MetaData.get -> System.Collections.Immutable.ImmutableDictionary!>!
-Usenet.Nzb.NzbDocument.NzbDocument(System.Collections.Generic.IDictionary!>? metaData, System.Collections.Generic.IEnumerable? files) -> void
Usenet.Nzb.NzbDocument.Size.get -> long
Usenet.Nzb.NzbFile
Usenet.Nzb.NzbFile.Date.get -> System.DateTimeOffset
Usenet.Nzb.NzbFile.Equals(Usenet.Nzb.NzbFile? other) -> bool
Usenet.Nzb.NzbFile.FileName.get -> string!
Usenet.Nzb.NzbFile.Groups.get -> Usenet.Nntp.Models.NntpGroups!
-Usenet.Nzb.NzbFile.NzbFile(string! poster, string! subject, string! fileName, System.DateTimeOffset date, Usenet.Nntp.Models.NntpGroups! groups, System.Collections.Generic.IEnumerable! segments) -> void
Usenet.Nzb.NzbFile.Poster.get -> string!
Usenet.Nzb.NzbFile.Segments.get -> System.Collections.Immutable.ImmutableList!
Usenet.Nzb.NzbFile.Size.get -> long
@@ -638,7 +619,6 @@ Usenet.Nzb.NzbSegment
Usenet.Nzb.NzbSegment.Equals(Usenet.Nzb.NzbSegment? other) -> bool
Usenet.Nzb.NzbSegment.MessageId.get -> Usenet.Nntp.Models.NntpMessageId!
Usenet.Nzb.NzbSegment.Number.get -> int
-Usenet.Nzb.NzbSegment.NzbSegment(int number, long offset, long size, Usenet.Nntp.Models.NntpMessageId! messageId) -> void
Usenet.Nzb.NzbSegment.Offset.get -> long
Usenet.Nzb.NzbSegment.Size.get -> long
Usenet.Nzb.NzbWriter
@@ -660,11 +640,9 @@ Usenet.Util.ValidationFailure
Usenet.Util.ValidationFailure.Code.get -> string!
Usenet.Util.ValidationFailure.Data.get -> object?
Usenet.Util.ValidationFailure.Message.get -> string!
-Usenet.Util.ValidationFailure.ValidationFailure(string! code, string! message, object? data = null) -> void
Usenet.Util.ValidationResult
-Usenet.Util.ValidationResult.Failures.get -> System.Collections.Generic.IList!
+Usenet.Util.ValidationResult.Failures.get -> System.Collections.Generic.IReadOnlyList!
Usenet.Util.ValidationResult.IsValid.get -> bool
-Usenet.Util.ValidationResult.ValidationResult(System.Collections.Generic.IList! failures) -> void
Usenet.Yenc.YencArticle
Usenet.Yenc.YencArticle.Data.get -> System.Collections.Generic.IReadOnlyList!
Usenet.Yenc.YencArticle.Footer.get -> Usenet.Yenc.YencFooter?
diff --git a/src/Usenet/Usenet.csproj b/src/Usenet/Usenet.csproj
index 2ccf518..2a9cdcc 100644
--- a/src/Usenet/Usenet.csproj
+++ b/src/Usenet/Usenet.csproj
@@ -25,6 +25,7 @@
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -42,6 +43,7 @@
Include="System.Linq.Async"
Condition="'$(TargetFramework)' == 'netstandard2.0' Or '$(TargetFramework)' == 'netstandard2.1'"
/>
+
diff --git a/src/Usenet/Util/AbstractBaseStream.cs b/src/Usenet/Util/AbstractBaseStream.cs
index 70110df..0fabce8 100644
--- a/src/Usenet/Util/AbstractBaseStream.cs
+++ b/src/Usenet/Util/AbstractBaseStream.cs
@@ -1,9 +1,12 @@
-namespace Usenet.Util;
+using JetBrains.Annotations;
+
+namespace Usenet.Util;
///
/// Represents an abstract base stream that overrides all abstract methods of the class.
/// Derived classes only need to override the methods they need.
///
+[PublicAPI]
public abstract class AbstractBaseStream : Stream
{
///
diff --git a/src/Usenet/Util/Compatibility/ObjectDisposedExceptionShims.cs b/src/Usenet/Util/Compatibility/ObjectDisposedExceptionShims.cs
index 26eaa78..159b07b 100644
--- a/src/Usenet/Util/Compatibility/ObjectDisposedExceptionShims.cs
+++ b/src/Usenet/Util/Compatibility/ObjectDisposedExceptionShims.cs
@@ -8,7 +8,7 @@ public static void ThrowIf(bool condition, object instance)
ObjectDisposedException.ThrowIf(condition, instance);
#else
if (condition)
- throw new ObjectDisposedException(instance?.GetType().FullName);
+ throw new ObjectDisposedException(instance.GetType().FullName);
#endif
}
}
diff --git a/src/Usenet/Util/CountingStream.cs b/src/Usenet/Util/CountingStream.cs
index ff53e58..a3ffeb9 100644
--- a/src/Usenet/Util/CountingStream.cs
+++ b/src/Usenet/Util/CountingStream.cs
@@ -1,8 +1,11 @@
-namespace Usenet.Util;
+using JetBrains.Annotations;
+
+namespace Usenet.Util;
///
/// Represents a counting stream. It can be used to count the number of bytes read and written.
///
+[PublicAPI]
public class CountingStream : AbstractBaseStream
{
private readonly Stream _innerStream;
diff --git a/src/Usenet/Util/Crc32.cs b/src/Usenet/Util/Crc32.cs
index adff791..5a1c50d 100644
--- a/src/Usenet/Util/Crc32.cs
+++ b/src/Usenet/Util/Crc32.cs
@@ -14,11 +14,10 @@ public static uint CalculateChecksum(IEnumerable buffer)
{
Guard.ThrowIfNull(buffer);
- var value = Seed;
- foreach (var b in buffer)
- {
- value = (value >> 8) ^ LookupTable[(value & 0xFF) ^ b];
- }
+ var value = buffer.Aggregate(
+ Seed,
+ (current, b) => (current >> 8) ^ LookupTable[(current & 0xFF) ^ b]
+ );
return value ^ Seed;
}
diff --git a/src/Usenet/Util/EnumerableStream.cs b/src/Usenet/Util/EnumerableStream.cs
index 4aa12dc..31076ed 100644
--- a/src/Usenet/Util/EnumerableStream.cs
+++ b/src/Usenet/Util/EnumerableStream.cs
@@ -1,10 +1,13 @@
-namespace Usenet.Util;
+using JetBrains.Annotations;
+
+namespace Usenet.Util;
///
/// Represents an enumerable stream. Can be used to stream an enumerable collection of
/// byte buffers.
///
-public class EnumerableStream : AbstractBaseStream
+[PublicAPI]
+public abstract class EnumerableStream : AbstractBaseStream
{
private readonly IEnumerator _enumerator;
private byte[]? _currentChunk;
@@ -14,7 +17,7 @@ public class EnumerableStream : AbstractBaseStream
/// Creates a new instance of the class.
///
/// An enumerable collection of byte buffers.
- public EnumerableStream(IEnumerable input)
+ protected EnumerableStream(IEnumerable input)
{
Guard.ThrowIfNull(input);
_enumerator = input.GetEnumerator();
@@ -26,9 +29,7 @@ protected override void Dispose(bool disposing)
try
{
if (disposing)
- {
- _enumerator?.Dispose();
- }
+ _enumerator.Dispose();
}
finally
{
diff --git a/src/Usenet/Util/Guard.cs b/src/Usenet/Util/Guard.cs
index a6386c9..0097193 100644
--- a/src/Usenet/Util/Guard.cs
+++ b/src/Usenet/Util/Guard.cs
@@ -36,7 +36,7 @@ public static void ThrowIfNull(
/// The name of the string
/// ArgumentNullException
/// ArgumentException
- public static void ThrowIfNullOrEmpty([NotNull] string str, string name)
+ public static void ThrowIfNullOrEmpty(string str, string name)
{
#if NET8_0_OR_GREATER
ArgumentException.ThrowIfNullOrEmpty(str, name);
@@ -55,7 +55,7 @@ public static void ThrowIfNullOrEmpty([NotNull] string str, string name)
/// The name of the string
/// ArgumentNullException
/// ArgumentException
- public static void ThrowIfNullOrWhiteSpace([NotNull] string str, string name)
+ public static void ThrowIfNullOrWhiteSpace(string str, string name)
{
#if NET8_0_OR_GREATER
ArgumentException.ThrowIfNullOrWhiteSpace(str, name);
diff --git a/src/Usenet/Util/HashCode.cs b/src/Usenet/Util/HashCode.cs
index 9f3a9fc..39cee8a 100644
--- a/src/Usenet/Util/HashCode.cs
+++ b/src/Usenet/Util/HashCode.cs
@@ -30,7 +30,7 @@ public static int Hash(this int hash, T? obj) =>
/// The collection.
/// A 32-bit signed integer hash code.
public static int Hash(this int hash, IEnumerable collection) =>
- collection?.Aggregate(hash, Hash) ?? hash;
+ collection.Aggregate(hash, Hash);
///
/// Combine the current hash code with the combined hash codes of all the keys and values in the
@@ -43,6 +43,5 @@ public static int Hash(this int hash, IEnumerable collection) =>
/// The dictionary.
///
public static int Hash(this int hash, IDictionary dictionary) =>
- dictionary?.Aggregate(hash, (current, pair) => current.Hash(pair.Key).Hash(pair.Value))
- ?? hash;
+ dictionary.Aggregate(hash, (current, pair) => current.Hash(pair.Key).Hash(pair.Value));
}
diff --git a/src/Usenet/Util/MultiSetComparer.cs b/src/Usenet/Util/MultiSetComparer.cs
index 445e410..2121b49 100644
--- a/src/Usenet/Util/MultiSetComparer.cs
+++ b/src/Usenet/Util/MultiSetComparer.cs
@@ -16,16 +16,13 @@ internal class MultiSetComparer : IEqualityComparer>
/// using the specified .
///
/// The equality comparer to use.
- public MultiSetComparer(IEqualityComparer comparer)
- {
- _comparer = comparer ?? EqualityComparer.Default;
- }
+ private MultiSetComparer(IEqualityComparer comparer) => _comparer = comparer;
///
/// Creates a new instance of the class
/// using the default for the type specified by the generic argument.
///
- public MultiSetComparer()
+ private MultiSetComparer()
: this(EqualityComparer.Default) { }
///
diff --git a/src/Usenet/Util/MultiValueDictionary.cs b/src/Usenet/Util/MultiValueDictionary.cs
index 4db3a9e..752da52 100644
--- a/src/Usenet/Util/MultiValueDictionary.cs
+++ b/src/Usenet/Util/MultiValueDictionary.cs
@@ -60,7 +60,7 @@ IEqualityComparer keyComparer
/// The value of the element to add.
public virtual void Add(TKey key, TValue value)
{
- if (!TryGetValue(key, out var values) || values == null)
+ if (!TryGetValue(key, out var values))
{
values = _collectionFactory();
Add(key, values);
@@ -77,7 +77,7 @@ public virtual void Add(TKey key, TValue value)
/// true if the element is successfully found and removed; otherwise, false.
public virtual bool Remove(TKey key, TValue value)
{
- if (!TryGetValue(key, out var values) || values == null)
+ if (!TryGetValue(key, out var values))
return false;
if (!values.Remove(value))
return false;
@@ -90,10 +90,7 @@ public virtual bool Remove(TKey key, TValue value)
/// Gets the number of elements contained in the .
/// The number of elements contained in the .
- public new int Count =>
- Values
- .Where(valueCollection => valueCollection != null)
- .Sum(valueCollection => valueCollection.Count);
+ public new int Count => Values.Sum(valueCollection => valueCollection.Count);
///
/// Represents an empty .
diff --git a/src/Usenet/Util/UsenetEncoding.cs b/src/Usenet/Util/UsenetEncoding.cs
index 984dfc7..4c5acfc 100644
--- a/src/Usenet/Util/UsenetEncoding.cs
+++ b/src/Usenet/Util/UsenetEncoding.cs
@@ -1,10 +1,12 @@
using System.Text;
+using JetBrains.Annotations;
namespace Usenet.Util;
///
/// This class defines the default usenet character encoding.
///
+[PublicAPI]
public static class UsenetEncoding
{
///
diff --git a/src/Usenet/Util/ValidationFailure.cs b/src/Usenet/Util/ValidationFailure.cs
index 25ecc86..9a94db4 100644
--- a/src/Usenet/Util/ValidationFailure.cs
+++ b/src/Usenet/Util/ValidationFailure.cs
@@ -1,10 +1,12 @@
-using Usenet.Extensions;
+using JetBrains.Annotations;
+using Usenet.Extensions;
namespace Usenet.Util;
///
/// Represents a validation failure.
///
+[PublicAPI]
public class ValidationFailure
{
///
@@ -28,7 +30,7 @@ public class ValidationFailure
/// A code associated with the validation failure.
/// A message describing the validation failure.
/// A data object containing information about the validation failure.
- public ValidationFailure(string code, string message, object? data = null)
+ internal ValidationFailure(string code, string message, object? data = null)
{
Code = code.ThrowIfNullOrWhiteSpace(nameof(code));
Message = message;
diff --git a/src/Usenet/Util/ValidationResult.cs b/src/Usenet/Util/ValidationResult.cs
index 26ee81e..59906ab 100644
--- a/src/Usenet/Util/ValidationResult.cs
+++ b/src/Usenet/Util/ValidationResult.cs
@@ -1,23 +1,23 @@
-namespace Usenet.Util;
+using JetBrains.Annotations;
+
+namespace Usenet.Util;
///
/// Represents a validation result.
///
+[PublicAPI]
public class ValidationResult
{
///
/// A collection of objects.
///
- public IList Failures { get; }
+ public IReadOnlyList Failures { get; }
///
/// Creates a new instance of the class.
///
/// A collection of objects.
- public ValidationResult(IList failures)
- {
- Failures = failures ?? new List(0);
- }
+ internal ValidationResult(IReadOnlyList failures) => Failures = failures;
///
/// A property indicating whether the validation result is valid or not.
diff --git a/src/Usenet/Yenc/YencArticle.cs b/src/Usenet/Yenc/YencArticle.cs
index 75ec43f..29decb1 100644
--- a/src/Usenet/Yenc/YencArticle.cs
+++ b/src/Usenet/Yenc/YencArticle.cs
@@ -1,4 +1,4 @@
-using Usenet.Extensions;
+using JetBrains.Annotations;
using Usenet.Util;
namespace Usenet.Yenc;
@@ -6,6 +6,7 @@ namespace Usenet.Yenc;
///
/// Represents a decoded yEnc-encoded article.
///
+[PublicAPI]
public class YencArticle
{
///
diff --git a/src/Usenet/Yenc/YencArticleDecoder.cs b/src/Usenet/Yenc/YencArticleDecoder.cs
index 6920d5c..fcc4202 100644
--- a/src/Usenet/Yenc/YencArticleDecoder.cs
+++ b/src/Usenet/Yenc/YencArticleDecoder.cs
@@ -1,4 +1,5 @@
using System.Text;
+using JetBrains.Annotations;
using Usenet.Extensions;
using Usenet.Util;
@@ -9,6 +10,7 @@ namespace Usenet.Yenc;
/// The article is completely decoded in memory.
/// Based on Kristian Hellang's yEnc project https://github.com/khellang/yEnc.
///
+[PublicAPI]
public static class YencArticleDecoder
{
private const string YEnd = YencKeywords.YEnd + " ";
diff --git a/src/Usenet/Yenc/YencEncoder.cs b/src/Usenet/Yenc/YencEncoder.cs
index 5282942..319e1f2 100644
--- a/src/Usenet/Yenc/YencEncoder.cs
+++ b/src/Usenet/Yenc/YencEncoder.cs
@@ -1,5 +1,6 @@
using System.Globalization;
using System.Text;
+using JetBrains.Annotations;
using Usenet.Extensions;
using Usenet.Util;
@@ -8,6 +9,7 @@ namespace Usenet.Yenc;
///
/// Represents an yEnc encoder.
///
+[PublicAPI]
public static class YencEncoder
{
///
@@ -68,9 +70,8 @@ CancellationToken cancellationToken
Guard.ThrowIfNull(stream);
Guard.ThrowIfNull(encoding);
- var lines = new List();
+ List lines = [GetHeaderLine(header)];
- lines.Add(GetHeaderLine(header));
if (header.IsFilePart)
{
lines.Add(GetPartHeaderLine(header));
diff --git a/src/Usenet/Yenc/YencFooter.cs b/src/Usenet/Yenc/YencFooter.cs
index 88b4576..a245732 100644
--- a/src/Usenet/Yenc/YencFooter.cs
+++ b/src/Usenet/Yenc/YencFooter.cs
@@ -1,9 +1,12 @@
-namespace Usenet.Yenc;
+using JetBrains.Annotations;
+
+namespace Usenet.Yenc;
///
/// Represents the yEnc footer (=yend) line.
/// Based on Kristian Hellang's yEnc project https://github.com/khellang/yEnc.
///
+[PublicAPI]
public class YencFooter
{
///
diff --git a/src/Usenet/Yenc/YencHeader.cs b/src/Usenet/Yenc/YencHeader.cs
index 126b4fc..fdf0ad7 100644
--- a/src/Usenet/Yenc/YencHeader.cs
+++ b/src/Usenet/Yenc/YencHeader.cs
@@ -1,10 +1,13 @@
-namespace Usenet.Yenc;
+using JetBrains.Annotations;
+
+namespace Usenet.Yenc;
///
/// Represents the combined information of the yEnc header (=ybegin) line
/// and the yEnc part header (=ypart) line if present.
/// Based on Kristian Hellang's yEnc project https://github.com/khellang/yEnc.
///
+[PublicAPI]
public class YencHeader
{
///
diff --git a/src/Usenet/Yenc/YencKeyWords.cs b/src/Usenet/Yenc/YencKeyWords.cs
index 6515f85..b8a0300 100644
--- a/src/Usenet/Yenc/YencKeyWords.cs
+++ b/src/Usenet/Yenc/YencKeyWords.cs
@@ -4,7 +4,7 @@
/// yEnc keywords
/// Based on Kristian Hellang's yEnc project https://github.com/khellang/yEnc.
///
-internal class YencKeywords
+internal static class YencKeywords
{
public const string YBegin = "=ybegin";
public const string YPart = "=ypart";
diff --git a/src/Usenet/Yenc/YencLineDecoder.cs b/src/Usenet/Yenc/YencLineDecoder.cs
index 5f55cb0..0a72c6c 100644
--- a/src/Usenet/Yenc/YencLineDecoder.cs
+++ b/src/Usenet/Yenc/YencLineDecoder.cs
@@ -4,12 +4,12 @@
/// yEnc line decoder.
/// Based on Kristian Hellang's yEnc project https://github.com/khellang/yEnc.
///
-internal class YencLineDecoder
+internal static class YencLineDecoder
{
public static int Decode(byte[] encodedBytes, byte[] decodedBytes, int decodedOffset) =>
Decode(encodedBytes, 0, encodedBytes.Length, decodedBytes, decodedOffset);
- public static int Decode(
+ private static int Decode(
byte[] encodedBytes,
int encodedOffset,
int encodedCount,
diff --git a/src/Usenet/Yenc/YencMeta.cs b/src/Usenet/Yenc/YencMeta.cs
index a5861e5..cd96a83 100644
--- a/src/Usenet/Yenc/YencMeta.cs
+++ b/src/Usenet/Yenc/YencMeta.cs
@@ -1,6 +1,8 @@
using Usenet.Exceptions;
using Usenet.Extensions;
+#if NETSTANDARD2_0
using Usenet.Util.Compatibility;
+#endif
namespace Usenet.Yenc;
@@ -8,7 +10,7 @@ namespace Usenet.Yenc;
/// Utiltiy class to retrieve yEnc metadata.
/// Based on Kristian Hellang's yEnc project https://github.com/khellang/yEnc.
///
-internal class YencMeta
+internal static class YencMeta
{
private const string YBegin = $"{YencKeywords.YBegin} ";
private const string YPart = $"{YencKeywords.YPart} ";
@@ -46,7 +48,9 @@ public static IDictionary GetPartHeaders(IEnumerator enu
if (
enumerator.MoveNext()
+#if NETSTANDARD2_0 || NETSTANDARD2_1
&& enumerator.Current != null
+#endif
&& enumerator.Current.StartsWith(YPart, StringComparison.Ordinal)
)
{
@@ -95,11 +99,6 @@ public static YencFooter ParseFooter(IDictionary footer)
public static Dictionary ParseLine(string line)
{
- if (line == null)
- {
- return new Dictionary(0);
- }
-
// name is always last item on the header line
var nameSplit = line.Split(NameSeparator, StringSplitOptions.RemoveEmptyEntries);
if (nameSplit.Length == 0)
diff --git a/src/Usenet/Yenc/YencStream.cs b/src/Usenet/Yenc/YencStream.cs
index 7044f74..efcb229 100644
--- a/src/Usenet/Yenc/YencStream.cs
+++ b/src/Usenet/Yenc/YencStream.cs
@@ -1,4 +1,5 @@
-using Usenet.Util;
+using JetBrains.Annotations;
+using Usenet.Util;
namespace Usenet.Yenc;
@@ -6,6 +7,7 @@ namespace Usenet.Yenc;
/// Represents a decoded yEnc-encoded article as a stream.
/// Based on Kristian Hellang's yEnc project https://github.com/khellang/yEnc.
///
+[PublicAPI]
public class YencStream : EnumerableStream
{
///
diff --git a/src/Usenet/Yenc/YencStreamDecoder.cs b/src/Usenet/Yenc/YencStreamDecoder.cs
index f65bb1d..3bd3143 100644
--- a/src/Usenet/Yenc/YencStreamDecoder.cs
+++ b/src/Usenet/Yenc/YencStreamDecoder.cs
@@ -1,4 +1,5 @@
using System.Text;
+using JetBrains.Annotations;
using Usenet.Extensions;
using Usenet.Util;
@@ -9,6 +10,7 @@ namespace Usenet.Yenc;
/// The article is decoded streaming.
/// Based on Kristian Hellang's yEnc project https://github.com/khellang/yEnc.
///
+[PublicAPI]
public static class YencStreamDecoder
{
private const string YEnd = YencKeywords.YEnd + " ";
diff --git a/src/Usenet/Yenc/YencValidationErrorCodes.cs b/src/Usenet/Yenc/YencValidationErrorCodes.cs
index fdaf6b0..941ac8a 100644
--- a/src/Usenet/Yenc/YencValidationErrorCodes.cs
+++ b/src/Usenet/Yenc/YencValidationErrorCodes.cs
@@ -4,7 +4,7 @@
/// yEnc validation error codes.
/// Based on Kristian Hellang's yEnc project https://github.com/khellang/yEnc.
///
-internal class YencValidationErrorCodes
+internal static class YencValidationErrorCodes
{
public const string MissingChecksum = "MissingChecksum";
public const string ChecksumMismatch = "ChecksumMismatch";
diff --git a/src/Usenet/Yenc/YencValidator.cs b/src/Usenet/Yenc/YencValidator.cs
index 0a1fdb9..8ca4550 100644
--- a/src/Usenet/Yenc/YencValidator.cs
+++ b/src/Usenet/Yenc/YencValidator.cs
@@ -1,3 +1,4 @@
+using JetBrains.Annotations;
using Usenet.Util;
namespace Usenet.Yenc;
@@ -6,6 +7,7 @@ namespace Usenet.Yenc;
/// Represents a yEnc-encoded article validator.
/// Based on Kristian Hellang's yEnc project https://github.com/khellang/yEnc.
///
+[PublicAPI]
public static class YencValidator
{
///
diff --git a/tests/Usenet.Tests/Nntp/Builders/NntpArticleBuilderTests.cs b/tests/Usenet.Tests/Nntp/Builders/NntpArticleBuilderTests.cs
index 0c1b2d5..4843e80 100644
--- a/tests/Usenet.Tests/Nntp/Builders/NntpArticleBuilderTests.cs
+++ b/tests/Usenet.Tests/Nntp/Builders/NntpArticleBuilderTests.cs
@@ -1,11 +1,10 @@
-using Usenet.Exceptions;
+using System.Diagnostics.CodeAnalysis;
+using Usenet.Exceptions;
using Usenet.Nntp;
using Usenet.Nntp.Builders;
using Usenet.Nntp.Models;
using Usenet.Util;
-// ReSharper disable DuplicateKeyCollectionInitialization
-
namespace Usenet.Tests.Nntp.Builders;
internal sealed class NntpArticleBuilderTests
@@ -142,6 +141,7 @@ string expectedParamName
}
[Test]
+ [SuppressMessage("ReSharper", "DuplicateKeyCollectionInitialization")]
public async Task BuildShouldBuildArticle()
{
var expected = new NntpArticle(
@@ -155,7 +155,7 @@ public async Task BuildShouldBuildArticle()
{ "Header1", "Value1" },
{ "Header1", "Value2" },
},
- null
+ []
);
var actual = new NntpArticleBuilder()
@@ -174,6 +174,7 @@ public async Task BuildShouldBuildArticle()
}
[Test]
+ [SuppressMessage("ReSharper", "DuplicateKeyCollectionInitialization")]
public async Task BuildInitializedFromExistingArticleShouldBuildSameArticle()
{
var expected = new NntpArticle(
@@ -187,7 +188,7 @@ public async Task BuildInitializedFromExistingArticleShouldBuildSameArticle()
{ "Header1", "Value1" },
{ "Header1", "Value2" },
},
- null
+ []
);
var actual = new NntpArticleBuilder().InitializeFrom(expected).Build();
diff --git a/tests/Usenet.Tests/Nntp/Models/NntpArticleTests.cs b/tests/Usenet.Tests/Nntp/Models/NntpArticleTests.cs
index 0f79951..5b64ac5 100644
--- a/tests/Usenet.Tests/Nntp/Models/NntpArticleTests.cs
+++ b/tests/Usenet.Tests/Nntp/Models/NntpArticleTests.cs
@@ -1,4 +1,5 @@
-using Usenet.Nntp.Models;
+using System.Diagnostics.CodeAnalysis;
+using Usenet.Nntp.Models;
using Usenet.Util;
namespace Usenet.Tests.Nntp.Models;
@@ -6,12 +7,13 @@ namespace Usenet.Tests.Nntp.Models;
internal sealed class NntpArticleTests
{
[Test]
+ [SuppressMessage("ReSharper", "DuplicateKeyCollectionInitialization")]
internal async Task EqualsWithSameValuesShouldReturnTrue()
{
var article1 = new NntpArticle(
0,
"123@bla.nl",
- null,
+ NntpGroups.Empty,
new MultiValueDictionary
{
{ "h1", "val1" },
@@ -25,7 +27,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue()
var article2 = new NntpArticle(
0,
"123@bla.nl",
- null,
+ NntpGroups.Empty,
new MultiValueDictionary
{
{ "h3", "val4" },
diff --git a/tests/Usenet.Tests/Nntp/Models/NntpGroupTests.cs b/tests/Usenet.Tests/Nntp/Models/NntpGroupTests.cs
index 25cc73e..a7741d8 100644
--- a/tests/Usenet.Tests/Nntp/Models/NntpGroupTests.cs
+++ b/tests/Usenet.Tests/Nntp/Models/NntpGroupTests.cs
@@ -7,10 +7,10 @@ namespace Usenet.Tests.Nntp.Models;
internal sealed class NntpGroupTests
{
public static IEnumerable<
- Func<(string, long, long, long, NntpPostingStatus, string?, long[]?)>
+ Func<(string, long, long, long, NntpPostingStatus, string, long[])>
> SerializationData()
{
- yield return () => ("test", 10, 2, 11, NntpPostingStatus.PostingPermitted, null, null);
+ yield return () => ("test", 10, 2, 11, NntpPostingStatus.PostingPermitted, "", []);
yield return () =>
("alt.rfc-writers.recovery", 0, 1, 4, NntpPostingStatus.PostingPermitted, "", []);
yield return () =>
@@ -29,8 +29,8 @@ public async Task SerializedInstanceShouldBeDeserializedCorrectly(
long lowWaterMark,
long highWaterMark,
NntpPostingStatus postingStatus,
- string? otherGroup,
- long[]? articleNumbers
+ string otherGroup,
+ long[] articleNumbers
)
{
var expected = new NntpGroup(
@@ -39,8 +39,8 @@ public async Task SerializedInstanceShouldBeDeserializedCorrectly(
lowWaterMark,
highWaterMark,
postingStatus,
- otherGroup!,
- articleNumbers?.ToImmutableList()!
+ otherGroup,
+ articleNumbers.ToImmutableList()
);
var json = JsonSerializer.Serialize(expected);
@@ -57,14 +57,22 @@ public async Task SerializedInstanceShouldBeDeserializedCorrectly(
1,
10,
NntpPostingStatus.PostingPermitted,
- null!,
+ string.Empty,
[1, 2, 3]
),
- new NntpGroup("group1", 10, 1, 10, NntpPostingStatus.PostingPermitted, null!, [1, 2, 3])
+ new NntpGroup(
+ "group1",
+ 10,
+ 1,
+ 10,
+ NntpPostingStatus.PostingPermitted,
+ string.Empty,
+ [1, 2, 3]
+ )
);
yield return (
- new NntpGroup("group1", 10, 1, 10, NntpPostingStatus.PostingPermitted, "other", null!),
- new NntpGroup("group1", 10, 1, 10, NntpPostingStatus.PostingPermitted, "other", null!)
+ new NntpGroup("group1", 10, 1, 10, NntpPostingStatus.PostingPermitted, "other", []),
+ new NntpGroup("group1", 10, 1, 10, NntpPostingStatus.PostingPermitted, "other", [])
);
}
@@ -207,7 +215,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NntpGroup group1, NntpG
"other",
[1, 2, 3]
),
- new NntpGroup("group1", 10, 1, 10, NntpPostingStatus.PostingPermitted, "other", null!)
+ new NntpGroup("group1", 10, 1, 10, NntpPostingStatus.PostingPermitted, "other", [])
);
}
diff --git a/tests/Usenet.Tests/Nntp/Parsers/ArticleResponseParserTests.cs b/tests/Usenet.Tests/Nntp/Parsers/ArticleResponseParserTests.cs
index 2a08af7..e4afe28 100644
--- a/tests/Usenet.Tests/Nntp/Parsers/ArticleResponseParserTests.cs
+++ b/tests/Usenet.Tests/Nntp/Parsers/ArticleResponseParserTests.cs
@@ -15,7 +15,13 @@ internal sealed class ArticleResponseParserTests
"123 <123@poster.com>",
(int)ArticleRequestType.Article,
[],
- new NntpArticle(123, "<123@poster.com>", null, null, new List(0))
+ new NntpArticle(
+ 123,
+ "<123@poster.com>",
+ NntpGroups.Empty,
+ MultiValueDictionary.EmptyIgnoreCase,
+ new List(0)
+ )
);
yield return () =>
@@ -33,7 +39,7 @@ internal sealed class ArticleResponseParserTests
new NntpArticle(
123,
"<123@poster.com>",
- null,
+ NntpGroups.Empty,
new MultiValueDictionary
{
{ "Path", "pathost!demo!whitehouse!not-for-mail" },
@@ -52,8 +58,8 @@ internal sealed class ArticleResponseParserTests
new NntpArticle(
123,
"<123@poster.com>",
- null,
- null,
+ NntpGroups.Empty,
+ MultiValueDictionary.EmptyIgnoreCase,
new List { "This is just a test article (2).", "With two lines." }
)
);
@@ -67,7 +73,7 @@ internal sealed class ArticleResponseParserTests
new NntpArticle(
123,
"<123@poster.com>",
- null,
+ NntpGroups.Empty,
new MultiValueDictionary
{
{ "Multi", "line1 line2 line3" },
@@ -86,7 +92,7 @@ internal sealed class ArticleResponseParserTests
new NntpArticle(
123,
"<123@poster.com>",
- null,
+ NntpGroups.Empty,
new MultiValueDictionary
{
{ "Path", "pathost!demo!whitehouse!not-for-mail" },
diff --git a/tests/Usenet.Tests/Nntp/Parsers/GroupsResponseParserTests.cs b/tests/Usenet.Tests/Nntp/Parsers/GroupsResponseParserTests.cs
index 27cad01..18b93e0 100644
--- a/tests/Usenet.Tests/Nntp/Parsers/GroupsResponseParserTests.cs
+++ b/tests/Usenet.Tests/Nntp/Parsers/GroupsResponseParserTests.cs
@@ -17,7 +17,7 @@ public static IEnumerable<
(int)GroupStatusRequestType.Basic,
["alt.rfc-writers.recovery 4 1 y", "tx.natives.recovery 89 56 y"],
[
- new(
+ new NntpGroup(
"alt.rfc-writers.recovery",
0,
1,
@@ -26,7 +26,7 @@ public static IEnumerable<
string.Empty,
[]
),
- new(
+ new NntpGroup(
"tx.natives.recovery",
0,
56,
@@ -49,7 +49,7 @@ public static IEnumerable<
(int)GroupStatusRequestType.Extended,
["misc.test 3002322 3000234 1234 y", "rec.food.drink.tea 100 51 3 y"],
[
- new(
+ new NntpGroup(
"misc.test",
1234,
3000234,
@@ -58,7 +58,7 @@ public static IEnumerable<
string.Empty,
[]
),
- new(
+ new NntpGroup(
"rec.food.drink.tea",
3,
51,
diff --git a/tests/Usenet.Tests/Nntp/Pooling/NntpClientPoolTests.cs b/tests/Usenet.Tests/Nntp/Pooling/NntpClientPoolTests.cs
index e9dbab1..34d4485 100644
--- a/tests/Usenet.Tests/Nntp/Pooling/NntpClientPoolTests.cs
+++ b/tests/Usenet.Tests/Nntp/Pooling/NntpClientPoolTests.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics.CodeAnalysis;
using NSubstitute;
using Usenet.Nntp;
using Usenet.Nntp.Contracts;
@@ -20,6 +21,7 @@ await Assert
}
[Test]
+ [SuppressMessage("ReSharper", "AccessToDisposedClosure")]
public async Task AllClientsBorrowed(CancellationToken cancellationToken)
{
using var pool = new NntpClientPool(
@@ -36,11 +38,11 @@ public async Task AllClientsBorrowed(CancellationToken cancellationToken)
};
// Get the first lease, this should succeed
- await pool.GetLease(cancellationToken).ConfigureAwait(true);
+ await pool.GetLease(cancellationToken);
// Get the second lease, should throw because the client does not become available again in time
await Assert
- .That(async () => await pool.GetLease(cancellationToken).ConfigureAwait(true))
+ .That(async () => await pool.GetLease(cancellationToken))
.ThrowsExactly();
}
@@ -61,15 +63,16 @@ public async Task ClientAvailable(CancellationToken cancellationToken)
};
// Get the first lease, this should succeed
- var lease1 = await pool.GetLease(cancellationToken).ConfigureAwait(true);
+ var lease1 = await pool.GetLease(cancellationToken);
lease1.Dispose();
// Get the second lease, this should succeed because the first client was returned to the pool
- var lease2 = await pool.GetLease(cancellationToken).ConfigureAwait(true);
+ var lease2 = await pool.GetLease(cancellationToken);
lease2.Dispose();
}
[Test]
+ [SuppressMessage("ReSharper", "AccessToDisposedClosure")]
public async Task DisposeClientAfterError(CancellationToken cancellationToken)
{
using var server = new TestNntpServer();
@@ -86,18 +89,14 @@ public async Task DisposeClientAfterError(CancellationToken cancellationToken)
};
// Get the first lease
- var lease1 = await pool.GetLease(cancellationToken).ConfigureAwait(true);
+ var lease1 = await pool.GetLease(cancellationToken);
var client1 = lease1.Client;
try
{
// Group command triggers disconnect on server side - throws IOException when connection is reset
// or NntpException when no response is received
await Assert
- .That(async () =>
- await lease1
- .Client.GroupAsync("some.group", cancellationToken)
- .ConfigureAwait(true)
- )
+ .That(async () => await lease1.Client.GroupAsync("some.group", cancellationToken))
.ThrowsException();
}
finally
@@ -107,16 +106,14 @@ await lease1
// The client should be disposed after the disconnect
await Assert
- .That(async () =>
- await client1.ArticleAsync("123", cancellationToken).ConfigureAwait(true)
- )
+ .That(async () => await client1.ArticleAsync("123", cancellationToken))
.ThrowsExactly();
// Get the second lease
// This should return a new client
- var lease2 = await pool.GetLease(cancellationToken).ConfigureAwait(true);
+ var lease2 = await pool.GetLease(cancellationToken);
var client2 = lease2.Client;
- await lease2.Client.ArticleAsync("123", cancellationToken).ConfigureAwait(true);
+ await lease2.Client.ArticleAsync("123", cancellationToken);
lease2.Dispose();
await Assert.That(client2).IsNotEqualTo(client1);
diff --git a/tests/Usenet.Tests/Nntp/Writers/ArticleWriterTests.cs b/tests/Usenet.Tests/Nntp/Writers/ArticleWriterTests.cs
index a9e7fad..72e5869 100644
--- a/tests/Usenet.Tests/Nntp/Writers/ArticleWriterTests.cs
+++ b/tests/Usenet.Tests/Nntp/Writers/ArticleWriterTests.cs
@@ -12,13 +12,25 @@ internal sealed class ArticleWriterTests
{
yield return () =>
(
- new NntpArticle(0, "1@example.com", "group", null, new List(0)),
+ new NntpArticle(
+ 0,
+ "1@example.com",
+ "group",
+ MultiValueDictionary.EmptyIgnoreCase,
+ new List(0)
+ ),
["Message-ID: <1@example.com>", "Newsgroups: group", "", "."]
);
yield return () =>
(
- new NntpArticle(0, "<2@example.com>", "group", null, new List(0)),
+ new NntpArticle(
+ 0,
+ "<2@example.com>",
+ "group",
+ MultiValueDictionary.EmptyIgnoreCase,
+ new List(0)
+ ),
["Message-ID: <2@example.com>", "Newsgroups: group", "", "."]
);
@@ -96,7 +108,7 @@ CancellationToken cancellationToken
)
{
using var connection = new MockConnection();
- await ArticleWriter.WriteAsync(connection, article, cancellationToken).ConfigureAwait(true);
+ await ArticleWriter.WriteAsync(connection, article, cancellationToken);
await Assert.That(connection.GetLines()).IsEquivalentTo(expectedLines);
}
}
diff --git a/tests/Usenet.Tests/Nzb/NzbDocumentTests.cs b/tests/Usenet.Tests/Nzb/NzbDocumentTests.cs
index 2981f4d..9c55e3d 100644
--- a/tests/Usenet.Tests/Nzb/NzbDocumentTests.cs
+++ b/tests/Usenet.Tests/Nzb/NzbDocumentTests.cs
@@ -1,4 +1,5 @@
using Usenet.Nzb;
+using Usenet.Util;
namespace Usenet.Tests.Nzb;
@@ -6,11 +7,14 @@ internal sealed class NzbDocumentTests
{
public static IEnumerable<(NzbDocument, NzbDocument)> EqualsWithSameValues()
{
- yield return (new NzbDocument(null, null), new NzbDocument(null, null));
+ yield return (
+ new NzbDocument(MultiValueDictionary.Empty, []),
+ new NzbDocument(MultiValueDictionary.Empty, [])
+ );
yield return (
new NzbDocument(
- null,
+ MultiValueDictionary.Empty,
[
new NzbFile(
"poster",
@@ -18,7 +22,7 @@ internal sealed class NzbDocumentTests
"fileName1",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
new NzbFile(
"poster",
@@ -26,12 +30,12 @@ internal sealed class NzbDocumentTests
"fileName2",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
]
),
new NzbDocument(
- null,
+ MultiValueDictionary.Empty,
[
new NzbFile(
"poster",
@@ -39,7 +43,7 @@ internal sealed class NzbDocumentTests
"fileName1",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
new NzbFile(
"poster",
@@ -47,7 +51,7 @@ internal sealed class NzbDocumentTests
"fileName2",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
]
)
@@ -55,7 +59,7 @@ internal sealed class NzbDocumentTests
yield return (
new NzbDocument(
- null,
+ MultiValueDictionary.Empty,
[
new NzbFile(
"poster",
@@ -63,7 +67,7 @@ internal sealed class NzbDocumentTests
"fileName3",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
new NzbFile(
"poster",
@@ -71,12 +75,12 @@ internal sealed class NzbDocumentTests
"fileName4",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
]
),
new NzbDocument(
- null,
+ MultiValueDictionary.Empty,
[
new NzbFile(
"poster",
@@ -84,7 +88,7 @@ internal sealed class NzbDocumentTests
"fileName4",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
new NzbFile(
"poster",
@@ -92,7 +96,7 @@ internal sealed class NzbDocumentTests
"fileName3",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
]
)
diff --git a/tests/Usenet.Tests/Nzb/NzbFileTests.cs b/tests/Usenet.Tests/Nzb/NzbFileTests.cs
index 09c329a..5f2c9c3 100644
--- a/tests/Usenet.Tests/Nzb/NzbFileTests.cs
+++ b/tests/Usenet.Tests/Nzb/NzbFileTests.cs
@@ -13,7 +13,7 @@ internal sealed class NzbFileTests
"fileName1",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
new NzbFile(
"poster",
@@ -21,7 +21,7 @@ internal sealed class NzbFileTests
"fileName1",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
)
);
@@ -92,7 +92,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NzbFile expected, NzbFi
"fileName",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
new NzbFile(
"blabla",
@@ -100,7 +100,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NzbFile expected, NzbFi
"fileName",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
)
);
@@ -111,7 +111,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NzbFile expected, NzbFi
"fileName",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
new NzbFile(
"poster",
@@ -119,7 +119,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NzbFile expected, NzbFi
"fileName",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
)
);
@@ -130,7 +130,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NzbFile expected, NzbFi
"fileName",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
new NzbFile(
"poster",
@@ -138,7 +138,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NzbFile expected, NzbFi
"blabla",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
)
);
@@ -149,7 +149,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NzbFile expected, NzbFi
"fileName",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
new NzbFile(
"poster",
@@ -157,7 +157,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NzbFile expected, NzbFi
"fileName",
DateTimeOffset.MinValue,
"group1;group2",
- null!
+ []
)
);
@@ -168,7 +168,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NzbFile expected, NzbFi
"fileName",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"group1;group2",
- null!
+ []
),
new NzbFile(
"poster",
@@ -176,7 +176,7 @@ internal async Task EqualsWithSameValuesShouldReturnTrue(NzbFile expected, NzbFi
"fileName",
new DateTimeOffset(2017, 12, 8, 22, 44, 0, TimeSpan.Zero),
"blabla",
- null!
+ []
)
);
diff --git a/tests/Usenet.Tests/Nzb/NzbParserTests.cs b/tests/Usenet.Tests/Nzb/NzbParserTests.cs
index 03b3cf0..f037092 100644
--- a/tests/Usenet.Tests/Nzb/NzbParserTests.cs
+++ b/tests/Usenet.Tests/Nzb/NzbParserTests.cs
@@ -19,9 +19,7 @@ CancellationToken cancellationToken
)
{
var nzbData = file.ReadAllText(UsenetEncoding.Default);
- var actualDocument = await NzbParser
- .ParseAsync(nzbData, cancellationToken)
- .ConfigureAwait(true);
+ var actualDocument = await NzbParser.ParseAsync(nzbData, cancellationToken);
await Assert.That(actualDocument.MetaData["title"].Single()).IsEqualTo("Your File!");
await Assert.That(actualDocument.MetaData["password"].Single()).IsEqualTo("secret");
@@ -40,9 +38,7 @@ public static IEnumerable> GetValidNzbFiles()
internal async Task MinimalNzbDataShouldBeParsed(CancellationToken cancellationToken)
{
const string nzbText = """""";
- var actualDocument = await NzbParser
- .ParseAsync(nzbText, cancellationToken)
- .ConfigureAwait(true);
+ var actualDocument = await NzbParser.ParseAsync(nzbText, cancellationToken);
await Assert.That(actualDocument.MetaData).IsEmpty();
await Assert.That(actualDocument.Files).IsEmpty();
@@ -59,9 +55,7 @@ internal async Task MultipleMetaDataKeysShouldBeParsed(CancellationToken cancell
""";
- var actualDocument = await NzbParser
- .ParseAsync(nzbText, cancellationToken)
- .ConfigureAwait(true);
+ var actualDocument = await NzbParser.ParseAsync(nzbText, cancellationToken);
await Assert.That(actualDocument.MetaData).HasSingleItem();
await Assert.That(actualDocument.MetaData["tag"].Count).IsEqualTo(2);
@@ -82,9 +76,7 @@ internal async Task MinimalFileShouldBeParsed(CancellationToken cancellationToke
""";
- var actualDocument = await NzbParser
- .ParseAsync(nzbText, cancellationToken)
- .ConfigureAwait(true);
+ var actualDocument = await NzbParser.ParseAsync(nzbText, cancellationToken);
await Assert.That(actualDocument.MetaData).IsEmpty();
await Assert.That(actualDocument.Files).HasSingleItem();
@@ -103,9 +95,7 @@ internal async Task FileDateShouldBeParsed(CancellationToken cancellationToken)
""";
- var actualDocument = await NzbParser
- .ParseAsync(nzbText, cancellationToken)
- .ConfigureAwait(true);
+ var actualDocument = await NzbParser.ParseAsync(nzbText, cancellationToken);
await Assert.That(actualDocument.Files[0].Date).IsEqualTo(expected);
}
@@ -119,9 +109,7 @@ internal async Task InvalidFileDateShouldThrow(CancellationToken cancellationTok
""";
await Assert
- .That(async () =>
- await NzbParser.ParseAsync(nzbText, cancellationToken).ConfigureAwait(true)
- )
+ .That(async () => await NzbParser.ParseAsync(nzbText, cancellationToken))
.ThrowsExactly();
}
@@ -139,9 +127,7 @@ internal async Task InvalidSegmentNumberShouldThrow(CancellationToken cancellati
""";
await Assert
- .That(async () =>
- await NzbParser.ParseAsync(nzbText, cancellationToken).ConfigureAwait(true)
- )
+ .That(async () => await NzbParser.ParseAsync(nzbText, cancellationToken))
.ThrowsExactly();
}
@@ -159,9 +145,7 @@ internal async Task MissingSegmentNumberShouldThrow(CancellationToken cancellati
""";
await Assert
- .That(async () =>
- await NzbParser.ParseAsync(nzbText, cancellationToken).ConfigureAwait(true)
- )
+ .That(async () => await NzbParser.ParseAsync(nzbText, cancellationToken))
.ThrowsExactly();
}
@@ -179,9 +163,7 @@ internal async Task InvalidSegmentSizeShouldThrow(CancellationToken cancellation
""";
await Assert
- .That(async () =>
- await NzbParser.ParseAsync(nzbText, cancellationToken).ConfigureAwait(true)
- )
+ .That(async () => await NzbParser.ParseAsync(nzbText, cancellationToken))
.ThrowsExactly();
}
@@ -199,9 +181,7 @@ internal async Task MissingSegmentSizeShouldThrow(CancellationToken cancellation
""";
await Assert
- .That(async () =>
- await NzbParser.ParseAsync(nzbText, cancellationToken).ConfigureAwait(true)
- )
+ .That(async () => await NzbParser.ParseAsync(nzbText, cancellationToken))
.ThrowsExactly();
}
@@ -210,9 +190,7 @@ internal async Task InvalidXmlShouldThrow(CancellationToken cancellationToken)
{
const string nzbText = "sdfsfasfasdfasdf";
await Assert
- .That(async () =>
- await NzbParser.ParseAsync(nzbText, cancellationToken).ConfigureAwait(true)
- )
+ .That(async () => await NzbParser.ParseAsync(nzbText, cancellationToken))
.ThrowsExactly();
}
@@ -221,9 +199,7 @@ internal async Task InvalidNzbShouldThrow(CancellationToken cancellationToken)
{
const string nzbText = "";
await Assert
- .That(async () =>
- await NzbParser.ParseAsync(nzbText, cancellationToken).ConfigureAwait(true)
- )
+ .That(async () => await NzbParser.ParseAsync(nzbText, cancellationToken))
.ThrowsExactly();
}
@@ -238,9 +214,7 @@ CancellationToken cancellationToken
""";
- var actualDocument = await NzbParser
- .ParseAsync(nzbText, cancellationToken)
- .ConfigureAwait(true);
+ var actualDocument = await NzbParser.ParseAsync(nzbText, cancellationToken);
await Assert.That(actualDocument.Files.Single().FileName).IsEqualTo("TWD151 - 153.rar");
}
@@ -255,9 +229,7 @@ CancellationToken cancellationToken
""";
- var actualDocument = await NzbParser
- .ParseAsync(nzbText, cancellationToken)
- .ConfigureAwait(true);
+ var actualDocument = await NzbParser.ParseAsync(nzbText, cancellationToken);
await Assert
.That(actualDocument.Files.Single().FileName)
.IsEqualTo("(TWD151 - 153)[2 / 9] - TWD151 - 153.rar");
@@ -274,9 +246,7 @@ CancellationToken cancellationToken
""";
- var actualDocument = await NzbParser
- .ParseAsync(nzbText, cancellationToken)
- .ConfigureAwait(true);
+ var actualDocument = await NzbParser.ParseAsync(nzbText, cancellationToken);
await Assert
.That(actualDocument.Files.Single().FileName)
.IsEqualTo("[2 / 9] - TWD151 - 153.rar");
diff --git a/tests/Usenet.Tests/Nzb/NzbWriterTests.cs b/tests/Usenet.Tests/Nzb/NzbWriterTests.cs
index 997462e..d817590 100644
--- a/tests/Usenet.Tests/Nzb/NzbWriterTests.cs
+++ b/tests/Usenet.Tests/Nzb/NzbWriterTests.cs
@@ -15,18 +15,19 @@ internal async Task ShouldWriteDocumentToFile(
CancellationToken cancellationToken
)
{
- var expected = await NzbParser
- .ParseAsync(file.ReadAllText(UsenetEncoding.Default), cancellationToken)
- .ConfigureAwait(true);
+ var expected = await NzbParser.ParseAsync(
+ file.ReadAllText(UsenetEncoding.Default),
+ cancellationToken
+ );
using var stream = new MemoryStream();
- using var writer = new StreamWriter(stream, UsenetEncoding.Default);
+ await using var writer = new StreamWriter(stream, UsenetEncoding.Default);
using var reader = new StreamReader(stream, UsenetEncoding.Default);
// write to file and read back for comparison
- await writer.WriteNzbDocumentAsync(expected, cancellationToken).ConfigureAwait(true);
+ await writer.WriteNzbDocumentAsync(expected, cancellationToken);
stream.Position = 0;
- var actual = await NzbParser.ParseAsync(reader, cancellationToken).ConfigureAwait(true);
+ var actual = await NzbParser.ParseAsync(reader, cancellationToken);
// compare
await Assert.That(actual).IsEqualTo(expected);
diff --git a/tests/Usenet.Tests/TestHelpers/TestNntpServer.cs b/tests/Usenet.Tests/TestHelpers/TestNntpServer.cs
index 7339ead..c44ad40 100644
--- a/tests/Usenet.Tests/TestHelpers/TestNntpServer.cs
+++ b/tests/Usenet.Tests/TestHelpers/TestNntpServer.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Sockets;
using System.Text;
@@ -26,9 +27,7 @@ private async Task AcceptLoop()
TcpClient client;
try
{
- client = await _listener
- .AcceptTcpClientAsync(cancellationToken)
- .ConfigureAwait(false);
+ client = await _listener.AcceptTcpClientAsync(cancellationToken);
}
catch (OperationCanceledException)
{
@@ -45,7 +44,6 @@ CancellationToken cancellationToken
{
try
{
-#pragma warning disable CA2007
var stream = client.GetStream();
await using var writer = new StreamWriter(stream, Encoding.ASCII);
using var reader = new StreamReader(
@@ -55,15 +53,15 @@ CancellationToken cancellationToken
1024,
leaveOpen: true
);
-#pragma warning restore CA2007
+
writer.NewLine = "\r\n";
writer.AutoFlush = true;
// Send NNTP greeting
- await writer.WriteLineAsync("200 Dummy server ready").ConfigureAwait(false);
+ await writer.WriteLineAsync("200 Dummy server ready");
while (!cancellationToken.IsCancellationRequested)
{
- var line = await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false);
+ var line = await reader.ReadLineAsync(cancellationToken);
if (line == null)
break;
@@ -74,7 +72,7 @@ CancellationToken cancellationToken
switch (command)
{
case "AUTHINFO":
- await writer.WriteLineAsync("281 Success").ConfigureAwait(false);
+ await writer.WriteLineAsync("281 Success");
break;
case "GROUP":
// Group command is used to force immediate connection reset
@@ -82,12 +80,10 @@ CancellationToken cancellationToken
client.Client.LingerState = new LingerOption(true, 0);
return;
case "QUIT":
- await writer.WriteLineAsync("205 Goodbye").ConfigureAwait(false);
+ await writer.WriteLineAsync("205 Goodbye");
return;
default:
- await writer
- .WriteLineAsync("500 Command not recognized")
- .ConfigureAwait(false);
+ await writer.WriteLineAsync("500 Command not recognized");
break;
}
}
@@ -99,6 +95,7 @@ await writer
}
}
+ [SuppressMessage("ReSharper", "UnusedTupleComponentInReturnValue")]
private static (string? Command, string? SubCommand, string? Arguments) ParseCommand(
string line
)
diff --git a/tests/Usenet.Tests/Util/CountingStreamTests.cs b/tests/Usenet.Tests/Util/CountingStreamTests.cs
index c9e94e7..c89f9c0 100644
--- a/tests/Usenet.Tests/Util/CountingStreamTests.cs
+++ b/tests/Usenet.Tests/Util/CountingStreamTests.cs
@@ -8,7 +8,7 @@ internal sealed class CountingStreamTests
public async Task CountingStreamShouldCountBytesRead()
{
using var memStream = new MemoryStream(new byte[10]);
- using var stream = new CountingStream(memStream);
+ await using var stream = new CountingStream(memStream);
stream.ReadByte();
stream.ReadByte();
stream.ReadByte();
@@ -22,7 +22,7 @@ public async Task CountingStreamShouldCountBytesRead()
public async Task CountingStreamShouldCountBytesWritten()
{
using var memStream = new MemoryStream(new byte[10]);
- using var stream = new CountingStream(memStream);
+ await using var stream = new CountingStream(memStream);
stream.WriteByte(1);
stream.WriteByte(2);
stream.WriteByte(3);
@@ -36,7 +36,7 @@ public async Task CountingStreamShouldCountBytesWritten()
public async Task ResetCountersShouldResetBytesReadAndBytesWritten()
{
using var memStream = new MemoryStream(new byte[10]);
- using var stream = new CountingStream(memStream);
+ await using var stream = new CountingStream(memStream);
stream.ReadByte();
stream.ReadByte();
stream.WriteByte(1);
diff --git a/tests/Usenet.Tests/Util/MultiValueDictionaryTests.cs b/tests/Usenet.Tests/Util/MultiValueDictionaryTests.cs
index 3e36988..8eba9f4 100644
--- a/tests/Usenet.Tests/Util/MultiValueDictionaryTests.cs
+++ b/tests/Usenet.Tests/Util/MultiValueDictionaryTests.cs
@@ -1,10 +1,10 @@
-using System.Text.Json;
+using System.Diagnostics.CodeAnalysis;
+using System.Text.Json;
using Usenet.Util;
-// ReSharper disable DuplicateKeyCollectionInitialization
-
namespace Usenet.Tests.Util;
+[SuppressMessage("ReSharper", "DuplicateKeyCollectionInitialization")]
internal sealed class MultiValueDictionaryTests
{
[Test]
diff --git a/tests/Usenet.Tests/Yenc/YencArticleDecoderTests.cs b/tests/Usenet.Tests/Yenc/YencArticleDecoderTests.cs
index 811abbb..a36830c 100644
--- a/tests/Usenet.Tests/Yenc/YencArticleDecoderTests.cs
+++ b/tests/Usenet.Tests/Yenc/YencArticleDecoderTests.cs
@@ -77,14 +77,10 @@ IFileInfo part2File
using var actual = new MemoryStream();
actual.Seek(part1.Header.PartOffset, SeekOrigin.Begin);
- await actual
- .WriteAsync(part1.Data.ToArray().AsMemory(0, (int)part1.Header.PartSize))
- .ConfigureAwait(true);
+ await actual.WriteAsync(part1.Data.ToArray().AsMemory(0, (int)part1.Header.PartSize));
actual.Seek(part2.Header.PartOffset, SeekOrigin.Begin);
- await actual
- .WriteAsync(part2.Data.ToArray().AsMemory(0, (int)part2.Header.PartSize))
- .ConfigureAwait(true);
+ await actual.WriteAsync(part2.Data.ToArray().AsMemory(0, (int)part2.Header.PartSize));
var actualFileName = part1.Header.FileName;
diff --git a/tests/Usenet.Tests/Yenc/YencEncoderTests.cs b/tests/Usenet.Tests/Yenc/YencEncoderTests.cs
index 6dfdf97..bf19504 100644
--- a/tests/Usenet.Tests/Yenc/YencEncoderTests.cs
+++ b/tests/Usenet.Tests/Yenc/YencEncoderTests.cs
@@ -23,9 +23,7 @@ CancellationToken cancellationToken
using var stream = new MemoryStream(data);
var header = new YencHeader("test (1.2).txt", data.Length, 10, 0, 1, data.Length, 0);
- var actualText = await YencEncoder
- .EncodeAsync(header, stream, cancellationToken)
- .ConfigureAwait(true);
+ var actualText = await YencEncoder.EncodeAsync(header, stream, cancellationToken);
await Assert.That(actualText).IsEquivalentTo(expectedText);
}
@@ -54,9 +52,7 @@ CancellationToken cancellationToken
using var stream = new MemoryStream(data);
var header = new YencHeader("test (1.2).txt", 120, 10, 1, 2, data.Length, 0);
- var actualText = await YencEncoder
- .EncodeAsync(header, stream, cancellationToken)
- .ConfigureAwait(true);
+ var actualText = await YencEncoder.EncodeAsync(header, stream, cancellationToken);
await Assert.That(actualText).IsEquivalentTo(expectedText);
}
diff --git a/tests/Usenet.Tests/Yenc/YencStreamDecoderTests.cs b/tests/Usenet.Tests/Yenc/YencStreamDecoderTests.cs
index f98dc51..22af4db 100644
--- a/tests/Usenet.Tests/Yenc/YencStreamDecoderTests.cs
+++ b/tests/Usenet.Tests/Yenc/YencStreamDecoderTests.cs
@@ -90,10 +90,10 @@ CancellationToken cancellationToken
using var actual = new MemoryStream();
actual.Seek(part1.Header.PartOffset, SeekOrigin.Begin);
- await part1.CopyToAsync(actual, cancellationToken).ConfigureAwait(true);
+ await part1.CopyToAsync(actual, cancellationToken);
actual.Seek(part2.Header.PartOffset, SeekOrigin.Begin);
- await part2.CopyToAsync(actual, cancellationToken).ConfigureAwait(true);
+ await part2.CopyToAsync(actual, cancellationToken);
var actualFileName = part1.Header.FileName;