Skip to content

Commit

Permalink
Added test cases for read and write VarInt, removed VarLong as it is …
Browse files Browse the repository at this point in the history
…not being used, WriteVarInt now expects int instead of uint (reflected this change within Minecraft.cs).
  • Loading branch information
SergeantSerk committed Sep 19, 2019
1 parent fae8bb0 commit a35adb7
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 65 deletions.
12 changes: 6 additions & 6 deletions MCQuery/Minecraft.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static class Minecraft
/// <summary>
/// Protocol number for latest, stable Minecraft.
/// </summary>
public static uint Protocol = 498;
public static int Protocol = 498;

private static Stopwatch stopwatch;
private static byte[] pingBytes;
Expand Down Expand Up @@ -56,7 +56,7 @@ public static string Status(string server, ushort port = 25565)
}
#endregion

private static TcpClient InitialiseConnection(string server, ushort port, uint state)
private static TcpClient InitialiseConnection(string server, ushort port, int state)
{
TcpClient client = new TcpClient();
client.Client.Blocking = true;
Expand All @@ -72,7 +72,7 @@ private static TcpClient InitialiseConnection(string server, ushort port, uint s
/// <param name="state">The state command that follows after this handshake (usually 1 for status, 2 for login).</param>
/// <param name="server">The server to handshake with.</param>
/// <param name="port">The port of the Minecraft server.</param>
private static void Handshake(NetworkStream network, uint state, string server, ushort port)
private static void Handshake(NetworkStream network, int state, string server, ushort port)
{
using (MemoryStream packet = new MemoryStream())
using (MemoryStream data = new MemoryStream())
Expand All @@ -84,7 +84,7 @@ private static void Handshake(NetworkStream network, uint state, string server,
data.Write(BitConverter.GetBytes(port)); // Server port
Utilities.WriteVarInt(data, state); // State command
}
Utilities.WriteVarInt(packet, (uint)(data.Length + 1)); // Write packet length (Packet ID + Inner Packet)
Utilities.WriteVarInt(packet, (int)data.Length + 1); // Write packet length (Packet ID + Inner Packet)
Utilities.WriteVarInt(packet, 0); // Packet ID (0 = Handshake at this state)
data.Seek(0, SeekOrigin.Begin); // Seek to beginning and copy inner packet to actual packet
data.CopyTo(packet);
Expand All @@ -104,7 +104,7 @@ private static void SendPing(NetworkStream network)
pingBytes = BitConverter.GetBytes(ticks);
data.Write(pingBytes);
}
Utilities.WriteVarInt(packet, (uint)(data.Length + 1));
Utilities.WriteVarInt(packet, (int)data.Length + 1);
Utilities.WriteVarInt(packet, 1);
data.Seek(0, SeekOrigin.Begin);
data.CopyTo(packet);
Expand Down Expand Up @@ -147,7 +147,7 @@ private static void SendStatusRequest(NetworkStream network)
using (MemoryStream packet = new MemoryStream())
using (MemoryStream data = new MemoryStream())
{
Utilities.WriteVarInt(packet, (uint)(data.Length + 1)); // Packet ID + Packet
Utilities.WriteVarInt(packet, (int)data.Length + 1); // Packet ID + Packet
Utilities.WriteVarInt(packet, 0); // Packet ID
data.Seek(0, SeekOrigin.Begin); // Seek to beginning and copy inner packet to actual packet
data.CopyTo(packet);
Expand Down
54 changes: 12 additions & 42 deletions MCQuery/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,24 @@ namespace MCQuery
{
public static class Utilities
{
public static void WriteVarLong(Stream stream, long value)
#region VarInt (https://wiki.vg/Protocol#VarInt_and_VarLong)
public static void WriteVarInt(Stream stream, int value)
{
// Converting int to uint is necessary to preserve the sign bit
// when performing bit shifting
uint actual = (uint)value;
do
{
byte temp = (byte)(value & 0b01111111);
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
value >>= 7;
if (value != 0)
byte temp = (byte)(actual & 0b01111111);
// Note: >>> means that the sign bit is shifted with the
// rest of the number rather than being left alone
actual >>= 7;
if (actual != 0)
{
temp |= 0b10000000;
}
stream.WriteByte(temp);
} while (value != 0);
}

public static void WriteVarInt(Stream stream, uint value)
{
do
{
byte temp = (byte)(value & 0b01111111);
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
value >>= 7;
if (value != 0)
{
temp |= 0b10000000;
}
stream.WriteByte(temp);
} while (value != 0);
}

public static long ReadVarLong(Stream stream)
{
int numRead = 0;
long result = 0;
byte read;
do
{
read = (byte)stream.ReadByte();
int value = read & 0b01111111;
result |= value << (7 * numRead);

numRead++;
if (numRead > 10)
{
throw new FormatException("VarLong is too big");
}
} while ((read & 0b10000000) != 0);

return result;
} while (actual != 0);
}

public static int ReadVarInt(Stream stream)
Expand All @@ -76,5 +45,6 @@ public static int ReadVarInt(Stream stream)

return result;
}
#endregion
}
}
100 changes: 83 additions & 17 deletions MCQueryTests/UtilitiesTest.cs
Original file line number Diff line number Diff line change
@@ -1,39 +1,105 @@
using MCQuery;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Linq;

namespace MCQueryTests
{
[TestClass]
public class UtilitiesTest
{
[TestMethod]
public void ReadVarIntTest()
public void WriteVarIntTest()
{
byte[] samplePacketLength = new byte[] { 0x81, 0x01 }; // VarInt(129) == 0x81, 0x01
byte[] samplePacketId = new byte[] { 0x00 }; // VarInt(0) == 0x00
byte[] sampleResponseLength = new byte[] { 0x7F }; // VarInt(127) == 0x7F

bool cond1, cond2, cond3;
int[] testCases = new int[9]
{
0,
1,
2,
127,
128,
255,
2147483647,
-1,
-2147483648
};
byte[][] testCasesResults = new byte[9][]
{
new byte[] { 0x00 }, // VarInt(0)
new byte[] { 0x01 }, // VarInt(1)
new byte[] { 0x02 }, // VarInt(2)
new byte[] { 0x7F }, // VarInt(127)
new byte[] { 0x80, 0x01 }, // VarInt(128)
new byte[] { 0xFF, 0x01 }, // VarInt(255)
new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0x07 }, // VarInt(2147483647)
new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, }, // VarInt(-1)
new byte[] { 0x80, 0x80, 0x80, 0x80, 0x08 } // VarInt(-2147483648)
};

using (MemoryStream memory = new MemoryStream(samplePacketLength))
using (MemoryStream memory = new MemoryStream())
{
int result = MCQuery.Utilities.ReadVarInt(memory);
cond1 = result == 129;
for (int i = 0; i < testCases.Length; ++i)
{
memory.SetLength(0); // Reset stream
Utilities.WriteVarInt(memory, testCases[i]); // Write integer (VarInt) to stream
byte[] result = memory.ToArray();
if (!testCasesResults[i].SequenceEqual(result))
Assert.Fail($"Expected {BitConverter.ToString(testCasesResults[i])}, got {BitConverter.ToString(result)}");
}
}
}

using (MemoryStream memory = new MemoryStream(samplePacketId))
[TestMethod]
public void ReadVarIntTest()
{
byte[][] testCases = new byte[9][]
{
int result = MCQuery.Utilities.ReadVarInt(memory);
cond2 = result == 0;
}
new byte[] { 0x00 }, // VarInt(0)
new byte[] { 0x01 }, // VarInt(1)
new byte[] { 0x02 }, // VarInt(2)
new byte[] { 0x7F }, // VarInt(127)
new byte[] { 0x80, 0x01 }, // VarInt(128)
new byte[] { 0xFF, 0x01 }, // VarInt(255)
new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0x07 }, // VarInt(2147483647)
new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, }, // VarInt(-1)
new byte[] { 0x80, 0x80, 0x80, 0x80, 0x08 } // VarInt(-2147483648)
};
int[] testCasesResults = new int[9]
{
0,
1,
2,
127,
128,
255,
2147483647,
-1,
-2147483648
};

using (MemoryStream memory = new MemoryStream(sampleResponseLength))
using (MemoryStream memory = new MemoryStream())
{
int result = MCQuery.Utilities.ReadVarInt(memory);
cond3 = result == 127;
for (int i = 0; i < testCases.Length; ++i)
{
int result = ReadVarIntHelper(memory, testCases[i]);
if (result != testCasesResults[i])
Assert.Fail($"Expected {testCasesResults[i]}, got {result}.");
}
}
}

Assert.IsTrue(cond1 && cond2 && cond3);
private int ReadVarIntHelper(Stream stream, byte[] data)
{
StreamHelper(stream, data); // Setup stream for testing
return Utilities.ReadVarInt(stream); // Get VarInt from stream
}

private void StreamHelper(Stream stream, byte[] data)
{
stream.SetLength(0); // Reset stream
stream.Write(data); // Write test bytes
stream.Seek(0, SeekOrigin.Begin); // Go back to the start for reading
}
}
}

0 comments on commit a35adb7

Please sign in to comment.