diff --git a/src/Hyperion.Tests/IncompleteStreamTests.cs b/src/Hyperion.Tests/IncompleteStreamTests.cs new file mode 100644 index 00000000..0b2f8183 --- /dev/null +++ b/src/Hyperion.Tests/IncompleteStreamTests.cs @@ -0,0 +1,84 @@ +using System.IO; +using Xunit; + +namespace Hyperion.Tests +{ + public class IncompleteStreamTests : TestBase + { + private const int IncompleteBytes = 4; + + public IncompleteStreamTests() + : base(x => new IncompleteReadStream(x, IncompleteBytes)) + { + } + + [Fact] + public void ThrowsOnEOF() + { + double data = 4; //double has 8 bytes + Serialize(data); + Reset(); + + // manifest requires 1 byte + // incomplete returned bytes are then (IncompleteBytes)4 - 1 = 3 => EOF + Assert.Throws(() => Deserialize()); + } + + private class IncompleteReadStream : Stream + { + private readonly Stream _baseStream; + private readonly int _maxReadBytes; + + private int _totalReadBytes; + + public IncompleteReadStream(Stream baseStream, int maxReadBytes) + { + _baseStream = baseStream; + _maxReadBytes = maxReadBytes; + } + + public override void Flush() + { + _baseStream.Flush(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _baseStream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + _baseStream.SetLength(value); + } + + public override int Read(byte[] buffer, int offset, int count) + { + var allBytes = _totalReadBytes + count; + var bytesToRead = allBytes > _maxReadBytes + ? _maxReadBytes - _totalReadBytes + : count; + + var readBytes = _baseStream.Read(buffer, offset, bytesToRead); + _totalReadBytes += readBytes; + return readBytes; + } + + public override void Write(byte[] buffer, int offset, int count) + { + _baseStream.Write(buffer, offset, count); + } + + public override bool CanRead => _baseStream.CanRead; + public override bool CanSeek => _baseStream.CanSeek; + public override bool CanWrite => _baseStream.CanWrite; + public override long Length => _baseStream.Length; + + public override long Position + { + get => _baseStream.Position; + set => _baseStream.Position = value; + } + } + } +} \ No newline at end of file diff --git a/src/Hyperion.Tests/PartialStreamTest.cs b/src/Hyperion.Tests/PartialStreamTests.cs similarity index 94% rename from src/Hyperion.Tests/PartialStreamTest.cs rename to src/Hyperion.Tests/PartialStreamTests.cs index a4ed6b09..1569514d 100644 --- a/src/Hyperion.Tests/PartialStreamTest.cs +++ b/src/Hyperion.Tests/PartialStreamTests.cs @@ -2,13 +2,13 @@ namespace Hyperion.Tests { - public class PartialStreamTest : PrimitivesTest + public class PartialStreamTests : PrimitivesTest { - public PartialStreamTest() + public PartialStreamTests() : base(x => new OneBytePerReadStream(x)) { } - + private class OneBytePerReadStream : Stream { private readonly Stream _baseStream; diff --git a/src/Hyperion/Extensions/StreamEx.cs b/src/Hyperion/Extensions/StreamEx.cs index a2800542..4269930a 100644 --- a/src/Hyperion/Extensions/StreamEx.cs +++ b/src/Hyperion/Extensions/StreamEx.cs @@ -188,8 +188,8 @@ public static string ReadString(this Stream stream, DeserializerSession session) } var buffer = session.GetBuffer(length); - stream.ReadFull(buffer, 0, length); + var res = StringEx.FromUtf8Bytes(buffer, 0, length); return res; } @@ -213,12 +213,16 @@ public static int ReadFull(this Stream stream, byte[] buffer, int offset, int co { var readBytes = stream.Read(buffer, offset + totalReadBytes, count - totalReadBytes); if (readBytes == 0) - break; + break; // EOF totalReadBytes += readBytes; } while (totalReadBytes < count); + // received enough bytes? + if (totalReadBytes != count) + throw new EndOfStreamException("Stream didn't returned sufficient bytes"); + return totalReadBytes; } }