/** * Copyright 2011-2017 Asakusa Framework Team. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asakusafw.dmdl.parser; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.math.BigInteger; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.asakusafw.dmdl.DmdlTesterRoot; import com.asakusafw.dmdl.model.AstAttribute; import com.asakusafw.dmdl.model.AstAttributeElement; import com.asakusafw.dmdl.model.AstAttributeValue; import com.asakusafw.dmdl.model.AstAttributeValueArray; import com.asakusafw.dmdl.model.AstAttributeValueMap; import com.asakusafw.dmdl.model.AstBasicType; import com.asakusafw.dmdl.model.AstCollectionType; import com.asakusafw.dmdl.model.AstCollectionType.CollectionKind; import com.asakusafw.dmdl.model.AstExpression; import com.asakusafw.dmdl.model.AstJoin; import com.asakusafw.dmdl.model.AstLiteral; import com.asakusafw.dmdl.model.AstModelDefinition; import com.asakusafw.dmdl.model.AstModelReference; import com.asakusafw.dmdl.model.AstPropertyDefinition; import com.asakusafw.dmdl.model.AstQualifiedName; import com.asakusafw.dmdl.model.AstRecord; import com.asakusafw.dmdl.model.AstRecordDefinition; import com.asakusafw.dmdl.model.AstScript; import com.asakusafw.dmdl.model.AstSimpleName; import com.asakusafw.dmdl.model.AstSummarize; import com.asakusafw.dmdl.model.AstTerm; import com.asakusafw.dmdl.model.AstType; import com.asakusafw.dmdl.model.AstUnionExpression; import com.asakusafw.dmdl.model.BasicTypeKind; import com.asakusafw.dmdl.model.LiteralKind; /** * Test for {@link DmdlParser}. */ public class DmdlParserTest extends DmdlTesterRoot { static final Logger LOG = LoggerFactory.getLogger(DmdlParserTest.class); /** * Parse a simple record definition. */ @Test public void record_simple() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstRecord> record = getRecord(script, "simple"); assertThat(record.description, is(nullValue())); assertThat(record.attributes.isEmpty(), is(true)); List<AstRecord> terms = extract(record.expression); assertThat(terms.size(), is(1)); AstRecord term = terms.get(0); assertThat(term, instanceOf(AstRecordDefinition.class)); AstRecordDefinition def = (AstRecordDefinition) term; assertThat(def.properties.size(), is(1)); AstPropertyDefinition pdef = def.properties.get(0); assertThat(pdef.description, is(nullValue())); assertThat(pdef.attributes.isEmpty(), is(true)); assertThat(pdef.name.identifier, is("a")); assertThat(pdef.type, is(astType(BasicTypeKind.INT))); } /** * Parse a simple record definition with a model reference. */ @Test public void record_reference() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstRecord> record = getRecord(script, "simple"); List<AstRecord> terms = extract(record.expression); assertThat(terms.size(), is(1)); assertThat(terms.get(0), instanceOf(AstModelReference.class)); AstModelReference ref = (AstModelReference) terms.get(0); assertThat(ref.name.identifier, is("other")); } /** * Parse a record definition with multi references. */ @Test public void record_multi_reference() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstRecord> record = getRecord(script, "simple"); List<AstRecord> terms = extract(record.expression); assertThat(terms.size(), is(3)); assertThat(terms.get(0), instanceOf(AstModelReference.class)); assertThat(terms.get(1), instanceOf(AstModelReference.class)); assertThat(terms.get(2), instanceOf(AstModelReference.class)); AstModelReference a = (AstModelReference) terms.get(0); AstModelReference b = (AstModelReference) terms.get(1); AstModelReference c = (AstModelReference) terms.get(2); assertThat(a.name.identifier, is("a")); assertThat(b.name.identifier, is("b")); assertThat(c.name.identifier, is("c")); } /** * Parse a record definition with mixed terms. */ @Test public void record_mixed() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstRecord> record = getRecord(script, "simple"); List<AstRecord> terms = extract(record.expression); assertThat(terms.size(), is(3)); assertThat(terms.get(0), instanceOf(AstModelReference.class)); assertThat(terms.get(1), instanceOf(AstModelReference.class)); assertThat(terms.get(2), instanceOf(AstRecordDefinition.class)); AstModelReference a = (AstModelReference) terms.get(0); AstModelReference b = (AstModelReference) terms.get(1); AstRecordDefinition def = (AstRecordDefinition) terms.get(2); assertThat(a.name.identifier, is("a")); assertThat(b.name.identifier, is("b")); assertThat(def.properties.size(), is(1)); assertThat(def.properties.get(0).name.identifier, is("c")); } /** * Parse a simple projection definition. */ @Test public void projective_simple() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstRecord> record = getProjection(script, "simple"); assertThat(record.description, is(nullValue())); assertThat(record.attributes.isEmpty(), is(true)); List<AstRecord> terms = extract(record.expression); assertThat(terms.size(), is(1)); AstRecord term = terms.get(0); assertThat(term, instanceOf(AstRecordDefinition.class)); AstRecordDefinition def = (AstRecordDefinition) term; assertThat(def.properties.size(), is(1)); AstPropertyDefinition pdef = def.properties.get(0); assertThat(pdef.description, is(nullValue())); assertThat(pdef.attributes.isEmpty(), is(true)); assertThat(pdef.name.identifier, is("a")); assertThat(pdef.type, is(astType(BasicTypeKind.INT))); } /** * Parse a simple join model definition. */ @Test public void join_simple() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstJoin> joined = getJoined(script, "simple"); List<AstJoin> terms = extract(joined.expression); assertThat(terms.size(), is(2)); AstJoin left = terms.get(0); AstJoin right = terms.get(1); assertThat(left.reference.name.identifier, is("left")); assertThat(left.mapping, is(nullValue())); assertThat(left.grouping, is(nullValue())); assertThat(right.reference.name.identifier, is("right")); assertThat(right.mapping, is(nullValue())); assertThat(right.grouping, is(nullValue())); } /** * Parse a join model definition with model mappings. */ @Test public void join_mapping() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstJoin> joined = getJoined(script, "simple"); List<AstJoin> terms = extract(joined.expression); assertThat(terms.size(), is(2)); AstJoin left = terms.get(0); AstJoin right = terms.get(1); assertThat(left.reference.name.identifier, is("left")); assertThat(left.mapping, not(nullValue())); assertThat(left.mapping.properties.size(), is(1)); assertThat(left.mapping.properties.get(0).source.identifier, is("a")); assertThat(left.mapping.properties.get(0).target.identifier, is("b")); assertThat(right.reference.name.identifier, is("right")); assertThat(right.mapping, not(nullValue())); assertThat(right.mapping.properties.size(), is(2)); assertThat(right.mapping.properties.get(0).source.identifier, is("a")); assertThat(right.mapping.properties.get(0).target.identifier, is("c")); assertThat(right.mapping.properties.get(1).source.identifier, is("b")); assertThat(right.mapping.properties.get(1).target.identifier, is("d")); } /** * Parse a join model definition with join conditions. */ @Test public void join_grouping() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstJoin> joined = getJoined(script, "simple"); List<AstJoin> terms = extract(joined.expression); assertThat(terms.size(), is(2)); AstJoin left = terms.get(0); AstJoin right = terms.get(1); assertThat(left.reference.name.identifier, is("left")); assertThat(left.grouping, not(nullValue())); assertThat(left.grouping.properties.size(), is(1)); assertThat(left.grouping.properties.get(0).identifier, is("a")); assertThat(right.reference.name.identifier, is("right")); assertThat(right.grouping, not(nullValue())); assertThat(right.grouping.properties.size(), is(3)); assertThat(right.grouping.properties.get(0).identifier, is("a")); assertThat(right.grouping.properties.get(1).identifier, is("b")); assertThat(right.grouping.properties.get(2).identifier, is("c")); } /** * Parse a simple summarized model definition. */ @Test public void summarize_simple() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstSummarize> summarized = getSummarized(script, "simple"); List<AstSummarize> terms = extract(summarized.expression); assertThat(terms.size(), is(1)); AstSummarize term = terms.get(0); assertThat(term.reference.name.identifier, is("source")); assertThat(term.folding.properties.size(), is(1)); assertThat(term.folding.properties.get(0).aggregator.toString(), is("any")); assertThat(term.folding.properties.get(0).source.toString(), is("a")); assertThat(term.folding.properties.get(0).target.toString(), is("b")); assertThat(term.grouping, is(nullValue())); } /** * Parse a summarized model definition with multi foldings. */ @Test public void summarize_multi_folding() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstSummarize> summarized = getSummarized(script, "simple"); List<AstSummarize> terms = extract(summarized.expression); assertThat(terms.size(), is(1)); AstSummarize term = terms.get(0); assertThat(term.reference.name.identifier, is("source")); assertThat(term.folding.properties.size(), is(3)); assertThat(term.folding.properties.get(0).aggregator.toString(), is("any")); assertThat(term.folding.properties.get(0).source.toString(), is("a")); assertThat(term.folding.properties.get(0).target.toString(), is("a")); assertThat(term.folding.properties.get(1).aggregator.toString(), is("count")); assertThat(term.folding.properties.get(1).source.toString(), is("b")); assertThat(term.folding.properties.get(1).target.toString(), is("b")); assertThat(term.folding.properties.get(2).aggregator.toString(), is("com.asakusafw.aggregate")); assertThat(term.folding.properties.get(2).source.toString(), is("c")); assertThat(term.folding.properties.get(2).target.toString(), is("d")); assertThat(term.grouping, is(nullValue())); } /** * Parse a simple summarized model definition. */ @Test public void summarize_grouping() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<AstSummarize> summarized = getSummarized(script, "simple"); List<AstSummarize> terms = extract(summarized.expression); assertThat(terms.size(), is(1)); AstSummarize term = terms.get(0); assertThat(term.reference.name.identifier, is("source")); assertThat(term.folding.properties.size(), is(1)); assertThat(term.grouping, not(nullValue())); assertThat(term.grouping.properties.size(), is(1)); assertThat(term.grouping.properties.get(0).identifier, is("category")); } /** * Parse a model with description. */ @Test public void model_description() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<?> model = script.models.get(0); assertThat(model.description, not(nullValue())); assertThat(model.description.token, is("\"With Description\"")); } /** * Parse a model with an attribute. */ @Test public void model_attribute() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<?> model = script.models.get(0); assertThat(model.attributes.size(), is(1)); AstAttribute attribute = model.attributes.get(0); assertThat(attribute.name.toString(), is("attr")); assertThat(attribute.elements.isEmpty(), is(true)); } /** * Parse a model with many attributes. */ @Test public void model_multi_attribute() { AstScript script = load(); assertThat(script.models.size(), is(1)); AstModelDefinition<?> model = script.models.get(0); assertThat(model.attributes.size(), is(3)); assertThat(model.attributes.get(0).name.toString(), is("a")); assertThat(model.attributes.get(1).name.toString(), is("b")); assertThat(model.attributes.get(2).name.toString(), is("c")); } /** * Parse a property with description. */ @Test public void property_description() { AstRecordDefinition def = loadFirstTermAs(AstRecordDefinition.class); assertThat(def.properties.size(), is(1)); AstPropertyDefinition prop = def.properties.get(0); assertThat(prop.description, not(nullValue())); assertThat(prop.description.token, is("\"With Description\"")); } /** * Parse a property with an attribute. */ @Test public void property_attribute() { AstRecordDefinition def = loadFirstTermAs(AstRecordDefinition.class); assertThat(def.properties.size(), is(1)); AstPropertyDefinition prop = def.properties.get(0); assertThat(prop.attributes.size(), is(1)); AstAttribute attribute = prop.attributes.get(0); assertThat(attribute.name.toString(), is("attr")); assertThat(attribute.elements.isEmpty(), is(true)); } /** * Parse a property with many attributes. */ @Test public void property_multi_attribute() { AstRecordDefinition def = loadFirstTermAs(AstRecordDefinition.class); assertThat(def.properties.size(), is(1)); AstPropertyDefinition prop = def.properties.get(0); assertThat(prop.attributes.size(), is(3)); assertThat(prop.attributes.get(0).name.toString(), is("a")); assertThat(prop.attributes.get(1).name.toString(), is("b")); assertThat(prop.attributes.get(2).name.toString(), is("c")); } /** * Parse all basic types. */ @Test public void basic_type() { AstRecordDefinition def = loadFirstTermAs(AstRecordDefinition.class); assertThat(getProp(def, "p_int").type, is(astType(BasicTypeKind.INT))); assertThat(getProp(def, "p_long").type, is(astType(BasicTypeKind.LONG))); assertThat(getProp(def, "p_byte").type, is(astType(BasicTypeKind.BYTE))); assertThat(getProp(def, "p_short").type, is(astType(BasicTypeKind.SHORT))); assertThat(getProp(def, "p_decimal").type, is(astType(BasicTypeKind.DECIMAL))); assertThat(getProp(def, "p_float").type, is(astType(BasicTypeKind.FLOAT))); assertThat(getProp(def, "p_double").type, is(astType(BasicTypeKind.DOUBLE))); assertThat(getProp(def, "p_text").type, is(astType(BasicTypeKind.TEXT))); assertThat(getProp(def, "p_boolean").type, is(astType(BasicTypeKind.BOOLEAN))); assertThat(getProp(def, "p_date").type, is(astType(BasicTypeKind.DATE))); assertThat(getProp(def, "p_datetime").type, is(astType(BasicTypeKind.DATETIME))); } /** * Parse all literals. */ @Test public void literals() { AstAttribute attr = loadFirstAttribute(); assertThat(getValue(attr, "e_int"), is(value("100", LiteralKind.INTEGER))); assertThat(getValue(attr, "e_string"), is(value("\"Hello, world!\"", LiteralKind.STRING))); assertThat(getValue(attr, "e_decimal"), is(value("3.141592", LiteralKind.DECIMAL))); assertThat(getValue(attr, "e_boolean"), is(value("TRUE", LiteralKind.BOOLEAN))); } /** * Parse a qualified name. */ @Test public void qualified_name() { AstAttribute attr = loadFirstAttribute(); assertThat(attr.name.toString(), is("com.asakusafw.dmdl")); } /** * Parse an array. */ @Test public void array() { AstAttribute attr = loadFirstAttribute(); AstAttributeValue value = getValue(attr, "e_array"); assertThat(value, instanceOf(AstAttributeValueArray.class)); AstAttributeValueArray array = (AstAttributeValueArray) value; assertThat(array.elements.size(), is(4)); assertThat(array.elements.get(0), is(value("100", LiteralKind.INTEGER))); assertThat(array.elements.get(1), is(value("\"Hello, world!\"", LiteralKind.STRING))); assertThat(array.elements.get(2), is(value("3.141592", LiteralKind.DECIMAL))); assertThat(array.elements.get(3), is(value("TRUE", LiteralKind.BOOLEAN))); } /** * Parse a map. */ @Test public void map() { AstAttribute attr = loadFirstAttribute(); AstAttributeValue value = getValue(attr, "e_map"); assertThat(value, instanceOf(AstAttributeValueMap.class)); AstAttributeValueMap map = (AstAttributeValueMap) value; assertThat(map.entries.size(), is(6)); assertThat(get(map, "a"), is(value("100", LiteralKind.INTEGER))); assertThat(get(map, "b"), is(value("\"Hello, world!\"", LiteralKind.STRING))); assertThat(get(map, "c"), is(value("3.141592", LiteralKind.DECIMAL))); assertThat(get(map, "d"), is(value("TRUE", LiteralKind.BOOLEAN))); assertThat(get(map, BigInteger.valueOf(0)), is(instanceOf(AstAttributeValueArray.class))); assertThat(get(map, BigInteger.valueOf(1)), is(instanceOf(AstAttributeValueMap.class))); } private static AstAttributeValue get(AstAttributeValueMap map, Object value) { return map.entries.stream() .filter(e -> e.key.toValue().equals(value)) .findAny() .get().value; } /** * Parse a qualified name in an attribute value. */ @Test public void value_qname() { AstAttribute attr = loadFirstAttribute(); AstAttributeValue value = getValue(attr, "e_qname"); assertThat(value, instanceOf(AstQualifiedName.class)); AstQualifiedName name = (AstQualifiedName) value; assertThat(name.toString(), is("com.asakusafw.dmdl")); } /** * Accept special names (e.g. "joined", "summarized" for model / property names). */ @Test public void special_names() { load(); } /** * Name with arrow. */ @Test public void name_follows_arrow() { load(); } /** * with invalid name. */ @Test public void invalid_name() { shouldSyntaxError(); } /** * with invalid name. */ @Test public void invalid_name_separator() { shouldSyntaxError(); } /** * with invalid type name. */ @Test public void invalid_type_name() { shouldSyntaxError(); } /** * with invalid separator character. */ @Test public void invalid_separator() { shouldSyntaxError(); } /** * with invalid name. */ @Test public void invalid_missing_eq() { shouldSyntaxError(); } /** * record definition must be followed semicolon. */ @Test public void invalid_record_nodelim() { shouldSyntaxError(); } /** * property definition in record must be followed semicolon. */ @Test public void invalid_record_property_nodelim() { shouldSyntaxError(); } /** * property definition in record must be followed semicolon. */ @Test public void invalid_record_property_type() { shouldSyntaxError(); } /** * reference. */ @Test public void reference_list() { AstRecordDefinition record = loadFirstTermAs(AstRecordDefinition.class, new String[] { "simple = {", " a : INT;", " r = {a};", "};", }); AstPropertyDefinition r = getProp(record, "r"); assertThat(r.description, is(nullValue())); assertThat(r.attributes, hasSize(0)); assertThat(r.name, is(name("r"))); assertThat(r.type, is(nullValue())); assertThat(r.expression, instanceOf(AstAttributeValueArray.class)); AstAttributeValueArray array = (AstAttributeValueArray) r.expression; assertThat(array.elements.size(), is(1)); assertThat(array.elements.get(0), is(name("a"))); } /** * reference. */ @Test public void reference_map() { AstRecordDefinition record = loadFirstTermAs(AstRecordDefinition.class, new String[] { "simple = {", " a : INT;", " r = {`A`:a};", "};", }); AstPropertyDefinition r = getProp(record, "r"); assertThat(r.description, is(nullValue())); assertThat(r.attributes, hasSize(0)); assertThat(r.name, is(name("r"))); assertThat(r.type, is(nullValue())); assertThat(r.expression, instanceOf(AstAttributeValueMap.class)); AstAttributeValueMap map = (AstAttributeValueMap) r.expression; assertThat(map.entries.get(0).key, is(value("\"A\"", LiteralKind.STRING))); assertThat(map.entries.get(0).value, is(name("a"))); } /** * reference. */ @Test public void reference_indirect() { AstRecordDefinition record = loadFirstTermAs(AstRecordDefinition.class, new String[] { "simple = {", " a : INT;", " r = other.r;", "};", }); AstPropertyDefinition r = getProp(record, "r"); assertThat(r.description, is(nullValue())); assertThat(r.attributes, hasSize(0)); assertThat(r.name, is(name("r"))); assertThat(r.type, is(nullValue())); assertThat(r.expression, is(qname("other", "r"))); } /** * reference - stub. */ @Test public void reference_stub() { AstRecordDefinition record = loadFirstTermAs(AstRecordDefinition.class, new String[] { "simple = {", " a : INT;", " r_list : {INT};", " r_map : {:INT};", "};", }); AstPropertyDefinition list = getProp(record, "r_list"); assertThat(list.type, is(astType(CollectionKind.LIST, BasicTypeKind.INT))); assertThat(list.expression, is(nullValue())); AstPropertyDefinition map = getProp(record, "r_map"); assertThat(map.type, is(astType(CollectionKind.MAP, BasicTypeKind.INT))); assertThat(map.expression, is(nullValue())); } /** * reference. */ @Test public void reference_empty() { AstRecordDefinition record = loadFirstTermAs(AstRecordDefinition.class, new String[] { "simple = {", " a : INT;", " r_list : {INT} = {};", " r_map : {:INT} = {:};", "};", }); AstPropertyDefinition list = getProp(record, "r_list"); assertThat(list.type, is(astType(CollectionKind.LIST, BasicTypeKind.INT))); assertThat(list.expression, instanceOf(AstAttributeValueArray.class)); assertThat(((AstAttributeValueArray) list.expression).elements, hasSize(0)); AstPropertyDefinition map = getProp(record, "r_map"); assertThat(map.type, is(astType(CollectionKind.MAP, BasicTypeKind.INT))); assertThat(map.expression, instanceOf(AstAttributeValueMap.class)); assertThat(((AstAttributeValueMap) map.expression).entries, hasSize(0)); } private static AstType astType(BasicTypeKind kind) { return new AstBasicType(null, kind); } private static AstType astType(CollectionKind container, BasicTypeKind element) { return new AstCollectionType(null, container, astType(element)); } private static AstAttributeValue value(String token, LiteralKind kind) { return new AstLiteral(null, token, kind); } private static AstSimpleName name(String identifier) { return new AstSimpleName(null, identifier); } private static AstQualifiedName qname(String qualifier, String identifier) { return new AstQualifiedName(null, name(qualifier), name(identifier)); } @SuppressWarnings("unchecked") private static <T extends AstTerm<T>> List<T> extract(AstExpression<T> expression) { List<T> results = new ArrayList<>(); LinkedList<AstExpression<T>> work = new LinkedList<>(); work.add(expression); int count = 0; while (work.isEmpty() == false) { if (count++ > 1000) { throw new AssertionError(work); } AstExpression<T> first = work.removeFirst(); if (first instanceof AstUnionExpression<?>) { AstUnionExpression<T> union = (AstUnionExpression<T>) first; work.addAll(0, union.terms); } else if (first instanceof AstTerm<?>) { results.add((T) first); } else { throw new AssertionError("Unknown expression: " + first); } } return results; } private static AstModelDefinition<AstRecord> getRecord(AstScript script, String name) { for (AstModelDefinition<?> def : script.models) { if (def.name.identifier.equals(name)) { return def.asRecord(); } } throw new AssertionError(name); } private static AstModelDefinition<AstRecord> getProjection(AstScript script, String name) { for (AstModelDefinition<?> def : script.models) { if (def.name.identifier.equals(name)) { return def.asProjective(); } } throw new AssertionError(name); } private static AstModelDefinition<AstJoin> getJoined(AstScript script, String name) { for (AstModelDefinition<?> def : script.models) { if (def.name.identifier.equals(name)) { return def.asJoined(); } } throw new AssertionError(name); } private static AstModelDefinition<AstSummarize> getSummarized(AstScript script, String name) { for (AstModelDefinition<?> def : script.models) { if (def.name.identifier.equals(name)) { return def.asSummarized(); } } throw new AssertionError(name); } private static AstPropertyDefinition getProp(AstRecordDefinition record, String name) { for (AstPropertyDefinition prop : record.properties) { if (prop.name.identifier.equals(name)) { return prop; } } throw new AssertionError(name); } private static AstAttributeValue getValue(AstAttribute attr, String name) { for (AstAttributeElement elem : attr.elements) { if (elem.name.identifier.equals(name)) { return elem.value; } } throw new AssertionError(name); } private AstScript load(String... lines) { AstScript script = parse(lines); AstScript restored = restore(script); assertThat(restored, equalTo(script)); return script; } private static AstScript restore(AstScript script) { StringWriter output = new StringWriter(); try (PrintWriter writer = new PrintWriter(output)) { DmdlEmitter.emit(script, writer); } LOG.debug("{}", script.getRegion().sourceFile); LOG.debug("{}", output); DmdlParser parser = new DmdlParser(); try { return parser.parse(new StringReader(output.toString()), null); } catch (DmdlSyntaxException e) { throw new AssertionError(e); } } private <T extends AstTerm<?>> T loadFirstTermAs(Class<T> termKind, String... lines) { AstScript script = load(lines); assertThat(script.models.size(), greaterThanOrEqualTo(1)); AstModelDefinition<?> firstModel = script.models.get(0); List<? extends AstTerm<?>> terms = extract(firstModel.expression); assertThat(terms.size(), greaterThanOrEqualTo(1)); AstTerm<?> term = terms.get(0); return termKind.cast(term); } private AstAttribute loadFirstAttribute(String... lines) { AstScript script = load(lines); assertThat(script.models.size(), greaterThanOrEqualTo(1)); AstModelDefinition<?> firstModel = script.models.get(0); assertThat(firstModel.attributes.size(), greaterThanOrEqualTo(1)); return firstModel.attributes.get(0); } }