Skip to content

Commit 9c3133a

Browse files
authored
Merge pull request #3 from NewLifeX/copilot/add-unit-tests-for-classes
Add comprehensive unit tests and fix COTP ReadPacket bug
2 parents 8e8d192 + 57c9818 commit 9c3133a

11 files changed

Lines changed: 1755 additions & 11 deletions

File tree

NewLife.Siemens/Protocols/COTP.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ public Boolean Read(IPacket data)
6464
Number = flags & 0x7F;
6565
LastDataUnit = (flags & 0x80) > 0;
6666

67-
Data = reader.ReadPacket(-1);
67+
var remaining = reader.FreeCapacity;
68+
if (remaining > 0)
69+
Data = reader.ReadPacket(remaining);
6870
}
6971
break;
7072
case PduType.ConnectionRequest:

XUnitTest/BasicTest.cs

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,75 @@
11
using System;
2+
using System.IO;
23
using System.Linq;
3-
using System.Threading;
4-
using NewLife.Caching;
5-
using NewLife.Log;
4+
using NewLife;
5+
using NewLife.Data;
6+
using NewLife.Serialization;
7+
using NewLife.Siemens.Messages;
8+
using NewLife.Siemens.Models;
9+
using NewLife.Siemens.Protocols;
610
using Xunit;
711

812
namespace XUnitTest;
913

1014
public class BasicTest
1115
{
16+
[Fact]
17+
public void PLCAddress_ParseStatic()
18+
{
19+
PLCAddress.Parse("DB1.DBB0", out var dataType, out var dbNumber, out var varType, out var address, out var bitNumber);
20+
Assert.Equal(DataType.DataBlock, dataType);
21+
Assert.Equal(1, dbNumber);
22+
Assert.Equal(VarType.Byte, varType);
23+
Assert.Equal(0, address);
24+
Assert.Equal(-1, bitNumber);
25+
}
26+
27+
[Fact]
28+
public void TPKT_COTP_S7Message_FullStack()
29+
{
30+
// Build a complete S7 message wrapped in COTP and TPKT
31+
var msg = new S7Message
32+
{
33+
Kind = S7Kinds.Job,
34+
Sequence = 1
35+
};
36+
msg.Setup(1, 960);
37+
38+
var cotp = msg.ToCOTP();
39+
Assert.Equal(PduType.Data, cotp.Type);
40+
Assert.True(cotp.LastDataUnit);
41+
42+
var pk = cotp.ToPacket(true);
43+
var bytes = pk.ToArray();
44+
45+
// Parse back
46+
var tpkt = new TPKT();
47+
tpkt.Read(new Packet(bytes));
48+
Assert.Equal(3, tpkt.Version);
49+
50+
var cotp2 = new COTP();
51+
cotp2.Read(tpkt.Data);
52+
Assert.Equal(PduType.Data, cotp2.Type);
53+
54+
var msg2 = new S7Message();
55+
msg2.Read(cotp2.Data);
56+
Assert.Equal(S7Kinds.Job, msg2.Kind);
57+
Assert.Equal(1, msg2.Sequence);
58+
Assert.Single(msg2.Parameters);
59+
60+
var pm = msg2.Parameters[0] as SetupMessage;
61+
Assert.NotNull(pm);
62+
Assert.Equal(1, pm.MaxAmqCaller);
63+
Assert.Equal(1, pm.MaxAmqCallee);
64+
Assert.Equal(960, pm.PduLength);
65+
}
66+
67+
[Fact]
68+
public void EnumValues_Consistent()
69+
{
70+
// Quick sanity check that key enum values haven't changed
71+
Assert.Equal(132, (Int32)DataType.DataBlock);
72+
Assert.Equal(1, (Byte)VarType.Bit);
73+
Assert.Equal(0x32, new S7Message().ProtocolId);
74+
}
1275
}

