/************************************************ Copyright (c) 2013-2014 by Progress Software Corporation. All rights reserved. *************************************************/ /*------------------------------------------------------------------------ File : ClassAnnotationInfo Purpose : Stores the information related to the BeforeClass,Before, Test, After, AfterClass annotations in the test class. Contains methods to run specific annotated methods. Syntax : Description : Author(s) : hgarapat Created : Mon Jul 23 11:21:50 IST 2012 Notes : ----------------------------------------------------------------------*/ USING OpenEdge.Core.AssertionFailedError. USING OpenEdge.ABLUnit.Reflection.AnnotationInfo. USING OpenEdge.ABLUnit.Reflection.ClassAnnotationInfo. USING OpenEdge.ABLUnit.Reflection.TestInfo. USING OpenEdge.ABLUnit.Reflection.TestInfo. USING OpenEdge.ABLUnit.Results.TestTestResult. USING OpenEdge.ABLUnit.Results.TestTypeResult. USING OpenEdge.Core.Collections.Array. CLASS OpenEdge.ABLUnit.Reflection.ClassAnnotationInfo: DEFINE PRIVATE VARIABLE beforeClassMethod AS TestInfo NO-UNDO. DEFINE PRIVATE VARIABLE beforeMethod AS TestInfo NO-UNDO. DEFINE PRIVATE VARIABLE testList AS Array NO-UNDO. DEFINE PUBLIC PROPERTY testCount AS INTEGER NO-UNDO GET. SET. DEFINE PRIVATE VARIABLE afterMethod AS TestInfo NO-UNDO. DEFINE PRIVATE VARIABLE afterClassMethod AS TestInfo NO-UNDO. DEFINE PRIVATE VARIABLE testMethodResult AS TestTestResult NO-UNDO. /*------------------------------------------------------------------------------ Purpose: Notes: ------------------------------------------------------------------------------*/ CONSTRUCTOR PUBLIC ClassAnnotationInfo ( ): SUPER (). testList = NEW Array(). testList:AutoExpand = TRUE. END CONSTRUCTOR. METHOD PUBLIC VOID setBeforeClass(INPUT bClass AS TestInfo): IF beforeClassMethod = ? THEN beforeClassMethod= bClass. ELSE throwError(). END METHOD. METHOD PUBLIC CHARACTER getBeforeClass(): RETURN beforeClassMethod:getTestName(). END METHOD. METHOD PUBLIC CHARACTER getAfterClass(): RETURN afterClassMethod:getTestName(). END METHOD. METHOD PUBLIC Array getTestList(): RETURN testList. END METHOD. METHOD PUBLIC VOID setAfterClass(INPUT aClass AS TestInfo): IF afterClassMethod = ? THEN afterClassMethod= aClass. ELSE throwError(). END METHOD. METHOD PUBLIC VOID setBeforeMethod(INPUT bMethod AS TestInfo): IF beforeMethod = ? THEN beforeMethod = bMethod. ELSE throwError(). END METHOD. METHOD PUBLIC VOID setAfterMethod(INPUT aMethod AS TestInfo): IF afterMethod = ? THEN afterMethod = aMethod. ELSE throwError(). END METHOD. METHOD PUBLIC VOID AddTestMethod(INPUT tMethod AS TestInfo): testCount = testCount + 1. testList:SetValue(tMethod, testCount). END METHOD. /*------------------------------------------------------------------------------ Runs the @BeforeClass annotated method. ------------------------------------------------------------------------------*/ METHOD PUBLIC TestTypeResult RunBeforeClass(INPUT testClassType AS Progress.Lang.Object, INPUT testClassResult AS TestTypeResult ): IF NOT beforeClassMethod = ? AND NOT testList:size = 0 THEN DO ON ERROR UNDO, THROW: Invoke(testClassType, beforeClassMethod:getTestName()). CATCH e AS Progress.Lang.Error : RETURN ERROR e. END CATCH. END. RETURN testClassResult. END METHOD. /*------------------------------------------------------------------------------ Runs the @Before annotated method ------------------------------------------------------------------------------*/ METHOD PUBLIC VOID RunBeforeMethod(INPUT testClassType AS Progress.Lang.Object, INPUT testResult AS TestTestResult): IF NOT beforeMethod = ? THEN DO ON ERROR UNDO, THROW: Invoke(testClassType, beforeMethod:getTestName()). CATCH e AS Progress.Lang.Error : RETURN ERROR e. END CATCH. END. END METHOD. /*------------------------------------------------------------------------------ Runs a particular test method denoted by OpenEdge.ABLUnit.Reflection.TestInfo ------------------------------------------------------------------------------*/ METHOD PUBLIC TestTestResult RunSelectedTestMethod(INPUT testClassType AS Progress.Lang.Object, INPUT testMethod AS TestInfo): DEFINE VARIABLE testResult AS TestTestResult NO-UNDO. testResult = NEW TestTestResult(). RunBeforeMethod(testClassType, testResult). RunTestMethod(testClassType, testResult, testMethod). /* Mike Fechner, Consultingwerk Ltd. 27.05.2016 Handle Consultingwerk AssertException (and derived types like ABLUnit AssertFailedError */ {Consultingwerk/Studio/AblUnit/11_6_0/handle-consultingwerk-exception.i} CATCH err AS AssertionFailedError : testResult:testResult = TestTestResult:StatusFailed. testResult:ErrorMessage = err:GetMessage(). testResult:Error = err. testResult:TestName = testMethod:getTestName(). testResult:isIncomplete = TRUE. END CATCH. CATCH e AS Progress.Lang.Error: testResult:testResult = TestTestResult:StatusError. testResult:Error = err. testResult:TestName = testMethod:getTestName(). testResult:isIncomplete = TRUE. END CATCH. FINALLY: RunAfterMethod(testClassType, testResult). /* Mike Fechner, Consultingwerk Ltd. 27.05.2016 Handle Consultingwerk AssertException (and derived types like ABLUnit AssertFailedError */ {Consultingwerk/Studio/AblUnit/11_6_0/handle-consultingwerk-exception.i} CATCH err AS AssertionFailedError : testResult:TestResult = TestTestResult:StatusFailed. testResult:ErrorMessage = err:GetMessage(). testResult:TestName = testMethod:getTestName(). testResult:Error = err. END CATCH. CATCH e AS Progress.Lang.Error: testResult:TestResult = TestTestResult:StatusError. testResult:Error = e. testResult:TestName = testMethod:getTestName(). END CATCH. FINALLY: RETURN testResult. END FINALLY. END FINALLY. END METHOD. /*------------------------------------------------------------------------------ Invokes instance method. ------------------------------------------------------------------------------*/ METHOD PUBLIC STATIC VOID Invoke(INPUT obj AS Progress.Lang.Object, INPUT testMethod AS CHARACTER): DYNAMIC-INVOKE (obj, testMethod). CATCH e AS Progress.Lang.Error : RETURN ERROR e. END CATCH. END METHOD. /*------------------------------------------------------------------------------ Invokes static method given. ------------------------------------------------------------------------------*/ METHOD PUBLIC STATIC VOID invokeStatic(INPUT obj AS Progress.Lang.Object, INPUT testMethod AS CHARACTER): DYNAMIC-INVOKE (obj:GetClass():TypeName, testMethod). CATCH e AS Progress.Lang.Error : RETURN ERROR e. END CATCH. END METHOD. /*------------------------------------------------------------------------------ Runs a particular @Test method ------------------------------------------------------------------------------*/ METHOD PUBLIC TestTestResult RunTestMethod(INPUT testClassType AS Progress.Lang.Object, INPUT testResult AS TestTestResult, INPUT testMethod AS TestInfo ): DEFINE VARIABLE expectedException AS CHARACTER NO-UNDO. DEFINE VARIABLE annotations AS Array NO-UNDO. DEFINE VARIABLE annotation AS AnnotationInfo NO-UNDO. DEFINE VARIABLE exception AS Progress.Lang.Error NO-UNDO. annotations = testMethod:annotations. /** considering only the 1st annotation for now**/ annotation = CAST(annotations:GetValue(1), AnnotationInfo ). expectedException = annotation:getAttributeValue(). IF testMethod:isStatic THEN invokeStatic(testClassType, testMethod:getTestName()). ELSE Invoke(testClassType, testMethod:getTestName()). IF expectedException = "" THEN DO: testResult:TestResult = TestTestResult:StatusPassed. testResult:TestName = testMethod:getTestName(). END. ELSE DO: testResult:TestResult = TestTestResult:StatusFailed. testResult:TestName = testMethod:getTestName(). testResult:ErrorMessage = "Expecting:" + expectedException + " but this expection is not raised.". exception = NEW Progress.Lang.AppError("No exception is raised but expecting " + expectedException, 1). testResult:Error = exception. END. CATCH e AS Progress.Lang.Error : IF expectedException = "" THEN DO: /* Mike Fechner, Consultingwerk Ltd. 27.05.2016 Handle Consultingwerk AssertException (and derived types like ABLUnit AssertFailedError */ {Consultingwerk/Studio/AblUnit/11_6_0/handle-consultingwerk-exception2.i testResult testMethod} IF (e:GetClass():TypeName = "OpenEdge.Core.AssertionFailedError") THEN DO: testResult:TestResult = TestTestResult:StatusFailed. testResult:TestName = testMethod:getTestName(). testResult:Error = e. testResult:ErrorMessage = e:GetMessage(1). END. ELSE DO: testResult:TestResult = TestTestResult:StatusError. testResult:TestName = testMethod:getTestName(). testResult:Error = e. END. END. ELSE IF (ClassAnnotationInfo:IsTypeOf(e, GetExpectedErrorType(expectedException))) THEN DO: testResult:TestResult = TestTestResult:StatusPassed. testResult:TestName = testMethod:getTestName(). END. ELSE DO: testResult:TestResult = OpenEdge.ABLUnit.Results.TestTestResult:StatusFailed. testResult:TestName = testMethod:getTestName(). testResult:ErrorMessage = "Expecting:" + expectedException + " but found:" + e:GetClass():TypeName. testResult:Error = e. END. END CATCH. FINALLY: RETURN testResult. END FINALLY. END METHOD. /*---------------------------------------------------------------------------- Expands the given expected error type if it is a recognised abbreviation. ----------------------------------------------------------------------------*/ METHOD PUBLIC STATIC CHARACTER GetExpectedErrorType(INPUT expectedError AS CHARACTER): /* Add the package name for recognised error types */ CASE expectedError: WHEN "Error" OR WHEN "AppError" OR WHEN "ProError" OR WHEN "SoapFaultError" OR WHEN "SysError" THEN RETURN "Progress.Lang." + expectedError. WHEN "Stop" OR WHEN "Quit" THEN RETURN "Progress.Lang.SysError". END CASE. RETURN expectedError. END METHOD. /*---------------------------------------------------------------------------- Returns true if the given object can be cast to the given type. Otherwise returns false. ----------------------------------------------------------------------------*/ METHOD PUBLIC STATIC LOGICAL IsTypeOf(INPUT obj AS Progress.Lang.Object, INPUT castType AS CHARACTER): IF obj:GetClass():TypeName = castType THEN RETURN TRUE. DEFINE VARIABLE castObject AS Progress.Lang.Object NO-UNDO. castObject = DYNAMIC-CAST(obj, castType) NO-ERROR. IF ERROR-STATUS:ERROR OR ERROR-STATUS:NUM-MESSAGES > 0 THEN RETURN FALSE. RETURN TRUE. END METHOD. /*------------------------------------------------------------------------------ Runs @After annotated method ------------------------------------------------------------------------------*/ METHOD PUBLIC VOID RunAfterMethod(INPUT testClassType AS Progress.Lang.Object, INPUT testResult AS OpenEdge.ABLUnit.Results.TestTestResult): IF NOT afterMethod = ? THEN DO ON ERROR UNDO, THROW: Invoke(testClassType, afterMethod:getTestName()). CATCH e AS Progress.Lang.Error : RETURN ERROR e. END CATCH. END. RETURN. END METHOD. /*------------------------------------------------------------------------------ Runs @AfterClass annotated method ------------------------------------------------------------------------------*/ METHOD PUBLIC OpenEdge.ABLUnit.Results.TestTypeResult RunAfterClass(INPUT testClassType AS Progress.Lang.Object): IF NOT afterClassMethod = ? AND NOT testList:size = 0 THEN DO ON ERROR UNDO, THROW: Invoke(testClassType, afterClassMethod:getTestName()). CATCH e AS Progress.Lang.Error : RETURN ERROR e. END CATCH. END. END METHOD. /*------------------------------------------------------------------------------ Throws error for multiple occurence of lifecycle methods ------------------------------------------------------------------------------*/ METHOD PRIVATE VOID throwError( ): RETURN ERROR NEW Progress.Lang.AppError("Life cycle annotations can not occur more than once.", 0). END METHOD. END CLASS.