/**
* Copyright (C) 2010 STMicroelectronics
*
* This file is part of "Mind Compiler" is free software: you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Contact: mind@ow2.org
*
* Authors: Matthieu Leclercq
* Contributors:
*/
package org.ow2.mind.idl;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.objectweb.fractal.adl.ADLException;
import org.objectweb.fractal.adl.Node;
import org.ow2.mind.idl.ast.ArrayOf;
import org.ow2.mind.idl.ast.ConstantDefinition;
import org.ow2.mind.idl.ast.EnumDefinition;
import org.ow2.mind.idl.ast.EnumMember;
import org.ow2.mind.idl.ast.EnumReference;
import org.ow2.mind.idl.ast.IDL;
import org.ow2.mind.idl.ast.IDLASTHelper;
import org.ow2.mind.idl.ast.Include;
import org.ow2.mind.idl.ast.IncludeContainer;
import org.ow2.mind.idl.ast.InterfaceDefinition;
import org.ow2.mind.idl.ast.Member;
import org.ow2.mind.idl.ast.MemberContainer;
import org.ow2.mind.idl.ast.Method;
import org.ow2.mind.idl.ast.Parameter;
import org.ow2.mind.idl.ast.PointerOf;
import org.ow2.mind.idl.ast.PrimitiveType;
import org.ow2.mind.idl.ast.StructDefinition;
import org.ow2.mind.idl.ast.StructReference;
import org.ow2.mind.idl.ast.Type;
import org.ow2.mind.idl.ast.TypeCollectionContainer;
import org.ow2.mind.idl.ast.TypeDefReference;
import org.ow2.mind.idl.ast.TypeDefinition;
import org.ow2.mind.idl.ast.UnionDefinition;
import org.ow2.mind.idl.ast.UnionReference;
public class ASTChecker {
protected final Map<Node, Object> checkers = new IdentityHashMap<Node, Object>();
// ---------------------------------------------------------------------------
// IDL checking
// ---------------------------------------------------------------------------
protected void checkIDL(final IDL idl) {
assertNotNull("IDL is null", idl);
assertNotNull("idl name is null", idl.getName());
if (idl instanceof IncludeContainer)
checkIncludeContainer((IncludeContainer) idl);
if (idl instanceof TypeCollectionContainer) {
for (final Type type : ((TypeCollectionContainer) idl).getTypes()) {
checkType(type);
}
}
if (idl instanceof InterfaceDefinition)
checkInterface((InterfaceDefinition) idl);
}
protected void checkInterface(final InterfaceDefinition itf) {
for (final Method method : itf.getMethods()) {
checkMethod(method);
}
}
public IDLChecker assertIDL(final IDL idl) {
IDLChecker checker = (IDLChecker) checkers.get(idl);
if (checker == null) {
checker = createIDLChecker(idl);
checkers.put(idl, checker);
}
return checker;
}
protected IDLChecker createIDLChecker(final IDL idl) {
return new IDLChecker(idl);
}
public class IDLChecker {
public final IDL idl;
public IDLChecker(final IDL idl) {
this.idl = idl;
checkIDL(idl);
}
public IDLChecker that() {
return this;
}
public IDLChecker and() {
return this;
}
public IDLChecker extendsInterface(final String name) {
if (!(idl instanceof InterfaceDefinition))
fail("idl do not implements InterfaceDefinition");
final InterfaceDefinition container = (InterfaceDefinition) idl;
assertEquals("IDL " + idl.getName() + " does not extends \"" + name
+ "\".", name, container.getExtends());
return this;
}
public MethodChecker containsMethod(final String name) {
if (!(idl instanceof InterfaceDefinition))
fail("idl do not implements InterfaceDefinition");
final InterfaceDefinition container = (InterfaceDefinition) idl;
for (final Method meth : container.getMethods()) {
if (name.equals(meth.getName())) return assertMethod(meth, container);
}
fail("IDL " + idl.getName() + " does not contains a \"" + name
+ "\" method.");
// unreachable
return null;
}
public MethodCheckerIterator containsMethods(final String... names) {
final Set<String> nameSet = new HashSet<String>();
final List<MethodChecker> list = new ArrayList<MethodChecker>(
names.length);
for (final String name : names) {
assertTrue("Duplucated string in given names " + names, nameSet
.add(name));
list.add(containsMethod(name));
}
assertEquals("IDL contains more methods than expected.", names.length,
((InterfaceDefinition) idl).getMethods().length);
return new MethodCheckerIterator(list);
}
public IncludeChecker containsInclude(final String name) {
if (!(idl instanceof IncludeContainer))
fail("idl do not implements IncludeContainer");
final IncludeContainer container = (IncludeContainer) idl;
for (final Include include : container.getIncludes()) {
if (name.equals(include.getPath()))
return assertInclude(include, container);
}
fail("IDL " + idl.getName() + " does not include \"" + name + "\".");
// unreachable
return null;
}
public IncludeCheckerIterator containsIncludes(final String... names) {
final Set<String> nameSet = new HashSet<String>();
final List<IncludeChecker> list = new ArrayList<IncludeChecker>(
names.length);
for (final String name : names) {
assertTrue("Duplucated string in given names " + names, nameSet
.add(name));
list.add(containsInclude(name));
}
assertEquals("IDL contains more includes than expected.", names.length,
((IncludeContainer) idl).getIncludes().length);
return new IncludeCheckerIterator(list);
}
public TypeCheckerIterator definesType() {
if (!(idl instanceof TypeCollectionContainer))
fail("idl do not implements TypeCollectionContainer");
final TypeCollectionContainer container = (TypeCollectionContainer) idl;
final List<TypeChecker> checkers = new ArrayList<TypeChecker>();
for (final Type type : container.getTypes()) {
checkers.add(assertType(type));
}
return new TypeCheckerIterator(checkers);
}
}
// ---------------------------------------------------------------------------
// Include checking
// ---------------------------------------------------------------------------
protected void checkInclude(final Include include) {
assertNotNull("Include node is null", include);
assertNotNull("Include path is null", include.getPath());
}
protected void checkIncludeContainer(final IncludeContainer container) {
for (final Include include : container.getIncludes()) {
checkInclude(include);
}
}
protected IncludeChecker assertInclude(final Include include,
final IncludeContainer container) {
IncludeChecker checker = (IncludeChecker) checkers.get(include);
if (checker == null) {
checker = createIncludeChecker(include, container);
checkers.put(include, checker);
} else {
assertSame("Unexpected container", container, checker.container);
}
return checker;
}
protected IncludeChecker createIncludeChecker(final Include include,
final IncludeContainer container) {
return new IncludeChecker(include, container);
}
public class IncludeChecker {
public final Include include;
public final IncludeContainer container;
protected IncludeChecker(final Include include,
final IncludeContainer container) {
this.include = include;
this.container = container;
checkInclude(include);
}
public IncludeChecker pathIs(final String path) {
assertEquals("Unexpected include path \"" + include.getPath() + "\".",
path, include.getPath());
return this;
}
public IDLChecker includes() {
try {
return assertIDL(IDLASTHelper.getIncludedIDL(include, null, null));
} catch (final ADLException e) {
// never append
return null;
}
}
}
public class IncludeCheckerIterator
extends
CheckerIterator<IncludeCheckerIterator, IncludeChecker> {
public IncludeCheckerIterator(final List<IncludeChecker> list) {
super(list);
}
@Override
protected IncludeCheckerIterator getThis() {
return this;
}
public IncludeCheckerIterator pathIs(final String path) {
element.pathIs(path);
return this;
}
public IDLChecker includes() {
return element.includes();
}
}
// ---------------------------------------------------------------------------
// Method checking
// ---------------------------------------------------------------------------
protected void checkMethod(final Method method) {
assertNotNull("Method node is null", method);
assertNotNull("Method name is null", method.getName());
checkType(method.getType());
final Set<String> names = new HashSet<String>();
for (final Parameter param : method.getParameters()) {
assertTrue("Duplicated parameter name.", names.add(param.getName()));
checkParameter(param);
}
}
protected MethodChecker assertMethod(final Method method,
final InterfaceDefinition container) {
MethodChecker checker = (MethodChecker) checkers.get(method);
if (checker == null) {
checker = createMethodChecker(method, container);
checkers.put(method, checker);
} else {
assertSame("Unexpected container", container, checker.container);
}
return checker;
}
protected MethodChecker createMethodChecker(final Method method,
final InterfaceDefinition container) {
return new MethodChecker(method, container);
}
public class MethodChecker {
public final Method method;
public final InterfaceDefinition container;
protected MethodChecker(final Method method,
final InterfaceDefinition container) {
this.method = method;
this.container = container;
checkMethod(method);
}
public TypeChecker returnsType() {
return assertType(method.getType());
}
public ParameterChecker hasParameter(final String name) {
for (final Parameter param : method.getParameters()) {
if (name.equals(param.getName())) {
return assertParameter(param, method);
}
}
fail("method \"" + method.getName() + "\"does not contains a \"" + name
+ "\" parameter.");
// unreachable
return null;
}
public ParameterCheckerIterator hasParameters(final String... names) {
final Set<String> nameSet = new HashSet<String>();
final List<ParameterChecker> list = new ArrayList<ParameterChecker>(
names.length);
for (final String name : names) {
assertTrue("Duplucated string in given names " + names, nameSet
.add(name));
list.add(hasParameter(name));
}
assertEquals("Method contains more parameter than expected.",
names.length, method.getParameters().length);
return new ParameterCheckerIterator(list);
}
}
public class MethodCheckerIterator
extends
CheckerIterator<MethodCheckerIterator, MethodChecker> {
public MethodCheckerIterator(final List<MethodChecker> list) {
super(list);
}
@Override
protected MethodCheckerIterator getThis() {
return this;
}
public TypeChecker returnsType() {
return element.returnsType();
}
public ParameterChecker hasParameter(final String name) {
return element.hasParameter(name);
}
public ParameterCheckerIterator hasParameters(final String... names) {
return element.hasParameters(names);
}
}
// ---------------------------------------------------------------------------
// Parameter checking
// ---------------------------------------------------------------------------
protected void checkParameter(final Parameter parameter) {
assertNotNull("Parameter node is null", parameter);
assertNotNull("Parameter name is null", parameter.getName());
checkType(parameter.getType());
}
protected ParameterChecker assertParameter(final Parameter parameter,
final Method container) {
ParameterChecker checker = (ParameterChecker) checkers.get(parameter);
if (checker == null) {
checker = createParameterChecker(parameter, container);
checkers.put(parameter, checker);
} else {
assertSame("Unexpected container", container, checker.container);
}
return checker;
}
protected ParameterChecker createParameterChecker(final Parameter parameter,
final Method container) {
return new ParameterChecker(parameter, container);
}
public class ParameterChecker {
public final Parameter parameter;
public final Method container;
protected ParameterChecker(final Parameter parameter, final Method container) {
this.parameter = parameter;
this.container = container;
checkParameter(parameter);
}
public TypeChecker hasType() {
return assertType(parameter.getType());
}
}
public class ParameterCheckerIterator
extends
CheckerIterator<ParameterCheckerIterator, ParameterChecker> {
public ParameterCheckerIterator(final List<ParameterChecker> list) {
super(list);
}
@Override
protected ParameterCheckerIterator getThis() {
return this;
}
public TypeChecker hasType() {
return element.hasType();
}
}
// ---------------------------------------------------------------------------
// Type checking
// ---------------------------------------------------------------------------
protected void checkType(final Type type) {
assertNotNull("Type node is null", type);
if (type instanceof EnumDefinition) {
checkType((EnumDefinition) type);
} else if (type instanceof EnumReference) {
checkType((EnumReference) type);
} else if (type instanceof StructDefinition) {
checkType((StructDefinition) type);
} else if (type instanceof StructReference) {
checkType((StructReference) type);
} else if (type instanceof UnionDefinition) {
checkType((UnionDefinition) type);
} else if (type instanceof UnionReference) {
checkType((UnionReference) type);
} else if (type instanceof TypeDefinition) {
checkType((TypeDefinition) type);
} else if (type instanceof TypeDefReference) {
checkType((TypeDefReference) type);
} else if (type instanceof ConstantDefinition) {
checkType((ConstantDefinition) type);
} else if (type instanceof PrimitiveType) {
checkType((PrimitiveType) type);
} else if (type instanceof ArrayOf) {
checkType((ArrayOf) type);
} else if (type instanceof PointerOf) {
checkType((PointerOf) type);
}
}
protected void checkType(final EnumDefinition type) {
final Set<String> names = new HashSet<String>();
for (final EnumMember member : type.getEnumMembers()) {
assertTrue("Duplicated member name.", names.add(member.getName()));
checkEnumMember(member);
}
}
protected void checkType(final EnumReference type) {
assertNotNull("Type name is null", type.getName());
}
protected void checkType(final StructDefinition type) {
final Set<String> names = new HashSet<String>();
for (final Member member : type.getMembers()) {
assertTrue("Duplicated member name.", names.add(member.getName()));
checkMember(member);
}
}
protected void checkType(final StructReference type) {
assertNotNull("Type name is null", type.getName());
}
protected void checkType(final UnionDefinition type) {
final Set<String> names = new HashSet<String>();
for (final Member member : type.getMembers()) {
assertTrue("Duplicated member name.", names.add(member.getName()));
checkMember(member);
}
}
protected void checkType(final UnionReference type) {
assertNotNull("Type name is null", type.getName());
}
protected void checkType(final TypeDefinition type) {
assertNotNull("Type name is null", type.getName());
checkType(type.getType());
}
protected void checkType(final TypeDefReference type) {
assertNotNull("Type name is null", type.getName());
}
protected void checkType(final ConstantDefinition type) {
assertNotNull("Type name is null", type.getName());
}
protected void checkType(final PrimitiveType type) {
assertNotNull("Type name is null", type.getName());
}
protected void checkType(final ArrayOf type) {
checkType(type.getType());
}
protected void checkType(final PointerOf type) {
checkType(type.getType());
}
protected TypeChecker assertType(final Type type) {
TypeChecker checker = (TypeChecker) checkers.get(type);
if (checker == null) {
checker = createTypeChecker(type);
checkers.put(type, checker);
}
return checker;
}
protected TypeChecker createTypeChecker(final Type type) {
return new TypeChecker(type);
}
public class TypeChecker {
public final Type type;
protected TypeChecker(final Type type) {
this.type = type;
checkType(type);
}
public TypeChecker isPrimitiveType(final String name) {
assertTrue("Type node is not a PrimitiveType",
type instanceof PrimitiveType);
assertEquals(name, ((PrimitiveType) type).getName());
return this;
}
public TypeChecker isPointerOf() {
assertTrue("Type node is not a PointerOf", type instanceof PointerOf);
return assertType(((PointerOf) type).getType());
}
public TypeChecker isArrayOf() {
assertTrue("Type node is not a ArrayOf", type instanceof ArrayOf);
return assertType(((ArrayOf) type).getType());
}
public TypeChecker isTypedefOf(final String name) {
assertTrue("Type node is not a TypeDefinition",
type instanceof TypeDefinition);
assertEquals(name, ((TypeDefinition) type).getName());
return assertType(((TypeDefinition) type).getType());
}
public void isTypedefRefOf(final String name) {
assertTrue("Type node is not a TypeDefReference",
type instanceof TypeDefReference);
assertEquals(name, ((TypeDefReference) type).getName());
}
public TypeChecker isEnumRef(final String name) {
assertTrue("Type node is not a EnumReference",
type instanceof EnumReference);
assertEquals(name, ((EnumReference) type).getName());
return this;
}
public TypeChecker isStructRef(final String name) {
assertTrue("Type node is not a StructReference",
type instanceof StructReference);
assertEquals(name, ((StructReference) type).getName());
return this;
}
public TypeChecker isUnionRef(final String name) {
assertTrue("Type node is not a UnionReference",
type instanceof UnionReference);
assertEquals(name, ((UnionReference) type).getName());
return this;
}
public EnumChecker isEnumDef(final String name) {
assertTrue("Type node is not a EnumDefinition",
type instanceof EnumDefinition);
assertEquals(name, ((EnumDefinition) type).getName());
return assertEnum((EnumDefinition) type);
}
public StructUnionChecker isStructDef(final String name) {
assertTrue("Type node is not a StructDefinition",
type instanceof StructDefinition);
assertEquals(name, ((StructDefinition) type).getName());
return assertStructUnion((StructDefinition) type);
}
public StructUnionChecker isUnionDef(final String name) {
assertTrue("Type node is not a UnionDefinition",
type instanceof UnionDefinition);
assertEquals(name, ((UnionDefinition) type).getName());
return assertStructUnion((UnionDefinition) type);
}
}
public class TypeCheckerIterator
extends
CheckerIterator<TypeCheckerIterator, TypeChecker> {
public TypeCheckerIterator(final List<TypeChecker> list) {
super(list);
}
@Override
protected TypeCheckerIterator getThis() {
return this;
}
public TypeChecker isPrimitiveType(final String name) {
return element.isPrimitiveType(name);
}
public TypeChecker isPointerOf() {
return element.isPointerOf();
}
public TypeChecker isArrayOf() {
return element.isArrayOf();
}
public TypeChecker isTypedefOf(final String name) {
return element.isTypedefOf(name);
}
public TypeCheckerIterator isTypedefRefOf(final String name) {
element.isTypedefRefOf(name);
return this;
}
public TypeChecker isEnumRef(final String name) {
return element.isEnumRef(name);
}
public TypeChecker isStructRef(final String name) {
return element.isStructRef(name);
}
public TypeChecker isUnionRef(final String name) {
return element.isUnionRef(name);
}
public EnumChecker isEnumDef(final String name) {
return element.isEnumDef(name);
}
public StructUnionChecker isStructDef(final String name) {
return element.isStructDef(name);
}
public StructUnionChecker isUnionDef(final String name) {
return element.isUnionDef(name);
}
}
public EnumChecker assertEnum(final EnumDefinition enumDef) {
return createEnumChecker(enumDef);
}
protected EnumChecker createEnumChecker(final EnumDefinition enumDef) {
return new EnumChecker(enumDef);
}
public class EnumChecker {
EnumDefinition enumDef;
EnumChecker(final EnumDefinition enumDef) {
this.enumDef = enumDef;
checkType(enumDef);
}
public EnumMemberChecker hasMember(final String name) {
for (final EnumMember member : enumDef.getEnumMembers()) {
if (name.equals(member.getName())) {
return assertEnumMember(member);
}
}
fail("Enum does not contains a \"" + name + "\" member.");
// unreachable
return null;
}
public EnumMemberCheckerIterator hasMembers(final String... names) {
final Set<String> nameSet = new HashSet<String>();
final List<EnumMemberChecker> list = new ArrayList<EnumMemberChecker>(
names.length);
for (final String name : names) {
assertTrue("Duplucated string in given names " + names, nameSet
.add(name));
list.add(hasMember(name));
}
assertEquals("Enum contains more members than expected.", names.length,
enumDef.getEnumMembers().length);
return new EnumMemberCheckerIterator(list);
}
}
protected void checkEnumMember(final EnumMember member) {
assertNotNull("EnumMember is null", member);
assertNotNull("EnumMember name is null", member.getName());
}
public EnumMemberChecker assertEnumMember(final EnumMember member) {
EnumMemberChecker checker = (EnumMemberChecker) checkers.get(member);
if (checker == null) {
checker = createEnumMemberChecker(member);
checkers.put(member, checker);
}
return checker;
}
protected EnumMemberChecker createEnumMemberChecker(final EnumMember member) {
return new EnumMemberChecker(member);
}
public class EnumMemberChecker {
public final EnumMember member;
public EnumMemberChecker(final EnumMember member) {
this.member = member;
checkEnumMember(member);
}
public EnumMemberChecker hasValue() {
assertNotNull(member.getConstantExpression());
return this;
}
}
public class EnumMemberCheckerIterator
extends
CheckerIterator<EnumMemberCheckerIterator, EnumMemberChecker> {
public EnumMemberCheckerIterator(final List<EnumMemberChecker> list) {
super(list);
}
@Override
protected EnumMemberCheckerIterator getThis() {
return this;
}
public EnumMemberCheckerIterator hasValue() {
element.hasValue();
return this;
}
}
public StructUnionChecker assertStructUnion(final MemberContainer structUnion) {
return createStructUnionChecker(structUnion);
}
protected StructUnionChecker createStructUnionChecker(
final MemberContainer structUnion) {
return new StructUnionChecker(structUnion);
}
public class StructUnionChecker {
MemberContainer structUnion;
StructUnionChecker(final MemberContainer structUnion) {
this.structUnion = structUnion;
checkType((Type) structUnion);
}
public StructUnionMemberChecker hasMember(final String name) {
for (final Member member : structUnion.getMembers()) {
if (name.equals(member.getName())) {
return assertStructUnionMember(member);
}
}
fail("Enum does not contains a \"" + name + "\" member.");
// unreachable
return null;
}
public StructUnionMemberCheckerIterator hasMembers(final String... names) {
final Set<String> nameSet = new HashSet<String>();
final List<StructUnionMemberChecker> list = new ArrayList<StructUnionMemberChecker>(
names.length);
for (final String name : names) {
assertTrue("Duplucated string in given names " + names, nameSet
.add(name));
list.add(hasMember(name));
}
assertEquals("Struct/Union contains more members than expected.",
names.length, structUnion.getMembers().length);
return new StructUnionMemberCheckerIterator(list);
}
}
protected void checkMember(final Member member) {
assertNotNull("Member is null", member);
assertNotNull("Member name is null", member.getName());
checkType(member.getType());
}
public StructUnionMemberChecker assertStructUnionMember(final Member member) {
StructUnionMemberChecker checker = (StructUnionMemberChecker) checkers
.get(member);
if (checker == null) {
checker = createStructUnionMemberChecker(member);
checkers.put(member, checker);
}
return checker;
}
protected StructUnionMemberChecker createStructUnionMemberChecker(
final Member member) {
return new StructUnionMemberChecker(member);
}
public class StructUnionMemberChecker {
public final Member member;
public StructUnionMemberChecker(final Member member) {
this.member = member;
checkMember(member);
}
public StructUnionMemberChecker hasSize() {
assertNotNull(member.getConstantExpression());
return this;
}
public TypeChecker hasType() {
return assertType(member.getType());
}
}
public class StructUnionMemberCheckerIterator
extends
CheckerIterator<StructUnionMemberCheckerIterator, StructUnionMemberChecker> {
public StructUnionMemberCheckerIterator(
final List<StructUnionMemberChecker> list) {
super(list);
}
@Override
protected StructUnionMemberCheckerIterator getThis() {
return this;
}
public StructUnionMemberCheckerIterator hasSize() {
element.hasSize();
return this;
}
public TypeChecker hasType() {
return element.hasType();
}
}
// ---------------------------------------------------------------------------
// Utility
// ---------------------------------------------------------------------------
public static abstract class CheckerIterator<T extends CheckerIterator<?, ?>, U> {
protected final List<U> list;
protected Iterator<U> iterator;
protected U element;
public CheckerIterator(final List<U> list) {
this.list = list;
}
protected abstract T getThis();
public T whereFirst() {
iterator = list.iterator();
if (!iterator.hasNext()) fail("List is empty");
element = iterator.next();
return getThis();
}
public T andNext() {
if (!iterator.hasNext()) fail("List has no more element");
element = iterator.next();
return getThis();
}
public U that() {
return element;
}
}
}