Skip to content

Commit

Permalink
Allow redundant use of the metadata command
Browse files Browse the repository at this point in the history
This clarifies the use of the metadata command: If a non-zero metadata
count is present, the metadata command must be specified exactly
once. If the metadata count is zero, the metadata command may be
specified at most once.

Fix #29
  • Loading branch information
io7m committed Jan 10, 2017
1 parent 433d581 commit e0b8f21
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 11 deletions.
7 changes: 7 additions & 0 deletions README-CHANGES.xml
Expand Up @@ -6,6 +6,13 @@
<c:date>2017-01-09</c:date>
<c:version>0.6.0</c:version>

<c:item>
<c:date>2017-01-09</c:date>
<c:type-code-change/>
<c:ticket>29</c:ticket>
<c:summary>Allow redundant use of the metadata command.</c:summary>
</c:item>

<c:item>
<c:date>2017-01-09</c:date>
<c:type-code-change/>
Expand Down
Expand Up @@ -51,7 +51,8 @@ final class SMFTV1BodyParser extends SMFTAbstractParser
private Map<SMFAttributeName, Boolean> attributes_ok;
private Map<SMFAttributeName, Boolean> attributes_attempted;
private long parsed_triangles;
private long parsed_metas;
private long metas_parsed_count;
private boolean metas_started;