XUnitTest/COTPTests.cs

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,227 @@ public void ConfirmedTest()
221221
Assert.True(rs);
222222
Assert.Equal(cotp.Type, cotp2.Type);
223223
}
224+
225+
#region GetParameter / SetParameter
226+
[Fact]
227+
public void GetParameter_ReturnsNull_WhenNotFound()
228+
{
229+
var cotp = new COTP { Type = PduType.ConnectionRequest };
230+
var result = cotp.GetParameter(COTPParameterKinds.TpduSize);
231+
Assert.Null(result);
232+
}
233+
234+
[Fact]
235+
public void GetParameter_ReturnsExisting()
236+
{
237+
var cotp = new COTP { Type = PduType.ConnectionRequest };
238+
cotp.SetParameter(COTPParameterKinds.TpduSize, (Byte)0x0A);
239+
240+
var result = cotp.GetParameter(COTPParameterKinds.TpduSize);
241+
Assert.NotNull(result);
242+
Assert.Equal(COTPParameterKinds.TpduSize, result.Kind);
243+
Assert.Equal((Byte)0x0A, result.Value);
244+
}
245+
246+
[Fact]
247+
public void SetParameter_AddNew()
248+
{
249+
var cotp = new COTP { Type = PduType.ConnectionRequest };
250+
Assert.Empty(cotp.Parameters);
251+
252+
cotp.SetParameter(new COTPParameter(COTPParameterKinds.TpduSize, 1, (Byte)0x0A));
253+
Assert.Single(cotp.Parameters);
254+
Assert.Equal(COTPParameterKinds.TpduSize, cotp.Parameters[0].Kind);
255+
}
256+
257+
[Fact]
258+
public void SetParameter_ReplaceExisting()
259+
{
260+
var cotp = new COTP { Type = PduType.ConnectionRequest };
261+
cotp.SetParameter(new COTPParameter(COTPParameterKinds.TpduSize, 1, (Byte)0x0A));
262+
cotp.SetParameter(new COTPParameter(COTPParameterKinds.TpduSize, 1, (Byte)0x0B));
263+
264+
Assert.Single(cotp.Parameters);
265+
Assert.Equal((Byte)0x0B, cotp.Parameters[0].Value);
266+
}
267+
268+
[Fact]
269+
public void SetParameter_Byte()
270+
{
271+
var cotp = new COTP { Type = PduType.ConnectionRequest };
272+
cotp.SetParameter(COTPParameterKinds.TpduSize, (Byte)0x0A);
273+
274+
var p = cotp.GetParameter(COTPParameterKinds.TpduSize);
275+
Assert.NotNull(p);
276+
Assert.Equal(1, p.Length);
277+
Assert.Equal((Byte)0x0A, p.Value);
278+
}
279+
280+
[Fact]
281+
public void SetParameter_UInt16()
282+
{
283+
var cotp = new COTP { Type = PduType.ConnectionRequest };
284+
cotp.SetParameter(COTPParameterKinds.SrcTsap, (UInt16)0x1000);
285+
286+
var p = cotp.GetParameter(COTPParameterKinds.SrcTsap);
287+
Assert.NotNull(p);
288+
Assert.Equal(2, p.Length);
289+
Assert.Equal((UInt16)0x1000, p.Value);
290+
}
291+
292+
[Fact]
293+
public void SetParameter_UInt32()
294+
{
295+
var cotp = new COTP { Type = PduType.ConnectionRequest };
296+
cotp.SetParameter(COTPParameterKinds.DstTsap, (UInt32)0x12345678);
297+
298+
var p = cotp.GetParameter(COTPParameterKinds.DstTsap);
299+
Assert.NotNull(p);
300+
Assert.Equal(4, p.Length);
301+
Assert.Equal((UInt32)0x12345678, p.Value);
302+
}
303+
#endregion
304+
305+
#region ToString
306+
[Fact]
307+
public void ToString_Data()
308+
{
309+
var cotp = new COTP
310+
{
311+
Type = PduType.Data,
312+
Data = new Packet(new Byte[] { 1, 2, 3 })
313+
};
314+
var str = cotp.ToString();
315+
Assert.Contains("Data", str);
316+
Assert.Contains("3", str);
317+
}
318+
319+
[Fact]
320+
public void ToString_CR()
321+
{
322+
var cotp = new COTP
323+
{
324+
Type = PduType.ConnectionRequest
325+
};
326+
var str = cotp.ToString();
327+
Assert.Contains("ConnectionRequest", str);
328+
}
329+
#endregion
330+
331+
#region CR with parameters roundtrip
332+
[Fact]
333+
public void CR_WithParameters_Roundtrip()
334+
{
335+
var cotp = new COTP
336+
{
337+
Type = PduType.ConnectionRequest,
338+
Destination = 0x0000,
339+
Source = 0x0001,
340+
Option = 0x00
341+
};
342+
cotp.SetParameter(COTPParameterKinds.SrcTsap, (UInt16)0x1000);
343+
cotp.SetParameter(COTPParameterKinds.DstTsap, (UInt16)0x0300);
344+
cotp.SetParameter(COTPParameterKinds.TpduSize, (Byte)0x0A);
345+
346+
var pk = cotp.ToPacket(false);
347+
348+
var cotp2 = new COTP();
349+
var rs = cotp2.Read(pk);
350+
Assert.True(rs);
351+
352+
Assert.Equal(PduType.ConnectionRequest, cotp2.Type);
353+
Assert.Equal(0x0000, cotp2.Destination);
354+
Assert.Equal(0x0001, cotp2.Source);
355+
Assert.Equal(0x00, cotp2.Option);
356+
Assert.Equal(3, cotp2.Parameters.Count);
357+
358+
var src = cotp2.GetParameter(COTPParameterKinds.SrcTsap);
359+
Assert.NotNull(src);
360+
Assert.Equal((UInt16)0x1000, src.Value);
361+
362+
var dst = cotp2.GetParameter(COTPParameterKinds.DstTsap);
363+
Assert.NotNull(dst);
364+
Assert.Equal((UInt16)0x0300, dst.Value);
365+
366+
var tpdu = cotp2.GetParameter(COTPParameterKinds.TpduSize);
367+
Assert.NotNull(tpdu);
368+
Assert.Equal((Byte)0x0A, tpdu.Value);
369+
}
370+
#endregion
371+
372+
#region COTPParameter constructor
373+
[Fact]
374+
public void COTPParameter_ConstructorSetsFields()
375+
{
376+
var p = new COTPParameter(COTPParameterKinds.TpduSize, 1, (Byte)10);
377+
Assert.Equal(COTPParameterKinds.TpduSize, p.Kind);
378+
Assert.Equal(1, p.Length);
379+
Assert.Equal((Byte)10, p.Value);
380+
}
381+
382+
[Fact]
383+
public void COTPParameter_MutableProperties()
384+
{
385+
var p = new COTPParameter(COTPParameterKinds.SrcTsap, 2, (UInt16)0x1000);
386+
p.Kind = COTPParameterKinds.DstTsap;
387+
p.Length = 4;
388+
p.Value = (UInt32)0x12345678;
389+
390+
Assert.Equal(COTPParameterKinds.DstTsap, p.Kind);
391+
Assert.Equal(4, p.Length);
392+
Assert.Equal((UInt32)0x12345678, p.Value);
393+
}
394+
#endregion
395+
396+
#region DT with data roundtrip
397+
[Fact]
398+
public void DT_WithData_Roundtrip()
399+
{
400+
var payload = new Byte[] { 0xDE, 0xAD, 0xBE, 0xEF };
401+
var cotp = new COTP
402+
{
403+
Type = PduType.Data,
404+
LastDataUnit = true,
405+
Number = 0,
406+
Data = new Packet(payload)
407+
};
408+
409+
var pk = cotp.ToPacket(false);
410+
var cotp2 = new COTP();
411+
var rs = cotp2.Read(pk);
412+
413+
Assert.True(rs);
414+
Assert.Equal(PduType.Data, cotp2.Type);
415+
Assert.True(cotp2.LastDataUnit);
416+
Assert.NotNull(cotp2.Data);
417+
Assert.Equal(payload.ToHex(), cotp2.Data.ToHex());
418+
}
419+
420+
[Fact]
421+
public void DT_WithTPKT_Roundtrip()
422+
{
423+
var payload = new Byte[] { 0x01, 0x02, 0x03 };
424+
var cotp = new COTP
425+
{
426+
Type = PduType.Data,
427+
LastDataUnit = true,
428+
Data = new Packet(payload)
429+
};
430+
431+
var pk = cotp.ToPacket(true);
432+
var bytes = pk.ToArray();
433+
434+
// Parse TPKT first
435+
var tpkt = new TPKT();
436+
tpkt.Read(new Packet(bytes));
437+
Assert.Equal(3, tpkt.Version);
438+
439+
// Then COTP
440+
var cotp2 = new COTP();
441+
cotp2.Read(tpkt.Data);
442+
Assert.Equal(PduType.Data, cotp2.Type);
443+
Assert.True(cotp2.LastDataUnit);
444+
Assert.Equal(payload.ToHex(), cotp2.Data.ToHex());
445+
}
446+
#endregion
224447
}

