|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- // 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
|