Commit c298c892 authored by Jon Skeet's avatar Jon Skeet

New tests, double build errors, and a few miscellaneous fixes

parent a6afb7cd
...@@ -61,6 +61,7 @@ namespace Google.ProtocolBuffers { ...@@ -61,6 +61,7 @@ namespace Google.ProtocolBuffers {
input = CodedInputStream.CreateInstance(data); input = CodedInputStream.CreateInstance(data);
Assert.AreEqual(value, input.ReadRawVarint64()); Assert.AreEqual(value, input.ReadRawVarint64());
Assert.IsTrue(input.IsAtEnd);
// Try different block sizes. // Try different block sizes.
for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) { for (int bufferSize = 1; bufferSize <= 16; bufferSize *= 2) {
...@@ -69,7 +70,18 @@ namespace Google.ProtocolBuffers { ...@@ -69,7 +70,18 @@ namespace Google.ProtocolBuffers {
input = CodedInputStream.CreateInstance(new SmallBlockInputStream(data, bufferSize)); input = CodedInputStream.CreateInstance(new SmallBlockInputStream(data, bufferSize));
Assert.AreEqual(value, input.ReadRawVarint64()); Assert.AreEqual(value, input.ReadRawVarint64());
Assert.IsTrue(input.IsAtEnd);
} }
// Try reading directly from a MemoryStream. We want to verify that it
// doesn't read past the end of the input, so write an extra byte - this
// lets us test the position at the end.
MemoryStream memoryStream = new MemoryStream();
memoryStream.Write(data, 0, data.Length);
memoryStream.WriteByte(0);
memoryStream.Position = 0;
Assert.AreEqual((uint)value, CodedInputStream.ReadRawVarint32(memoryStream));
Assert.AreEqual(data.Length, memoryStream.Position);
} }
/// <summary> /// <summary>
...@@ -77,7 +89,7 @@ namespace Google.ProtocolBuffers { ...@@ -77,7 +89,7 @@ namespace Google.ProtocolBuffers {
/// expects them to fail with an InvalidProtocolBufferException whose /// expects them to fail with an InvalidProtocolBufferException whose
/// description matches the given one. /// description matches the given one.
/// </summary> /// </summary>
private void AssertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data) { private static void AssertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data) {
CodedInputStream input = CodedInputStream.CreateInstance(data); CodedInputStream input = CodedInputStream.CreateInstance(data);
try { try {
input.ReadRawVarint32(); input.ReadRawVarint32();
...@@ -93,6 +105,14 @@ namespace Google.ProtocolBuffers { ...@@ -93,6 +105,14 @@ namespace Google.ProtocolBuffers {
} catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) {
Assert.AreEqual(expected.Message, e.Message); Assert.AreEqual(expected.Message, e.Message);
} }
// Make sure we get the same error when reading directly from a Stream.
try {
CodedInputStream.ReadRawVarint32(new MemoryStream(data));
Assert.Fail("Should have thrown an exception.");
} catch (InvalidProtocolBufferException e) {
Assert.AreEqual(expected.Message, e.Message);
}
} }
[Test] [Test]
...@@ -139,12 +159,14 @@ namespace Google.ProtocolBuffers { ...@@ -139,12 +159,14 @@ namespace Google.ProtocolBuffers {
private static void AssertReadLittleEndian32(byte[] data, uint value) { private static void AssertReadLittleEndian32(byte[] data, uint value) {
CodedInputStream input = CodedInputStream.CreateInstance(data); CodedInputStream input = CodedInputStream.CreateInstance(data);
Assert.AreEqual(value, input.ReadRawLittleEndian32()); Assert.AreEqual(value, input.ReadRawLittleEndian32());
Assert.IsTrue(input.IsAtEnd);
// Try different block sizes. // Try different block sizes.
for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
input = CodedInputStream.CreateInstance( input = CodedInputStream.CreateInstance(
new SmallBlockInputStream(data, blockSize)); new SmallBlockInputStream(data, blockSize));
Assert.AreEqual(value, input.ReadRawLittleEndian32()); Assert.AreEqual(value, input.ReadRawLittleEndian32());
Assert.IsTrue(input.IsAtEnd);
} }
} }
...@@ -155,12 +177,14 @@ namespace Google.ProtocolBuffers { ...@@ -155,12 +177,14 @@ namespace Google.ProtocolBuffers {
private static void AssertReadLittleEndian64(byte[] data, ulong value) { private static void AssertReadLittleEndian64(byte[] data, ulong value) {
CodedInputStream input = CodedInputStream.CreateInstance(data); CodedInputStream input = CodedInputStream.CreateInstance(data);
Assert.AreEqual(value, input.ReadRawLittleEndian64()); Assert.AreEqual(value, input.ReadRawLittleEndian64());
Assert.IsTrue(input.IsAtEnd);
// Try different block sizes. // Try different block sizes.
for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
input = CodedInputStream.CreateInstance( input = CodedInputStream.CreateInstance(
new SmallBlockInputStream(data, blockSize)); new SmallBlockInputStream(data, blockSize));
Assert.AreEqual(value, input.ReadRawLittleEndian64()); Assert.AreEqual(value, input.ReadRawLittleEndian64());
Assert.IsTrue(input.IsAtEnd);
} }
} }
...@@ -239,6 +263,21 @@ namespace Google.ProtocolBuffers { ...@@ -239,6 +263,21 @@ namespace Google.ProtocolBuffers {
} }
} }
/// <summary>
/// Test that a bug in SkipRawBytes has been fixed: if the skip
/// skips exactly up to a limit, this should bnot break things
/// </summary>
[Test]
public void SkipRawBytesBug() {
byte[] rawBytes = new byte[] { 1, 2 };
CodedInputStream input = CodedInputStream.CreateInstance(rawBytes);
int limit = input.PushLimit(1);
input.SkipRawBytes(1);
input.PopLimit(limit);
Assert.AreEqual(2, input.ReadRawByte());
}
public void ReadHugeBlob() { public void ReadHugeBlob() {
// Allocate and initialize a 1MB blob. // Allocate and initialize a 1MB blob.
byte[] blob = new byte[1 << 20]; byte[] blob = new byte[1 << 20];
...@@ -348,6 +387,31 @@ namespace Google.ProtocolBuffers { ...@@ -348,6 +387,31 @@ namespace Google.ProtocolBuffers {
} }
} }
[Test]
public void ResetSizeCounter() {
CodedInputStream input = CodedInputStream.CreateInstance(
new SmallBlockInputStream(new byte[256], 8));
input.SetSizeLimit(16);
input.ReadRawBytes(16);
try {
input.ReadRawByte();
Assert.Fail("Should have thrown an exception!");
} catch (InvalidProtocolBufferException e) {
// Success.
}
input.ResetSizeCounter();
input.ReadRawByte(); // No exception thrown.
try {
input.ReadRawBytes(16); // Hits limit again.
Assert.Fail("Should have thrown an exception!");
} catch (InvalidProtocolBufferException e) {
// Success.
}
}
/// <summary> /// <summary>
/// Tests that if we read an string that contains invalid UTF-8, no exception /// Tests that if we read an string that contains invalid UTF-8, no exception
/// is thrown. Instead, the invalid bytes are replaced with the Unicode /// is thrown. Instead, the invalid bytes are replaced with the Unicode
......
...@@ -32,6 +32,7 @@ using Google.ProtocolBuffers.TestProtos; ...@@ -32,6 +32,7 @@ using Google.ProtocolBuffers.TestProtos;
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using NUnit.Framework; using NUnit.Framework;
using System;
namespace Google.ProtocolBuffers { namespace Google.ProtocolBuffers {
[TestFixture] [TestFixture]
...@@ -56,6 +57,18 @@ namespace Google.ProtocolBuffers { ...@@ -56,6 +57,18 @@ namespace Google.ProtocolBuffers {
reflectionTester.AssertAllFieldsSetViaReflection(message); reflectionTester.AssertAllFieldsSetViaReflection(message);
} }
[Test]
public void DoubleBuildError() {
DynamicMessage.Builder builder = DynamicMessage.CreateBuilder(TestAllTypes.Descriptor);
builder.Build();
try {
builder.Build();
Assert.Fail("Should have thrown exception.");
} catch (InvalidOperationException e) {
// Success.
}
}
[Test] [Test]
public void DynamicMessageSettersRejectNull() { public void DynamicMessageSettersRejectNull() {
IBuilder builder = DynamicMessage.CreateBuilder(TestAllTypes.Descriptor); IBuilder builder = DynamicMessage.CreateBuilder(TestAllTypes.Descriptor);
......
...@@ -90,6 +90,18 @@ namespace Google.ProtocolBuffers { ...@@ -90,6 +90,18 @@ namespace Google.ProtocolBuffers {
} }
} }
[Test]
public void DoubleBuildError() {
TestAllTypes.Builder builder = new TestAllTypes.Builder();
builder.Build();
try {
builder.Build();
Assert.Fail("Should have thrown exception.");
} catch (InvalidOperationException e) {
// Success.
}
}
[Test] [Test]
public void DefaultInstance() { public void DefaultInstance() {
Assert.AreSame(TestAllTypes.DefaultInstance, TestAllTypes.DefaultInstance.DefaultInstanceForType); Assert.AreSame(TestAllTypes.DefaultInstance, TestAllTypes.DefaultInstance.DefaultInstanceForType);
...@@ -367,7 +379,7 @@ namespace Google.ProtocolBuffers { ...@@ -367,7 +379,7 @@ namespace Google.ProtocolBuffers {
} }
[Test] [Test]
public void TestOptimizedForSizeMergeUsesAllFieldsFromTarget() { public void OptimizedForSizeMergeUsesAllFieldsFromTarget() {
TestOptimizedForSize withFieldSet = new TestOptimizedForSize.Builder { I = 10 }.Build(); TestOptimizedForSize withFieldSet = new TestOptimizedForSize.Builder { I = 10 }.Build();
TestOptimizedForSize.Builder builder = new TestOptimizedForSize.Builder(); TestOptimizedForSize.Builder builder = new TestOptimizedForSize.Builder();
builder.MergeFrom(withFieldSet); builder.MergeFrom(withFieldSet);
......
...@@ -226,7 +226,7 @@ namespace Google.ProtocolBuffers { ...@@ -226,7 +226,7 @@ namespace Google.ProtocolBuffers {
} }
public TBuilder MergeDelimitedFrom(Stream input, ExtensionRegistry extensionRegistry) { public TBuilder MergeDelimitedFrom(Stream input, ExtensionRegistry extensionRegistry) {
int size = CodedInputStream.ReadRawVarint32(input); int size = (int) CodedInputStream.ReadRawVarint32(input);
Stream limitedStream = new LimitedInputStream(input, size); Stream limitedStream = new LimitedInputStream(input, size);
return MergeFrom(limitedStream, extensionRegistry); return MergeFrom(limitedStream, extensionRegistry);
} }
......
...@@ -466,7 +466,7 @@ namespace Google.ProtocolBuffers { ...@@ -466,7 +466,7 @@ namespace Google.ProtocolBuffers {
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <returns></returns> /// <returns></returns>
internal static int ReadRawVarint32(Stream input) { internal static uint ReadRawVarint32(Stream input) {
int result = 0; int result = 0;
int offset = 0; int offset = 0;
for (; offset < 32; offset += 7) { for (; offset < 32; offset += 7) {
...@@ -476,7 +476,7 @@ namespace Google.ProtocolBuffers { ...@@ -476,7 +476,7 @@ namespace Google.ProtocolBuffers {
} }
result |= (b & 0x7f) << offset; result |= (b & 0x7f) << offset;
if ((b & 0x80) == 0) { if ((b & 0x80) == 0) {
return result; return (uint) result;
} }
} }
// Keep reading up to 64 bits. // Keep reading up to 64 bits.
...@@ -486,7 +486,7 @@ namespace Google.ProtocolBuffers { ...@@ -486,7 +486,7 @@ namespace Google.ProtocolBuffers {
throw InvalidProtocolBufferException.TruncatedMessage(); throw InvalidProtocolBufferException.TruncatedMessage();
} }
if ((b & 0x80) == 0) { if ((b & 0x80) == 0) {
return result; return (uint) result;
} }
} }
throw InvalidProtocolBufferException.MalformedVarint(); throw InvalidProtocolBufferException.MalformedVarint();
...@@ -918,16 +918,33 @@ namespace Google.ProtocolBuffers { ...@@ -918,16 +918,33 @@ namespace Google.ProtocolBuffers {
// Then skip directly from the InputStream for the rest. // Then skip directly from the InputStream for the rest.
if (pos < size) { if (pos < size) {
// TODO(jonskeet): Java implementation uses skip(). Not sure whether this is really equivalent...
if (input == null) { if (input == null) {
throw InvalidProtocolBufferException.TruncatedMessage(); throw InvalidProtocolBufferException.TruncatedMessage();
} }
SkipImpl(size - pos);
totalBytesRetired += size - pos;
}
}
}
/// <summary>
/// Abstraction of skipping to cope with streams which can't really skip.
/// </summary>
private void SkipImpl(int amountToSkip) {
if (input.CanSeek) {
long previousPosition = input.Position; long previousPosition = input.Position;
input.Position += size - pos; input.Position += amountToSkip;
if (input.Position != previousPosition + size - pos) { if (input.Position != previousPosition + amountToSkip) {
throw InvalidProtocolBufferException.TruncatedMessage(); throw InvalidProtocolBufferException.TruncatedMessage();
} }
totalBytesRetired += size - pos; } else {
byte[] skipBuffer = new byte[1024];
while (amountToSkip > 0) {
int bytesRead = input.Read(skipBuffer, 0, skipBuffer.Length);
if (bytesRead <= 0) {
throw InvalidProtocolBufferException.TruncatedMessage();
}
amountToSkip -= bytesRead;
} }
} }
} }
......
...@@ -109,8 +109,7 @@ namespace Google.ProtocolBuffers.Descriptors { ...@@ -109,8 +109,7 @@ namespace Google.ProtocolBuffers.Descriptors {
"package) in file \"" + old.File.Name + "\"."); "package) in file \"" + old.File.Name + "\".");
} }
} }
// TODO(jonskeet): Check issue 25 wrt the ordering of these parameters descriptorsByName[fullName] = new PackageDescriptor(name, fullName, file);
descriptorsByName[fullName] = new PackageDescriptor(fullName, name, file);
} }
/// <summary> /// <summary>
......
...@@ -296,7 +296,7 @@ namespace Google.ProtocolBuffers { ...@@ -296,7 +296,7 @@ namespace Google.ProtocolBuffers {
} }
public override DynamicMessage Build() { public override DynamicMessage Build() {
if (!IsInitialized) { if (fields != null && !IsInitialized) {
throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields)); throw new UninitializedMessageException(new DynamicMessage(type, fields, unknownFields));
} }
return BuildPartial(); return BuildPartial();
...@@ -315,6 +315,9 @@ namespace Google.ProtocolBuffers { ...@@ -315,6 +315,9 @@ namespace Google.ProtocolBuffers {
} }
public override DynamicMessage BuildPartial() { public override DynamicMessage BuildPartial() {
if (fields == null) {
throw new InvalidOperationException("Build() has already been called on this Builder.");
}
fields.MakeImmutable(); fields.MakeImmutable();
DynamicMessage result = new DynamicMessage(type, fields, unknownFields); DynamicMessage result = new DynamicMessage(type, fields, unknownFields);
fields = null; fields = null;
......
...@@ -187,7 +187,8 @@ namespace Google.ProtocolBuffers { ...@@ -187,7 +187,8 @@ namespace Google.ProtocolBuffers {
/// Implementation of <see cref="IBuilder{TMessage, TBuilder}.Build" />. /// Implementation of <see cref="IBuilder{TMessage, TBuilder}.Build" />.
/// </summary> /// </summary>
public override TMessage Build() { public override TMessage Build() {
if (!IsInitialized) { // If the message is null, we'll throw a more appropriate exception in BuildPartial.
if (MessageBeingBuilt != null && !IsInitialized) {
throw new UninitializedMessageException(MessageBeingBuilt); throw new UninitializedMessageException(MessageBeingBuilt);
} }
return BuildPartial(); return BuildPartial();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment