diff options
Diffstat (limited to 'tests/new/MemberInitializationsAfterExplicitConstructorCallsCoverage.java')
-rw-r--r-- | tests/new/MemberInitializationsAfterExplicitConstructorCallsCoverage.java | 565 |
1 files changed, 565 insertions, 0 deletions
diff --git a/tests/new/MemberInitializationsAfterExplicitConstructorCallsCoverage.java b/tests/new/MemberInitializationsAfterExplicitConstructorCallsCoverage.java new file mode 100644 index 000000000..9485df6ba --- /dev/null +++ b/tests/new/MemberInitializationsAfterExplicitConstructorCallsCoverage.java @@ -0,0 +1,565 @@ +// todo: need header + +import org.aspectj.testing.Tester; + +/** + * "Coverage" tests for + * PR#476: + * Member initializations are run after explicit + * constructor calls ("this()" or "super()") when they should be run beforehand. + * <p>Status: + * 10 additional variants are defined, 5 of which fail, emitting 30 errors. + * <p>background: + * <br>The effective order of operation during initialization should be: + * <ol> + * <ol>superclass static initialization</ol> + * <ol>selfclass static initialization</ol> + * <ol>superclass member initialization</ol> + * <ol>superclass constructor</ol> + * <ol>selfclass member initialization</ol> + * <ol>selfclass constructor</ol> + * </ol> + * Other relevant rules: + * <li>this() or super() if present must be the first statement in a constructor</li> + * <li>Cannot use this (and hence this.member) in either this() or super() + * (checked by javac, not ajc) </li> + * <li>Cannot refer to parent instance members in either this() or super() + * (checked by javac, not ajc) </li> + * <li>an enclosing instance is accessible only in the body of an instance + * method, constructor (after the explicit constructor invocation, if any), + * initializer block, or in the initializer expression of an instance variable.</li> + * <p>fault model: + * the compiler is inserting member initialization after the explicit + * constructor call in the intermediate code. I.e., it produces: + * <pre>ThisCall() { + * this("correctValue"); + * { + * this.initString = "INIT"; + * this.initNull = null; + * }</pre> + * when it should produce: + * <pre>ThisCall() { + * this("correctValue");</pre> + * + * <p>fix model: + * Since member initialization must occur before this() call, + * and this() must be first in the constructor, + * I see no way to implement before advice on member initializers + * using preprocessing to produce source code except to put them only + * (and always) in the constructors without this() calls. + * + * <p>Variants tested in this coverage extension of the original test case: + * <li>{type}[Object, String, Primitive]: Different member types</li> + * <li>location[top, bottom, mixed]: location of the member initializer in the class declaration - + * before constructor, after constructor</li> + * <li>initializer[simpleExpression, blockExpression, none]: + * type of member initialization + * (<code>Member m = x;<code> or <code>Member m; { m = x; }<code>) + * with location variants. </li> + * <li>initializerLocus[this (default), super, enclosing ]: + * fields being initialized - this instance, superclass, enclosing class + * <li>{enclosingClass}[none, Outer, ]: Different member types</li> + * + * <p>Variants not (yet?) tested: + * <li>static variants</li> + * <li>{super}[{default},Child]: Calling <code>super()</code> rather than <code>this()</code> </li> + * + * <p>Untestable variants: + * <li>Illegal to use this or super member values in explicit constructor call parameter + * evaluation: <code>super("result: " + member)</code> + * or <code>this("result: " + member)</code>. + * or <code>this("result: " + super.member)</code>. + * + * $Id: MemberInitializationsAfterExplicitConstructorCallsCoverage.java,v 1.2 2001/08/03 22:38:49 isberg Exp $ + */ +public class MemberInitializationsAfterExplicitConstructorCallsCoverage { + public static final String INPUT = "input"; + public static final String INIT = "INIT"; + public static void main(String[] args) { + test(); + } + + public static void test() { + boolean doPassingTests = true; + boolean doFailingTests = true; + //--------- proof that test code is correct + { ThisCallTopSimple thisCall = new ThisCallTopSimple(1); thisCall.go(); } + //--------- passing test cases + //--- this duplicates original test case + // ThisCall thisCall; + // no constructor call to this + // thisCall = new ThisCall(INPUT); + // thisCall.go(); + //--- new coverage tests - 5 tests, 6 errors each, 30 errors + if (doPassingTests) { + { ThisCallTopSimple thisCall = new ThisCallTopSimple(INPUT); thisCall.go(); } + { ThisCallTopBlock thisCall = new ThisCallTopBlock(INPUT); thisCall.go(); } + { ThisCallBottomSimple thisCall = new ThisCallBottomSimple(INPUT); thisCall.go(); } + { ThisCallBottomBlock thisCall = new ThisCallBottomBlock(INPUT); thisCall.go(); } + { ThisCallMixed thisCall = new ThisCallMixed(INPUT); thisCall.go(); } + // all super cases pass + { ThisCallChild thisCall = new ThisCallChild(); thisCall.go(); } + { ThisCallChild thisCall = new ThisCallChild(2); thisCall.go(); } + { ThisCallChild thisCall = new ThisCallChild(INPUT); thisCall.go(); } + // enclosed inner class initializer can access enclosing members + { ThisCallEnclosing.ThisCallEnclosed thisCall + = (new ThisCallEnclosing("ignored")).new ThisCallEnclosed(); } + } + // { ThisCallChild thisCall = new ThisCallChild(); thisCall.go(); } + + //--------- failing test cases + //--- duplicate original test case + // fails - constructor call to this + //thisCall = new ThisCall(); + //thisCall.go(); + //--- new coverage tests + if (doFailingTests) { + { ThisCallTopSimple thisCall = new ThisCallTopSimple(); thisCall.go(); } + { ThisCallTopBlock thisCall = new ThisCallTopBlock(); thisCall.go(); } + { ThisCallBottomSimple thisCall = new ThisCallBottomSimple(); thisCall.go(); } + { ThisCallBottomBlock thisCall = new ThisCallBottomBlock(); thisCall.go(); } + { ThisCallMixed thisCall = new ThisCallMixed(); thisCall.go(); } + } + + //--------- impossible test cases + //---- unable to test superclass initialization before instance + // { ThisCallChild thisCall = new ThisCallChild((long)1l); thisCall.go(); } + } + + /** variant: location top, initializer simpleExpression */ + static class ThisCallTopSimple { + /** type primitive, location top, initializer simpleExpression */ + int initOne = 1; + /** type String, location top, initializer simpleExpression */ + String initString = "INIT"; + /** type Object, location top, initializer simpleExpression */ + Object initNull = null; + /** type String, location top, initializer none */ + String initNone; + + /** no bug when calling this directly */ + ThisCallTopSimple (String input) { + checkMembersHaveInitializedValues("constructor ThisCallTopSimple(\" + input + \")"); + setValues(input); + checkMembersHaveSetValues("constructor ThisCallTopSimple.ThisCallTopSimple(\" + input + \")"); + } + void setValues(String input) { + this.initString = input; + this.initNull = input; + this.initNone = input; + this.initOne = 2; + } + + /** proof that test code is correct */ + ThisCallTopSimple (int ignored) { + checkMembersHaveInitializedValues("constructor ThisCallTopSimple.ThisCallTopSimple(int)"); + setValues(INPUT); + checkMembersHaveSetValues("constructor ThisCallTopSimple.ThisCallTopSimple(int)"); + } + + /** bug when calling this which calls ThisCall(String) */ + ThisCallTopSimple () { + this(INPUT); + checkMembersHaveSetValues("constructor ThisCallTopSimple.ThisCallTopSimple()"); + } + + /** redundant check - same check at end of constructors */ + void go() { + checkMembersHaveSetValues("method ThisCallTopSimple.go()"); + } + /** the same method for all variants */ + protected void checkMembersHaveInitializedValues(String label) { + Tester.checkEqual("INIT", initString, label + " initialized "); + Tester.checkEqual((Object) null, initNull, label + " initialized "); + Tester.checkEqual((Object) null, initNone, label + " initialized "); + Tester.checkEqual(1, initOne, label + " initialized "); + } + + /** the same method for all variants */ + protected void checkMembersHaveSetValues(String label) { + Tester.checkEqual(2, initOne, label + " set "); + Tester.checkEqual("input", initString, label + " set "); + Tester.checkEqual("input", initNone, label + " set "); + // Object uses strict/reference identity - input dependency + Tester.checkEqual(INPUT, initNull, label + " set "); + } + } // ThisCallTopSimple + + /** variant: location top, initializer blockExpression */ + static class ThisCallTopBlock { + /** top declarations */ + /** type primitive, location top, initializer blockExpression */ + int initOne; + /** type String, location top, initializer blockExpression */ + String initString; + /** type Object, location top, initializer blockExpression */ + Object initNull; + /** type String, location top, initializer none */ + String initNone; + + /** top initializer block */ + { + initOne = 1; + initString = "INIT"; + initNull = null; + } + + /** no bug when calling this directly */ + ThisCallTopBlock (String input) { + checkMembersHaveInitializedValues("constructor ThisCallTopBlock(\" + input + \")"); + this.initString = input; + this.initNull = input; + this.initNone = input; + this.initOne = 2; + checkMembersHaveSetValues("constructor ThisCallTopSimple.ThisCall(\" + input + \")"); + } + + /** bug when calling this which calls ThisCallTopBlock(String) */ + ThisCallTopBlock () { + this(INPUT); + checkMembersHaveSetValues("constructor ThisCallTopSimple.ThisCallTopBlock()"); + } + + /** redundant check - same check at end of constructors */ + void go() { + checkMembersHaveSetValues("method ThisCallTopBlock.go()"); + } + + /** the same method for all variants */ + protected void checkMembersHaveInitializedValues(String label) { + Tester.checkEqual("INIT", initString, label + " initialized "); + Tester.checkEqual((Object) null, initNull, label + " initialized "); + Tester.checkEqual((Object) null, initNone, label + " initialized "); + Tester.checkEqual(1, initOne, label + " initialized "); + } + + /** the same method for all variants */ + protected void checkMembersHaveSetValues(String label) { + Tester.checkEqual(2, initOne, label + " set "); + Tester.checkEqual("input", initString, label + " set "); + Tester.checkEqual("input", initNone, label + " set "); + // Object uses strict/reference identity - input dependency + Tester.checkEqual(INPUT, initNull, label + " set "); + } + } // ThisCallTopBlock + + /** variant: location bottom, initializer simpleExpression */ + static class ThisCallBottomSimple { + /** no bug when calling this directly */ + ThisCallBottomSimple (String input) { + checkMembersHaveInitializedValues("constructor ThisCallBottomSimple(\" + input + \")"); + this.initString = input; + this.initNull = input; + this.initNone = input; + this.initOne = 2; + checkMembersHaveSetValues("constructor ThisCallBottomSimple.ThisCallBottomSimple(\" + input + \")"); + } + + /** bug when calling this which calls ThisCallBottomSimple(String) */ + ThisCallBottomSimple () { + this(INPUT); + checkMembersHaveSetValues("constructor ThisCallBottomSimple.ThisCallBottomSimple()"); + } + + /** redundant check - same check at end of constructors */ + void go() { + checkMembersHaveSetValues("method ThisCallBottomSimple.go()"); + } + + /** the same method for all variants */ + protected void checkMembersHaveInitializedValues(String label) { + Tester.checkEqual("INIT", initString, label + " initialized "); + Tester.checkEqual((Object) null, initNull, label + " initialized "); + Tester.checkEqual((Object) null, initNone, label + " initialized "); + Tester.checkEqual(1, initOne, label + " initialized "); + } + + /** the same method for all variants */ + protected void checkMembersHaveSetValues(String label) { + Tester.checkEqual(2, initOne, label + " set "); + Tester.checkEqual("input", initString, label + " set "); + Tester.checkEqual("input", initNone, label + " set "); + // Object uses strict/reference identity - input dependency + Tester.checkEqual(INPUT, initNull, label + " set "); + } + /** type primitive, location bottom, initializer simpleExpression */ + int initOne = 1; + /** type String, location bottom, initializer simpleExpression */ + String initString = "INIT"; + /** type Object, location bottom, initializer simpleExpression */ + Object initNull = null; + /** type String, location bottom, initializer none */ + String initNone; + } // ThisCallBottomSimple + + /** variant: location bottom, initializer blockExpression */ + static class ThisCallBottomBlock { + /** no bug when calling this directly */ + ThisCallBottomBlock (String input) { + checkMembersHaveInitializedValues("constructor ThisCallBottomBlock(\" + input + \")"); + this.initString = input; + this.initNull = input; + this.initNone = input; + this.initOne = 2; + checkMembersHaveSetValues("constructor ThisCallBottomBlock.ThisCallBottomBlock(\" + input + \")"); + } + + /** bug when calling this which calls ThisCallBottomBlock(String) */ + ThisCallBottomBlock () { + this(INPUT); + checkMembersHaveSetValues("constructor ThisCallBottemBlock.ThisCallBottomBlock()"); + } + + /** redundant check - same check at end of constructors */ + void go() { + checkMembersHaveSetValues("method ThisCallBottomBlock.go()"); + } + + /** the same method for all variants */ + protected void checkMembersHaveInitializedValues(String label) { + Tester.checkEqual("INIT", initString, label + " initialized "); + Tester.checkEqual((Object) null, initNull, label + " initialized "); + Tester.checkEqual((Object) null, initNone, label + " initialized "); + Tester.checkEqual(1, initOne, label + " initialized "); + } + + /** the same method for all variants */ + protected void checkMembersHaveSetValues(String label) { + Tester.checkEqual(2, initOne, label + " set "); + Tester.checkEqual("input", initString, label + " set "); + Tester.checkEqual("input", initNone, label + " set "); + // Object uses strict/reference identity - input dependency + Tester.checkEqual(INPUT, initNull, label + " set "); + } + /** bottom declarations */ + /** type primitive, location bottom, initializer blockExpression */ + int initOne; + /** type String, location bottom, initializer blockExpression */ + String initString; + /** type Object, location bottom, initializer blockExpression */ + Object initNull; + /** type String, location bottom, initializer none */ + String initNone; + + /** bottom initializer block */ + { + initOne = 1; + initString = "INIT"; + initNull = null; + } + } // ThisCallBottomBlock + + /** variant: location mixed, initializer mixed */ + static class ThisCallMixed { + /** type primitive, location top, initializer simpleExpression */ + int initOne = 1; + /** type String, location top, initializer simpleExpression */ + String initString; + + /** no bug when calling this directly */ + ThisCallMixed (String input) { + checkMembersHaveInitializedValues("constructor ThisCallMixed(\" + input + \")"); + this.initString = input; + this.initNull = input; + this.initNone = input; + this.initOne = 2; + checkMembersHaveSetValues("constructor ThisCallMixed.ThisCallMixed(\" + input + \")"); + } + + /** bug when calling this which calls ThisCallMixed(String) */ + ThisCallMixed () { + this(INPUT); + checkMembersHaveSetValues("constructor ThisCallMixed.ThisCallMixed()"); + } + + /** redundant check - same check at end of constructors */ + void go() { + checkMembersHaveSetValues("method ThisCallMixed.go()"); + } + + /** the same method for all variants */ + protected void checkMembersHaveInitializedValues(String label) { + Tester.checkEqual("INIT", initString, label + " initialized "); + Tester.checkEqual((Object) null, initNull, label + " initialized "); + Tester.checkEqual((Object) null, initNone, label + " initialized "); + Tester.checkEqual(1, initOne, label + " initialized "); + } + + /** the same method for all variants */ + protected void checkMembersHaveSetValues(String label) { + Tester.checkEqual(2, initOne, label + " set "); + Tester.checkEqual("input", initString, label + " set "); + Tester.checkEqual("input", initNone, label + " set "); + // Object uses strict/reference identity - input dependency + Tester.checkEqual(INPUT, initNull, label + " set "); + } + /** bottom declarations */ + /** type String, location bottom, initializer none */ + String initNone; + /** type Object, location bottom, initializer blockExpression */ + Object initNull; + + /** bottom (partial) initializer block */ + { + initString = "INIT"; + initNull = null; + } + } // ThisCallMixed + + static class ThisCallChild extends ThisCallParent { + /** type primitive, location top, initializer simpleExpression */ + int initOne = 1; + /** type String, location top, initializer simpleExpression */ + String initString = "INIT"; + /** type Object, location top, initializer simpleExpression */ + Object initNull = null; + /** type String, location top, initializer none */ + String initNone; + + /** no bug when calling this directly */ + ThisCallChild (String input) { + checkMembersHaveInitializedValues("constructor ThisCallChild(\" + input + \")"); + setValues(input); + checkMembersHaveSetValues("constructor ThisCallChild.ThisCallChild((\" + input + \")");; + Tester.checkEqual(parentObject, INPUT, "ThisCallChild.ThisCallChild(int ignored)"); + } + void setValues(String input) { + this.initString = input; + this.initNull = input; + this.initNone = input; + this.initOne = 2; + } + + /** + * @param correctResult + * @param actual + * @param expected + * @param failedResult + * @param testerMessage the String to use for Tester on failure - + * Tester unused if null + * @return correctResult if expected.equals(actual), failedResult otherwise + */ + static private String checkObject(String correctResult + , Object expected + , Object actual + , String failedResult + , String testerMessage) { + if (null == expected) { + if (null == actual) { + return correctResult; + } // else failures fall through + } else if ((null != actual) && (expected.equals(actual))) { + return correctResult; + } + // failures + if (null != testerMessage) { + Tester.checkEqual(actual, expected, testerMessage); + } + return failedResult; + } + + /** proof that test code is correct */ + ThisCallChild (int ignored) { + checkMembersHaveInitializedValues("constructor ThisCallChild.ThisCallChild(int)"); + setValues(INPUT); + checkMembersHaveSetValues("constructor ThisCallChild.ThisCallChild(int)"); + Tester.checkEqual(parentObject, INPUT, "ThisCallChild.ThisCallChild(int ignored)"); + } + + /** no bug when calling this which calls ThisCall(String) */ + ThisCallChild () { + super(INPUT); + checkMembersHaveInitializedValues("constructor ThisCallChild.ThisCallChild()"); + setValues(INPUT); + checkMembersHaveSetValues("constructor ThisCallChild.ThisCallChild()"); + Tester.checkEqual(parentObject, INPUT, "ThisCallChild.ThisCallChild()"); + } + + private static final String tccsuperlabel = + "ThisCallChild.ThisCallChild(long)/* parent initialization complete before child */"; + /** unable to access superclass member state before explicitly invoking constructor */ + ThisCallChild (long ignored) { + // this would do the check, but it is illegal + // this(checkObject(INPUT, INPUT, parentObject, tccsuperLabel + "_FAILED", tccsuperlabel)); + // this(checkObject(INPUT, INPUT, this$.getParentObject(), tccsuperlabel + "_FAILED", tccsuperlabel)); + checkMembersHaveInitializedValues("constructor ThisCallChild.ThisCallChild()"); + setValues(INPUT); + checkMembersHaveSetValues("constructor ThisCallChild.ThisCallChild()"); + Tester.checkEqual(parentObject, INPUT, "ThisCallChild.ThisCallChild()"); + } + + /** redundant check - same check at end of constructors */ + void go() { + checkMembersHaveSetValues("method ThisCallChild.go()"); + Tester.checkEqual(parentObject, INPUT, "ThisCallChild.go()"); + } + + /** the same method for all variants */ + protected void checkMembersHaveInitializedValues(String label) { + Tester.checkEqual("INIT", initString, label + " initialized "); + Tester.checkEqual((Object) null, initNull, label + " initialized "); + Tester.checkEqual((Object) null, initNone, label + " initialized "); + Tester.checkEqual(1, initOne, label + " initialized "); + } + + /** the same method for all variants */ + protected void checkMembersHaveSetValues(String label) { + Tester.checkEqual(2, initOne, label + " set "); + Tester.checkEqual("input", initString, label + " set "); + Tester.checkEqual("input", initNone, label + " set "); + // Object uses strict/reference identity - input dependency + Tester.checkEqual(INPUT, initNull, label + " set "); + } + } + static class ThisCallParent { + /** not available to in child explicit constructor parameter expression */ + protected Object parentObject = INIT; + /** not available to in child explicit constructor parameter expression */ + protected Object getParentObject() { return parentObject; } + /** no bug here */ + ThisCallParent() { + Tester.checkEqual(parentObject, INIT, "ThisCallParent.ThisCallParent()"); + parentObject = INPUT; + } + /** no bug here */ + ThisCallParent(String input) { + Tester.checkEqual(parentObject, INIT, "ThisCallParent.ThisCallParent(\"" + input + "\")"); + parentObject = input; + } + } +} // MemberInitializationsAfterExplicitConstructorCallsCoverage +/** variant: location enclosing */ +class ThisCallEnclosing { + public static final String INPUT = "input"; + public static final String INIT = "INIT"; + String initString = INIT; + String constructedString; + public ThisCallEnclosed getEnclosed() { + return new ThisCallEnclosed(); + } + /** no bug when calling this directly */ + ThisCallEnclosing (String ignored) { + constructedString = INPUT; + initString = INPUT; + } + + public class ThisCallEnclosed { + boolean didCheck; + { + // check enclosing instance in initializer + Tester.checkEqual(INPUT, initString, "ThisCallEnclosed.<initializer> initString"); + Tester.checkEqual(INPUT, constructedString, "ThisCallEnclosed.<initializer> constructedString"); + didCheck = true; + } + public ThisCallEnclosed() { + this("init: " + initString + " constructed: " + constructedString); + Tester.check(didCheck, "initializer ran before ThisCallEnclosed() body"); + + } + public ThisCallEnclosed(String s) { + Tester.checkEqual(INPUT, initString, "ThisCallEnclosed(String) initString"); + Tester.checkEqual(INPUT, constructedString, "ThisCallEnclosed(String) constructedString"); + Tester.check(didCheck, "initializer ran before ThisCallEnclosed(String) body"); + } + } +} // ThisCallEnclosing |