Skip to content

Commit f5b5542

Browse files
committed
Improved exception messages.
Avoid magic numbers. Improve test coverage.
1 parent a1f46d4 commit f5b5542

File tree

2 files changed

+440
-40
lines changed

2 files changed

+440
-40
lines changed

src/Renci.SshNet/SshMessageFactory.cs

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Globalization;
4+
using System.Linq;
45
using Renci.SshNet.Common;
56
using Renci.SshNet.Messages;
67
using Renci.SshNet.Messages.Authentication;
@@ -14,9 +15,19 @@ internal class SshMessageFactory
1415
private readonly MessageMetadata[] _enabledMessagesByNumber;
1516
private readonly bool[] _activatedMessagesById;
1617

17-
private static readonly MessageMetadata[] AllMessages;
18+
internal static readonly MessageMetadata[] AllMessages;
1819
private static readonly IDictionary<string, MessageMetadata> MessagesByName;
1920

21+
/// <summary>
22+
/// Defines the highest message number that is currently supported.
23+
/// </summary>
24+
internal const byte HighestMessageNumber = 100;
25+
26+
/// <summary>
27+
/// Defines the total number of supported messages.
28+
/// </summary>
29+
internal const int TotalMessageCount = 31;
30+
2031
static SshMessageFactory()
2132
{
2233
AllMessages = new MessageMetadata[]
@@ -54,15 +65,15 @@ static SshMessageFactory()
5465
new MessageMetadata<KeyExchangeDhGroupExchangeReply> (30, "SSH_MSG_KEX_DH_GEX_REPLY", 33)
5566
};
5667

57-
MessagesByName = new Dictionary<string, MessageMetadata>(31);
68+
MessagesByName = new Dictionary<string, MessageMetadata>(AllMessages.Length);
5869
foreach (var messageMetadata in AllMessages)
5970
MessagesByName.Add(messageMetadata.Name, messageMetadata);
6071
}
6172

6273
public SshMessageFactory()
6374
{
64-
_activatedMessagesById = new bool[31];
65-
_enabledMessagesByNumber = new MessageMetadata[101];
75+
_activatedMessagesById = new bool[TotalMessageCount];
76+
_enabledMessagesByNumber = new MessageMetadata[HighestMessageNumber + 1];
6677
}
6778

6879
/// <summary>
@@ -76,14 +87,24 @@ public void Reset()
7687

7788
public Message Create(byte messageNumber)
7889
{
79-
var messageMetadata = _enabledMessagesByNumber[messageNumber];
90+
if (messageNumber > HighestMessageNumber)
91+
{
92+
throw CreateMessageTypeNotSupportedException(messageNumber);
93+
}
8094

81-
if (messageMetadata == null)
95+
var enabledMessageMetadata = _enabledMessagesByNumber[messageNumber];
96+
if (enabledMessageMetadata == null)
8297
{
83-
throw new SshException(string.Format(CultureInfo.CurrentCulture, "Message type {0} is not valid.", messageNumber));
98+
var definedMessageMetadata = AllMessages.FirstOrDefault(p => p.Number == messageNumber);
99+
if (definedMessageMetadata == null)
100+
{
101+
throw CreateMessageTypeNotSupportedException(messageNumber);
102+
}
103+
104+
throw new SshException(string.Format(CultureInfo.InvariantCulture, "Message type {0} is not valid in the current context.", messageNumber));
84105
}
85106

86-
return messageMetadata.Create();
107+
return enabledMessageMetadata.Create();
87108
}
88109

89110
public void DisableNonKeyExchangeMessages()
@@ -106,58 +127,89 @@ public void EnableActivatedMessages()
106127
if (!_activatedMessagesById[messageMetadata.Id])
107128
continue;
108129

109-
var enabledMessage = _enabledMessagesByNumber[messageMetadata.Number];
110-
if (enabledMessage != null && enabledMessage != messageMetadata)
130+
var enabledMessageMetadata = _enabledMessagesByNumber[messageMetadata.Number];
131+
if (enabledMessageMetadata != null && enabledMessageMetadata != messageMetadata)
111132
{
112-
throw new Exception("Message X is already enabled for Y");
133+
throw CreateMessageTypeAlreadyEnabledForOtherMessageException(messageMetadata.Number,
134+
messageMetadata.Name,
135+
enabledMessageMetadata.Name);
113136
}
114137
_enabledMessagesByNumber[messageMetadata.Number] = messageMetadata;
115138
}
116139
}
117140

