/******************************************************************************* * Copyright (c) 2013 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package com.ibm.wala.cast.test; import java.io.File; import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import junit.framework.Assert; import com.ibm.wala.cast.ipa.callgraph.CAstCallGraphUtil; import com.ibm.wala.cast.ir.ssa.AstIRFactory; import com.ibm.wala.cast.loader.SingleClassLoaderFactory; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IField; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.classLoader.Language; import com.ibm.wala.classLoader.SourceFileModule; import com.ibm.wala.core.tests.util.WalaTestCase; import com.ibm.wala.ipa.callgraph.AnalysisScope; import com.ibm.wala.ipa.callgraph.impl.Everywhere; import com.ibm.wala.ipa.cha.ClassHierarchy; import com.ibm.wala.ssa.IRFactory; import com.ibm.wala.ssa.SSAOptions; import com.ibm.wala.util.collections.HashMapFactory; import com.ibm.wala.util.collections.Pair; public abstract class TestCAstTranslator extends WalaTestCase { protected static class TranslatorAssertions { private final Set<String> classes = new HashSet<String>(); private final Map<String, String> supers = new HashMap<String, String>(); private final Set<Pair<String, String>> instanceFields = new HashSet<Pair<String, String>>(); private final Set<Pair<String, String>> staticFields = new HashSet<Pair<String, String>>(); private final Map<Pair<String, Object>, Object> instanceMethods = HashMapFactory.make(); private final Map<Pair<String, Object>, Object> staticMethods = HashMapFactory.make(); private Set<String> getClasses() { return classes; } private Map<String, String> getSuperClasses() { return supers; } private Set<Pair<String, String>> getInstanceFields() { return instanceFields; } private Set<Pair<String, String>> getStaticFields() { return staticFields; } private Map<Pair<String, Object>, Object> getInstanceMethods() { return instanceMethods; } private Map<Pair<String, Object>, Object> getStaticMethods() { return staticMethods; } public TranslatorAssertions(Object[][] data) { for (int dataIndex = 0; dataIndex < data.length; dataIndex++) { Object[] entry = data[dataIndex]; String clsName = (String) entry[0]; this.classes.add(clsName); String superName = (String) entry[1]; this.supers.put(clsName, superName); String[] instanceFields = (String[]) entry[2]; if (instanceFields != null) { for (int i = 0; i < instanceFields.length; i++) { this.instanceFields.add(Pair.make(clsName, instanceFields[i])); } } String[] staticFields = (String[]) entry[3]; if (staticFields != null) { for (int i = 0; i < staticFields.length; i++) { this.staticFields.add(Pair.make(clsName, staticFields[i])); } } Pair[] instanceMethods = (Pair[]) entry[4]; if (instanceMethods != null) { for (int i = 0; i < instanceMethods.length; i++) { this.instanceMethods.put(Pair.make(clsName, instanceMethods[i].fst), instanceMethods[i].snd); } } Pair[] staticMethods = (Pair[]) entry[5]; if (staticMethods != null) { for (int i = 0; i < staticMethods.length; i++) { this.staticMethods.put(Pair.make(clsName, staticMethods[i].fst), staticMethods[i].snd); } } } } } protected abstract Language getLanguage(); protected abstract String getTestPath(); protected abstract SingleClassLoaderFactory getClassLoaderFactory(); protected final IRFactory<IMethod> factory = AstIRFactory.makeDefaultFactory(); protected final SSAOptions options = new SSAOptions(); public ClassHierarchy runTranslator(SourceFileModule[] fileNames) throws Exception { SingleClassLoaderFactory loaders = getClassLoaderFactory(); AnalysisScope scope = CAstCallGraphUtil.makeScope(fileNames, loaders, getLanguage()); ClassHierarchy cha = ClassHierarchy.make(scope, loaders, getLanguage()); return cha; } protected void dump(ClassHierarchy cha) { for (Iterator<?> clss = cha.iterator(); clss.hasNext();) { IClass cls = (IClass) clss.next(); System.err.println(("class " + cls)); for (Iterator<?> flds = cls.getDeclaredInstanceFields().iterator(); flds.hasNext();) { IField fld = (IField) flds.next(); System.err.println(("instance field " + fld)); } for (Iterator<?> flds = cls.getDeclaredStaticFields().iterator(); flds.hasNext();) { IField fld = (IField) flds.next(); System.err.println(("static field " + fld)); } for (Iterator<?> mths = cls.getDeclaredMethods().iterator(); mths.hasNext();) { IMethod mth = (IMethod) mths.next(); if (mth.isStatic()) System.err.print("static "); System.err.println(("method " + mth + " with " + mth.getNumberOfParameters() + " parameters")); for (int i = 0; i < mth.getNumberOfParameters(); i++) { System.err.println(("param " + i + ": " + mth.getParameterType(i))); } System.err.println(factory.makeIR(mth, Everywhere.EVERYWHERE, options)); } } } public void checkAssertions(ClassHierarchy cha, TranslatorAssertions assertions) { Set<String> classes = assertions.getClasses(); Map<String, String> supers = assertions.getSuperClasses(); Set<Pair<String, String>> instanceFields = assertions.getInstanceFields(); Set<Pair<String, String>> staticFields = assertions.getStaticFields(); Map<Pair<String, Object>, Object> instanceMethods = assertions.getInstanceMethods(); Map<Pair<String, Object>, Object> staticMethods = assertions.getStaticMethods(); int clsCount = 0; for (Iterator<?> clss = cha.iterator(); clss.hasNext();) { IClass cls = (IClass) clss.next(); clsCount++; Assert.assertTrue("found class " + cls.getName().toString(), classes.contains(cls.getName().toString())); if (cls.getSuperclass() == null) { Assert.assertTrue(cls.getName() + " has no superclass", supers.get(cls.getName()) == null); } else { Assert.assertTrue("super of " + cls.getName() + " is " + cls.getSuperclass().getName(), supers .get(cls.getName().toString()).equals(cls.getSuperclass().getName().toString())); } for (Iterator<?> flds = cls.getDeclaredInstanceFields().iterator(); flds.hasNext();) { IField fld = (IField) flds.next(); Assert.assertTrue(cls.getName() + " has field " + fld.getName(), instanceFields.contains(Pair.make( cls.getName().toString(), fld.getName().toString()))); } for (Iterator<?> flds = cls.getDeclaredStaticFields().iterator(); flds.hasNext();) { IField fld = (IField) flds.next(); Assert.assertTrue(cls.getName() + " has static field " + fld.getName(), staticFields.contains(Pair.make(cls.getName() .toString(), fld.getName().toString()))); } for (Iterator<?> mths = cls.getDeclaredMethods().iterator(); mths.hasNext();) { IMethod mth = (IMethod) mths.next(); Integer np = new Integer(mth.getNumberOfParameters()); Pair<String, String> key = Pair.make(cls.getName().toString(), mth.getName().toString()); if (mth.isStatic()) { Assert.assertTrue(cls.getName() + " has static method " + mth.getName(), staticMethods.containsKey(key)); Assert.assertTrue(cls.getName() + "::" + mth.getName() + " has " + np + " parameters", staticMethods.get(key).equals(np)); } else { Assert.assertTrue(cls.getName() + " has method " + mth.getName(), instanceMethods.containsKey(key)); Assert.assertTrue(cls.getName() + "::" + mth.getName() + " has " + np + " parameters", instanceMethods.get(key) .equals(np)); } } } Assert.assertTrue("want " + classes.size() + " classes", clsCount == classes.size()); } protected void testInternal(String[] args, TranslatorAssertions assertions) throws Exception { String testPath = getTestPath(); SourceFileModule[] fileNames = new SourceFileModule[args.length]; for (int i = 0; i < args.length; i++) { if (new File(args[i]).exists()) { fileNames[i] = CAstCallGraphUtil.makeSourceModule(new File(args[i]).toURI().toURL(), args[i]); } else if (new File(testPath + args[i]).exists()) { fileNames[i] = CAstCallGraphUtil.makeSourceModule(new File(testPath + args[i]).toURI().toURL(), args[i]); } else { URL url = getClass().getClassLoader().getResource(args[i]); fileNames[i] = CAstCallGraphUtil.makeSourceModule(url, args[i]); } Assert.assertTrue(args[i], fileNames[i] != null); } ClassHierarchy cha = runTranslator(fileNames); dump(cha); if (assertions != null) { checkAssertions(cha, assertions); } else { System.err.println(("WARNING: no assertions for " + getClass())); } } protected void testInternal(String arg, TranslatorAssertions assertions) { try { testInternal(new String[] { arg }, assertions); } catch (Exception e) { e.printStackTrace(); Assert.assertTrue(e.toString(), false); } } }