1  /*
     2   * Copyright the original author or authors.
     3   * 
     4   * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   * 
     8   *      http://www.mozilla.org/MPL/MPL-1.1.html
     9   * 
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  import org.as2lib.core.BasicClass;
    18  import org.as2lib.env.except.IllegalArgumentException;
    19  import org.as2lib.test.speed.TestResultLayout;
    20  import org.as2lib.test.speed.TestSuiteResult;
    21  import org.as2lib.test.speed.MethodInvocation;
    22  import org.as2lib.test.speed.MethodInvocationTestSuiteResult;
    23  import org.as2lib.test.speed.ConfigurableTestSuiteResult;
    24  import org.as2lib.test.speed.SimpleTestSuiteResult;
    25  
    26  /**
    27   * {@code MethodInvocationTreeLayout} lays test suite results out in a tree like
    28   * structure. The method invocations are ordered by their invocation succession and by
    29   * which-invocation-caused-which-other-invocation.
    30   * 
    31   * @author Simon Wacker
    32   */
    33  class org.as2lib.test.speed.layout.MethodInvocationTreeLayout extends BasicClass implements TestResultLayout {
    34  	
    35  	/** All method invocations of the test suite result to lay-out. */
    36  	private var allMethodInvocations:Array;
    37  	
    38  	/**
    39  	 * Constructs a new {@code MethodInvocationTreeLayout} instance.
    40  	 */
    41  	public function MethodInvocationTreeLayout(Void) {
    42  	}
    43  	
    44  	/**
    45  	 * Lays the passed-in {@code testSuiteResult} out as method invocation tree and
    46  	 * returns a new lay-outed test suite result.
    47  	 * 
    48  	 * @param testSuiteResult the test suite result to lay-out
    49  	 * @return the lay-outed test suite result
    50  	 */
    51  	public function layOut(testSuiteResult:TestSuiteResult):TestSuiteResult {
    52  		if (!testSuiteResult) throw new IllegalArgumentException("Argument 'testSuiteResult' [" + testSuiteResult + "] must not be 'null' nor 'undefined'.", this, arguments);
    53  		var result:SimpleTestSuiteResult = new SimpleTestSuiteResult(testSuiteResult.getName());
    54  		this.allMethodInvocations = testSuiteResult.getAllMethodInvocations();
    55  		if (this.allMethodInvocations) {
    56  			var rootMethodInvocations:Array = findRootMethodInvocations();
    57  			buildMethodInvocationTree(result, rootMethodInvocations);
    58  		}
    59  		result.sort(SimpleTestSuiteResult.METHOD_INVOCATION_SUCCESSION);
    60  		return result;
    61  	}
    62  	
    63  	/**
    64  	 * Returns an array that contains all root method invocations. Root method
    65  	 * invocations are the ones that have no parent method invocation.
    66  	 * 
    67  	 * @return all root method invocations as {@link MethodInvocation} instances
    68  	 */
    69  	private function findRootMethodInvocations(Void):Array {
    70  		return findChildMethodInvocations(null);
    71  	}
    72  	
    73  	/**
    74  	 * Finds the child method invocations for the passed-in
    75  	 * {@code parentMethodInvocation} and returns them as {@link MethodInvocation}
    76  	 * instances.
    77  	 * 
    78  	 * @param parentMethodInvocations the method invocation to return the childs for
    79  	 * @return the child method invocations of the parent method invocation
    80  	 */
    81  	private function findChildMethodInvocations(parentMethodInvocation:MethodInvocation):Array {
    82  		var result:Array = new Array();
    83  		for (var i:Number = 0; i < this.allMethodInvocations.length; i++) {
    84  			var methodInvocation:MethodInvocation = this.allMethodInvocations[i];
    85  			if (methodInvocation.getCaller() == parentMethodInvocation) {
    86  				result.push(methodInvocation);
    87  			}
    88  		}
    89  		return result;
    90  	}
    91  	
    92  	/**
    93  	 * Builds the method invocation tree starting from the passed-in
    94  	 * {@code methodInvocations} and adding all results to the passed-in
    95  	 * {@code testSuiteResult}. This is done recursively.
    96  	 * 
    97  	 * @param testSuiteResult the result to add sub-results
    98  	 * @param methodInvocations {@link MethodInvocation} instances to start at
    99  	 */
   100  	private function buildMethodInvocationTree(testSuiteResult:ConfigurableTestSuiteResult, methodInvocations:Array):Void {
   101  		if (testSuiteResult && methodInvocations) {
   102  			for (var i:Number = 0; i < methodInvocations.length; i++) {
   103  				var methodInvocation:MethodInvocation = methodInvocations[i];
   104  				var p:MethodInvocationTestSuiteResult = new MethodInvocationTestSuiteResult(methodInvocation);
   105  				testSuiteResult.addTestResult(p);
   106  				var childMethodInvocations:Array = findChildMethodInvocations(methodInvocation);
   107  				buildMethodInvocationTree(p, childMethodInvocations);
   108  			}
   109  		}
   110  	}
   111  	
   112  }