SMFTV1BodyParser(
final SMFTAbstractParser in_parent,
Expand Down Expand Up @@ -131,7 +132,7 @@ private void onEOF()

private void failMissedMetadata()
{
if (this.parsed_metas != this.header.metaCount()) {
if (this.metas_parsed_count != this.header.metaCount()) {
this.fail("Too few metadata elements specified", Optional.empty());
}
}
Expand Down Expand Up @@ -577,13 +578,16 @@ private void parseMetas()
{
LOG.debug("parsing metadata values");

if (this.header.metaCount() == 0L) {
super.fail("No metadata was expected.", Optional.empty());
if (this.metas_started) {
super.fail(
"A metadata command has already been specified.",
Optional.empty());
return;
}

this.parsed_metas = 0L;
while (this.parsed_metas != this.header.metaCount()) {
this.metas_started = true;
this.metas_parsed_count = 0L;
while (this.metas_parsed_count != this.header.metaCount()) {
if (this.parserHasFailed()) {
return;
}
Expand Down Expand Up @@ -614,7 +618,7 @@ private void parseMetas()
}
}

this.parsed_metas = Math.addExact(this.parsed_metas, 1L);
this.metas_parsed_count = Math.addExact(this.metas_parsed_count, 1L);
}
}

Expand Down
Expand Up @@ -278,10 +278,9 @@ The command takes no arguments.
[paragraph]
The command may only appear in the file after all
[link [target smft.data.commands.triangles] triangles] and
[link [target smft.data.commands.attribute] attributes] have been received.



[link [target smft.data.commands.attribute] attributes] have been received. If
the file does not have metadata, the command may be omitted. If the file does
have metadata, the command must be specified exactly once.

[subsection [title Data - meta] [id smft.data.commands.meta]]
[paragraph]
Expand Down
Expand Up @@ -2896,6 +2896,182 @@ public void testSerializerAttributeNotFinishedSerializingPrevious()
serializer.serializeData(SMFAttributeName.of("y"));
}

@Test
public void testMetaNoneNotOmitted(
final @Mocked SMFParserEventsType events)
{
final StringBuilder s = new StringBuilder(128);
s.append("smf 1 0");
s.append(System.lineSeparator());
s.append("schema 696F376D A0B0C0D0 1 2");
s.append(System.lineSeparator());
s.append("coordinates +x +y -z counter-clockwise");
s.append(System.lineSeparator());
s.append("attribute a integer-unsigned 1 32");
s.append(System.lineSeparator());
s.append("vertices 1");
s.append(System.lineSeparator());
s.append("triangles 1 16");
s.append(System.lineSeparator());
s.append("data");
s.append(System.lineSeparator());
s.append("attribute a");
s.append(System.lineSeparator());
s.append("0");
s.append(System.lineSeparator());
s.append("triangles");
s.append(System.lineSeparator());
s.append("0 0 0");
s.append(System.lineSeparator());
s.append("metadata");
s.append(System.lineSeparator());

final SMFAttribute attribute = SMFAttribute.of(
SMFAttributeName.of("a"),
SMFComponentType.ELEMENT_TYPE_INTEGER_UNSIGNED,
1,
32);

final SMFHeader.Builder header_b = baseHeader(List.of(attribute));
header_b.setTriangleCount(1L);
header_b.setVertexCount(1L);
final SMFHeader h = header_b.build();

new StrictExpectations()
{{
events.onStart();
events.onVersionReceived(SMFFormatVersion.of(1, 0));
events.onHeaderParsed(h);
events.onDataAttributeStart(attribute);
events.onDataAttributeValueIntegerUnsigned1(0L);
events.onDataAttributeFinish(attribute);
events.onDataTrianglesStart();
events.onDataTriangle(0L, 0L, 0L);
events.onDataTrianglesFinish();
events.onFinish();
}};

runForText(events, true, s);
}

@Test
public void testMetaNoneOmitted(
final @Mocked SMFParserEventsType events)
{
final StringBuilder s = new StringBuilder(128);
s.append("smf 1 0");
s.append(System.lineSeparator());
s.append("schema 696F376D A0B0C0D0 1 2");
s.append(System.lineSeparator());
s.append("coordinates +x +y -z counter-clockwise");
s.append(System.lineSeparator());
s.append("attribute a integer-unsigned 1 32");
s.append(System.lineSeparator());
s.append("vertices 1");
s.append(System.lineSeparator());
s.append("triangles 1 16");
s.append(System.lineSeparator());
s.append("data");
s.append(System.lineSeparator());
s.append("attribute a");
s.append(System.lineSeparator());
s.append("0");
s.append(System.lineSeparator());
s.append("triangles");
s.append(System.lineSeparator());
s.append("0 0 0");
s.append(System.lineSeparator());

final SMFAttribute attribute = SMFAttribute.of(
SMFAttributeName.of("a"),
SMFComponentType.ELEMENT_TYPE_INTEGER_UNSIGNED,
1,
32);

final SMFHeader.Builder header_b = baseHeader(List.of(attribute));
header_b.setTriangleCount(1L);
header_b.setVertexCount(1L);
final SMFHeader h = header_b.build();

new StrictExpectations()
{{
events.onStart();
events.onVersionReceived(SMFFormatVersion.of(1, 0));
events.onHeaderParsed(h);
events.onDataAttributeStart(attribute);
events.onDataAttributeValueIntegerUnsigned1(0L);
events.onDataAttributeFinish(attribute);
events.onDataTrianglesStart();
events.onDataTriangle(0L, 0L, 0L);
events.onDataTrianglesFinish();
events.onFinish();
}};

runForText(events, true, s);
}

@Test
public void testMetaTwice(
final @Mocked SMFParserEventsType events)
{
final StringBuilder s = new StringBuilder(128);
s.append("smf 1 0");
s.append(System.lineSeparator());
s.append("schema 696F376D A0B0C0D0 1 2");
s.append(System.lineSeparator());
s.append("coordinates +x +y -z counter-clockwise");
s.append(System.lineSeparator());
s.append("attribute a integer-unsigned 1 32");
s.append(System.lineSeparator());
s.append("vertices 1");
s.append(System.lineSeparator());
s.append("triangles 1 16");
s.append(System.lineSeparator());
s.append("data");
s.append(System.lineSeparator());
s.append("attribute a");
s.append(System.lineSeparator());
s.append("0");
s.append(System.lineSeparator());
s.append("triangles");
s.append(System.lineSeparator());
s.append("0 0 0");
s.append(System.lineSeparator());
s.append("metadata");
s.append(System.lineSeparator());
s.append("metadata");
s.append(System.lineSeparator());

final SMFAttribute attribute = SMFAttribute.of(
SMFAttributeName.of("a"),
SMFComponentType.ELEMENT_TYPE_INTEGER_UNSIGNED,
1,
32);

final SMFHeader.Builder header_b = baseHeader(List.of(attribute));
header_b.setTriangleCount(1L);
header_b.setVertexCount(1L);
final SMFHeader h = header_b.build();

new StrictExpectations()
{{
events.onStart();
events.onVersionReceived(SMFFormatVersion.of(1, 0));
events.onHeaderParsed(h);
events.onDataAttributeStart(attribute);
events.onDataAttributeValueIntegerUnsigned1(0L);
events.onDataAttributeFinish(attribute);
events.onDataTrianglesStart();
events.onDataTriangle(0L, 0L, 0L);
events.onDataTrianglesFinish();
events.onError(this.withArgThat(
new ParseErrorMessageStartsWith("A metadata command has already been specified.")));
events.onFinish();
}};

runForText(events, true, s);
}

private static class ParseErrorMessageStartsWith extends TypeSafeMatcher<SMFParseError>
{
private final String message;
Expand Down

0 comments on commit e0b8f21

Please sign in to comment.