118141
public void EnableAndActivateMessage(string messageName)
119142
{
143+
if (messageName == null)
144+
throw new ArgumentNullException("messageName");
145+
120146
lock (this)
121147
{
122148
MessageMetadata messageMetadata;
123149

124150
if (!MessagesByName.TryGetValue(messageName, out messageMetadata))
125151
{
126-
throw new Exception("TODO");
152+
throw CreateMessageNotSupportedException(messageName);
127153
}
128154

129-
var enabledMessage = _enabledMessagesByNumber[messageMetadata.Number];
130-
if (enabledMessage != null && enabledMessage != messageMetadata)
155+
var enabledMessageMetadata = _enabledMessagesByNumber[messageMetadata.Number];
156+
if (enabledMessageMetadata != null && enabledMessageMetadata != messageMetadata)
131157
{
132-
throw new Exception("Message X is already enabled for Y");
158+
throw CreateMessageTypeAlreadyEnabledForOtherMessageException(messageMetadata.Number,
159+
messageMetadata.Name,
160+
enabledMessageMetadata.Name);
133161
}
134-
_enabledMessagesByNumber[messageMetadata.Number] = messageMetadata;
135162

163+
_enabledMessagesByNumber[messageMetadata.Number] = messageMetadata;
136164
_activatedMessagesById[messageMetadata.Id] = true;
137165
}
138166
}
139167

140168
public void DisableAndDeactivateMessage(string messageName)
141169
{
170+
if (messageName == null)
171+
throw new ArgumentNullException("messageName");
172+
142173
lock (this)
143174
{
144175
MessageMetadata messageMetadata;
145176

146177
if (!MessagesByName.TryGetValue(messageName, out messageMetadata))
147178
{
148-
throw new Exception("TODO");
179+
throw CreateMessageNotSupportedException(messageName);
149180
}
150181

151-
_activatedMessagesById[messageMetadata.Id] = false;
182+
var enabledMessageMetadata = _enabledMessagesByNumber[messageMetadata.Number];
183+
if (enabledMessageMetadata != null && enabledMessageMetadata != messageMetadata)
184+
{
185+
throw CreateMessageTypeAlreadyEnabledForOtherMessageException(messageMetadata.Number,
186+
messageMetadata.Name,
187+
enabledMessageMetadata.Name);
188+
}
152189

153-
var enabledMetadata = _enabledMessagesByNumber[messageMetadata.Number];
154-
if (enabledMetadata != null && enabledMetadata != messageMetadata)
155-
throw new Exception();
190+
_activatedMessagesById[messageMetadata.Id] = false;
156191
_enabledMessagesByNumber[messageMetadata.Number] = null;
157192
}
158193
}
159194

160-
private abstract class MessageMetadata
195+
private SshException CreateMessageTypeNotSupportedException(byte messageNumber)
196+
{
197+
throw new SshException(string.Format(CultureInfo.InvariantCulture, "Message type {0} is not supported.", messageNumber));
198+
}
199+
200+
private SshException CreateMessageNotSupportedException(string messageName)
201+
{
202+
throw new SshException(string.Format(CultureInfo.InvariantCulture, "Message '{0}' is not supported.", messageName));
203+
}
204+
205+
private SshException CreateMessageTypeAlreadyEnabledForOtherMessageException(byte messageNumber, string messageName, string currentEnabledForMessageName)
206+
{
207+
throw new SshException(string.Format(CultureInfo.InvariantCulture,
208+
"Cannot enable message '{0}'. Message type {1} is already enabled for '{2}'.",
209+
messageName, messageNumber, currentEnabledForMessageName));
210+
}
211+
212+
internal abstract class MessageMetadata
161213
{
162214
protected MessageMetadata(byte id, string name, byte number)
163215
{
@@ -175,7 +227,7 @@ protected MessageMetadata(byte id, string name, byte number)
175227
public abstract Message Create();
176228
}
177229

178-
private class MessageMetadata<T> : MessageMetadata where T : Message, new()
230+
internal class MessageMetadata<T> : MessageMetadata where T : Message, new()
179231
{
180232
public MessageMetadata(byte id, string name, byte number)
181233
: base(id, name, number)

0 commit comments

Comments
 (0)