XUnitTest/CommonTests.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using System.IO;
3+
using NewLife.Siemens.Models;
4+
using Xunit;
5+
6+
namespace XUnitTest;
7+
8+
public class CommonTests
9+
{
10+
#region ErrorCode
11+
[Fact]
12+
public void ErrorCode_AllValues_AreDefined()
13+
{
14+
var values = Enum.GetValues(typeof(ErrorCode));
15+
Assert.Equal(9, values.Length);
16+
}
17+
18+
[Fact]
19+
public void ErrorCode_CanCastToInt()
20+
{
21+
Assert.Equal(0, (Int32)ErrorCode.NoError);
22+
Assert.Equal(50, (Int32)ErrorCode.WriteData);
23+
}
24+
25+
[Fact]
26+
public void ErrorCode_AllMembers_HaveExpectedValues()
27+
{
28+
Assert.Equal(1, (Int32)ErrorCode.WrongCPU_Type);
29+
Assert.Equal(2, (Int32)ErrorCode.ConnectionError);
30+
Assert.Equal(3, (Int32)ErrorCode.IPAddressNotAvailable);
31+
Assert.Equal(10, (Int32)ErrorCode.WrongVarFormat);
32+
Assert.Equal(11, (Int32)ErrorCode.WrongNumberReceivedBytes);
33+
Assert.Equal(20, (Int32)ErrorCode.SendData);
34+
Assert.Equal(30, (Int32)ErrorCode.ReadData);
35+
}
36+
37+
[Fact]
38+
public void ErrorCode_Enum_ContainsKey()
39+
{
40+
Assert.True(Enum.IsDefined(typeof(ErrorCode), 0));
41+
Assert.True(Enum.IsDefined(typeof(ErrorCode), 50));
42+
Assert.False(Enum.IsDefined(typeof(ErrorCode), 99));
43+
}
44+
#endregion
45+
}

0 commit comments

Comments
 (0)