import os, sys from org.aspectj.util import FileUtil from java.io import File sourcedir = "incr_test_scratch_sources" outdir = "incr_test_scratch_classes" errorList = [] VERBOSE = 1 def createEmpty(dir): if os.path.exists(dir): FileUtil.deleteContents(File(dir)) else: os.mkdir(dir) def makeFile(name, contents): fullname = os.path.join(sourcedir, name) dirname = os.path.dirname(fullname) if not os.path.exists(dirname): os.makedirs(dirname) fp = open(fullname, 'w') fp.write(contents) fp.close() def deleteFile(name): os.remove(os.path.join(sourcedir, name)) def snapshot(dir, map=None): if map is None: map = {} for file in os.listdir(dir): filename = os.path.join(dir, file) if os.path.isdir(filename): snapshot(filename, map) else: stats = os.stat(filename) map[filename] = stats[8] return map def diffSnapshots(old, new): unchanged = [] changed = [] for name, mtime in new.items(): if old.has_key(name): oldTime = old[name] if oldTime == mtime: unchanged.append(name) else: changed.append(name) del old[name] else: changed.append(name) deleted = old.keys() return unchanged, changed, deleted def error(m): errorList.append(m) print m def suffixInList(suffix, list): for i in list: if i.endswith(suffix): return 1 return 0 def checkClasses(kind, filelist, names): filenames = [] for o in filelist: name = os.path.basename(o) filenames.append(name[:-6]) checkSets(names, filenames, kind) """ #print names, repr(names) if repr(names).startswith("\'"): names = [names] for c in names: classname = c+".class" if not suffixInList(classname, filelist): error("%s expected %s not found in %s" % (name, classname, filelist)) """ def findAndRemove(l, item): for i in range(len(l)): if l[i] == item: del l[i] return 1 return 0 def makeList(l): if repr(l).startswith("\'"): return [l] return l def checkSets(expected, found, kind="error"): expected = makeList(expected) for e in expected: if not findAndRemove(found, e): error("expected %s %s not found in %s" % (kind, e, found)) for f in found: error("unexpected %s %s" % (kind, f)) from org.aspectj.ajdt.ajc import AjdtCommand from org.aspectj.bridge import IMessageHandler, IMessage def makeSet(errors): ret = {} for e in errors: loc = e.getISourceLocation() if loc is None: continue #??? s = "%s:%i" % (loc.sourceFile.name[:-5], loc.line) ret[s] = s return ret.keys() class Handler (IMessageHandler): def __init__(self): self.errors = [] def handleMessage(self, message): if message.kind == IMessage.ERROR: self.errors.append(message) if VERBOSE: print message def isIgnoring(self, kind): return 0 createEmpty(sourcedir) createEmpty(outdir) handler = Handler() cmd = AjdtCommand() TEMPLATE = """\ %(package)s %(modifiers)s %(kind)s %(classname)s %(parents)s { %(body)s public static void main(String[] args) { %(stmts)s } } """ import string, time def splitClassName(className): dot = className.rfind('.') if dot == -1: return None, className, className +".java" else: packageName = className[:dot] className = className[dot+1:] l = packageName.split('.') l.append(className + ".java") path = apply(os.path.join, l) return packageName, className, path def makeType(className, stmts="""System.out.println("hello");""", body="", kind="class", parents=""): packageName, className, path = splitClassName(className) if packageName is None: packageDecl = "" else: packageDecl = "package %s;" % packageName contents = TEMPLATE % {'package':packageDecl, 'modifiers':'public', 'classname':className, 'body':body, 'stmts':stmts, 'kind':kind, 'parents':parents} makeFile(path, contents) def deleteType(className): packageName, className, path = splitClassName(className) deleteFile(path) def test(batch=0, couldChange=[], changed=[], deleted=[], errors=[]): print ">>>>test changed=%s, couldChange=%s, deleted=%s, errors=%s<<<<" % (changed, couldChange, deleted, errors) start = snapshot(outdir) #print start handler.errors = [] time.sleep(0.1) if batch: cmd.runCommand(["-d", outdir, "-sourceroots", sourcedir], handler) else: cmd.repeatCommand(handler) checkSets(errors, makeSet(handler.errors)) if len(handler.errors) > 0: return end = snapshot(outdir) #print "end", end u, c, d = diffSnapshots(start, end) checkClasses("changed", c, makeList(changed) + makeList(couldChange)) checkClasses("deleted", d, deleted) """ Pure Java tests """ makeType("p1.Hello") test(batch=1, changed="Hello") test() makeType("p1.Hello", stmts="Target.staticM();") test(errors="Hello:5") test(errors="Hello:5") makeType("p1.Target", body="static void staticM() {}") test(changed=["Hello", "Target"]) deleteType("p1.Target") test(errors="Hello:5") makeType("p1.Target", body="static void staticM() { int x = 2; }") test(changed=["Target", "Hello"]) makeType("p1.Target", body="""static void staticM() { System.out.println("foo"); }""") test(changed=["Target"]) makeType("p1.Target", body="static int staticM() { return 2; }") test(changed=["Hello", "Target"]) makeType("p1.Hello", body="static class Inner {}") test(changed=["Hello", "Hello$Inner"]) deleteType("p1.Hello") test(deleted=["Hello", "Hello$Inner"]) makeType("p1.Hello", body="static class NewInner {}") test(changed=["Hello", "Hello$NewInner"]) makeType("p1.Hello", body="") test(changed=["Hello"], deleted=["Hello$NewInner"]) print "done", errorList sys.exit(0) """ Simple tests with aspects """ makeType("p1.Hello") test(batch=1, changed="Hello") makeType("p1.A", kind="aspect", body="before(): within(String) { }") test(changed=["A"], couldChange=["Hello"]) makeType("p1.Hello") makeType("p1.A", kind="aspect", body="before(): execution(* main(..)) { }") test(changed=["A", "Hello"]) makeType("p1.A", kind="aspect", body="before(): within(Hello) { }") test(changed=["A", "Hello"]) makeType("p1.Target") test(changed="Target") makeType("p1.Hello", stmts="new Target().m();") test(errors=["Hello:5"]) makeType("p1.ATypes", kind="aspect", body="int Target.m() { return 10; }") test(changed=["Hello", "ATypes", "Target"], couldChange=["A"]) makeType("p1.ATypes", kind="aspect", body="int Target.m(int x) { return x + 10; }") test(errors=["Hello:5"]) makeType("p1.Hello", stmts="new Target().m(2);") test(changed="Hello") makeType("p1.Hello", stmts="new Target().m(5);") test(changed="Hello") makeType("p1.Hello", stmts="new Target().m(42);") test(changed="Hello") print "done", errorList sys.exit(0) """ Bugzilla Bug 29684 Incremental: Commenting out conflict yeilds NullPointerException public class SomeClass { public String toString() { return "from SomeClass"; } } public aspect Conflicter { public String SomeClass.toString() { return "from Conflicter"; } public static void main(String[] args) { int i = 0; } } However, modifying Conflicter so that it reads: public aspect Conflicter { // public String SomeClass.toString() { // return "from Conflicter"; // } public static void main(String[] args) { int i = 0; } } """ makeType("conflict.SomeClass", body="""public String toString() { return "from SomeClass"; }""") makeType("conflict.Conflicter", kind="aspect", body="""public String SomeClass.toString() { return "from Conflicter"; }""") test(batch=1, errors=["Conflicter:3"]) makeType("conflict.Conflicter", kind="aspect", body="") test(changed=["SomeClass", "Conflicter"]) makeType("conflict.Conflicter", kind="aspect", body="""public String SomeClass.toString() { return "from Conflicter"; }""") test(errors=["Conflicter:3"]) makeType("conflict.SomeClass", body="") test(changed=["SomeClass"]) print "done", errorList sys.exit(0) """ Bugzilla Bug 28807 incremental compilation always fails with NullPointerException in 1.1 beta 2 """ makeType("incremental.BasicAspect") makeType("incremental.Basic") test(batch=1, changed=["Basic", "BasicAspect"]) makeType("incremental.BasicAspect") test() print "done", errorList sys.exit(0) """ Stress testing """ N = 2000 l = [] for i in range(N): name = "p1.Hello" + str(i) makeType(name) l.append("Hello" + str(i)) test(batch=1, changed=l) print "done", errorList sys.exit(0)