Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions AdvancedSharpAdbClient.Tests/Dummys/DummyChunkedStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
锘縰sing System;
using System.IO;

namespace AdvancedSharpAdbClient.Tests
{
/// <summary>
/// A forward-only stream that returns its content in the given chunk sizes, like a pipe or network stream may.
/// </summary>
internal class DummyChunkedStream(byte[] content, params int[] chunks) : Stream
{
private int position;
private int chunkIndex;

public override bool CanRead => true;

public override bool CanSeek => false;

public override bool CanWrite => false;

public override long Length => throw new NotSupportedException();

public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}

public override int Read(byte[] buffer, int offset, int count)
{
int chunk = chunkIndex < chunks.Length ? chunks[chunkIndex++] : count;
int read = Math.Min(Math.Min(chunk, count), content.Length - position);
Array.Copy(content, position, buffer, offset, read);
position += read;
return read;
}

public override void Flush() { }

public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();

public override void SetLength(long value) => throw new NotSupportedException();

public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
}
}
47 changes: 46 additions & 1 deletion AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,45 @@ await RunTestAsync(
TestContext.Current.CancellationToken);
}

/// <summary>
/// Tests the <see cref="SyncService.PushAsync(Stream, string, UnixFileStatus, DateTimeOffset, Action{SyncProgressChangedEventArgs}?, bool, CancellationToken)"/> method
/// with a stream that returns a short read followed by full reads.
/// </summary>
[Fact]
public async Task PushShortReadAsyncTest()
{
// A 24 byte buffer leaves 16 bytes of data per message
byte[] content = [.. Enumerable.Range(0, 40).Select(x => (byte)x)];
DummyChunkedStream stream = new(content, 5, 16, 16);
byte[][] contentMessages =
[
[.. SyncCommand.DATA.GetBytes(), .. BitConverter.GetBytes(5), .. content[..5]],
[.. SyncCommand.DATA.GetBytes(), .. BitConverter.GetBytes(16), .. content[5..21]],
[.. SyncCommand.DATA.GetBytes(), .. BitConverter.GetBytes(16), .. content[21..37]],
[.. SyncCommand.DATA.GetBytes(), .. BitConverter.GetBytes(3), .. content[37..]],
];

await RunTestAsync(
OkResponses(2),
NoResponseMessages,
["host:transport:169.254.109.177:5555", "sync:"],
[
(SyncCommand.SEND, "/sdcard/test,644"),
(SyncCommand.DONE, "1446505200")
],
[SyncCommand.OKAY],
null,
contentMessages,
async (ctx) =>
{
using SyncService service = new(Socket, Device) { MaxBufferSize = 24 };
await service.PushAsync(stream, "/sdcard/test", UnixFileStatus.StickyBit | UnixFileStatus.UserWrite | UnixFileStatus.OtherRead, new DateTime(2015, 11, 2, 23, 0, 0, DateTimeKind.Utc), cancellationToken: ctx);
Assert.False(service.IsProcessing);
Assert.True(service.IsOutdate);
},
TestContext.Current.CancellationToken);
}

/// <summary>
/// Tests the <see cref="SyncService.IsProcessing"/> field.
/// </summary>
Expand Down Expand Up @@ -818,6 +857,7 @@ .. SyncCommand.DATA.GetBytes(),
.. BitConverter.GetBytes(content.Length),
.. content,
];
SyncProgressChangedEventArgs progress = null;

await RunTestAsync(
OkResponses(2),
Expand All @@ -833,11 +873,16 @@ await RunTestAsync(
async (ctx) =>
{
using SyncService service = new(Socket, Device);
await service.PushAsync(stream, "/sdcard/test", (UnixFileStatus)644, new DateTime(2015, 11, 2, 23, 0, 0, DateTimeKind.Utc), cancellationToken: ctx);
await service.PushAsync(stream, "/sdcard/test", (UnixFileStatus)644, new DateTime(2015, 11, 2, 23, 0, 0, DateTimeKind.Utc), args => progress = args, cancellationToken: ctx);
Assert.False(service.IsProcessing);
Assert.True(service.IsOutdate);
},
TestContext.Current.CancellationToken);

// A random access stream knows its size, so the progress has a total and ends on it
Assert.NotNull(progress);
Assert.Equal((ulong)content.Length, progress.ReceivedBytesSize);
Assert.Equal((ulong)content.Length, progress.TotalBytesToReceive);
}

/// <summary>
Expand Down
38 changes: 38 additions & 0 deletions AdvancedSharpAdbClient.Tests/SyncServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,44 @@ .. BitConverter.GetBytes(content.Length),
});
}

/// <summary>
/// Tests the <see cref="SyncService.Push(Stream, string, UnixFileStatus, DateTimeOffset, Action{SyncProgressChangedEventArgs}?, bool, in bool)"/> method
/// with a stream that returns a short read followed by full reads.
/// </summary>
[Fact]
public void PushShortReadTest()
{
// A 24 byte buffer leaves 16 bytes of data per message
byte[] content = [.. Enumerable.Range(0, 40).Select(x => (byte)x)];
DummyChunkedStream stream = new(content, 5, 16, 16);
byte[][] contentMessages =
[
[.. SyncCommand.DATA.GetBytes(), .. BitConverter.GetBytes(5), .. content[..5]],
[.. SyncCommand.DATA.GetBytes(), .. BitConverter.GetBytes(16), .. content[5..21]],
[.. SyncCommand.DATA.GetBytes(), .. BitConverter.GetBytes(16), .. content[21..37]],
[.. SyncCommand.DATA.GetBytes(), .. BitConverter.GetBytes(3), .. content[37..]],
];

RunTest(
OkResponses(2),
NoResponseMessages,
["host:transport:169.254.109.177:5555", "sync:"],
[
(SyncCommand.SEND, "/sdcard/test,644"),
(SyncCommand.DONE, "1446505200")
],
[SyncCommand.OKAY],
null,
contentMessages,
() =>
{
using SyncService service = new(Socket, Device) { MaxBufferSize = 24 };
service.Push(stream, "/sdcard/test", (UnixFileStatus)644, new DateTime(2015, 11, 2, 23, 0, 0, DateTimeKind.Utc));
Assert.False(service.IsProcessing);
Assert.True(service.IsOutdate);
});
}

/// <summary>
/// Tests the <see cref="SyncService.IsProcessing"/> field.
/// </summary>
Expand Down
17 changes: 8 additions & 9 deletions AdvancedSharpAdbClient/SyncService.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,10 @@ await stream.ReadAsync(buffer, headerSize, maxDataSize, cancellationToken).Confi
// read up to SYNC_DATA_MAX
totalBytesRead += read;

if (read != maxDataSize)
{
// At the end of the line, so we need to recalculate the length of the header
lengthBytes = BitConverter.GetBytes(read);
headerSize = dataBytes.Length + lengthBytes.Length;
}
// A stream may return a short read before its end (pipes, network streams),
// so the header must always carry the length of this read.
lengthBytes = BitConverter.GetBytes(read);
headerSize = dataBytes.Length + lengthBytes.Length;

int startPosition = reservedHeaderSize - headerSize;

Expand Down Expand Up @@ -283,7 +281,7 @@ public virtual async Task PushAsync(IInputStream stream, string remotePath, Unix
{
if (stream is IRandomAccessStream random)
{
totalBytesRead = random.Size;
totalBytesToProcess = random.Size;
}
}
catch { }
Expand All @@ -300,9 +298,10 @@ public virtual async Task PushAsync(IInputStream stream, string remotePath, Unix
{
break;
}
else if (read != maxDataSize)
else
{
// At the end of the line, so we need to recalculate the length of the header
// A stream may return a short read before its end (pipes, network streams),
// so the header must always carry the length of this read.
lengthBytes = BitConverter.GetBytes(read);
headerSize = dataBytes.Length + lengthBytes.Length;
}
Expand Down
10 changes: 4 additions & 6 deletions AdvancedSharpAdbClient/SyncService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,10 @@ public virtual void Push(Stream stream, string remotePath, UnixFileStatus permis
// read up to SYNC_DATA_MAX
totalBytesRead += read;

if (read != maxDataSize)
{
// At the end of the line, so we need to recalculate the length of the header
lengthBytes = BitConverter.GetBytes(read);
headerSize = dataBytes.Length + lengthBytes.Length;
}
// A stream may return a short read before its end (pipes, network streams),
// so the header must always carry the length of this read.
lengthBytes = BitConverter.GetBytes(read);
headerSize = dataBytes.Length + lengthBytes.Length;

int startPosition = reservedHeaderSize - headerSize;

Expand Down
Loading