From fe322040ed4e7c676a3aa3c76447c870c2202a9a Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Mon, 21 Jul 2014 17:06:27 +0100 Subject: [PATCH 01/33] Issue #8 - AssertString:IsNotNullOrEmpty does not use failMessage - Pass failMessage parameter to Assert methods called in this method. --- src/OEUnit/Assertion/AssertStringType.i | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OEUnit/Assertion/AssertStringType.i b/src/OEUnit/Assertion/AssertStringType.i index e4755fa..3dc3261 100644 --- a/src/OEUnit/Assertion/AssertStringType.i +++ b/src/OEUnit/Assertion/AssertStringType.i @@ -38,8 +38,8 @@ throws an AssertionFailedError with the given failMessage. ----------------------------------------------------------------------------*/ METHOD STATIC VOID IsNotNullOrEmpty(INPUT val AS {&DataType}, INPUT failMessage AS CHARACTER): - Assert:IsNotNull(val). - Assert:AreNotEqual(val, ""). + Assert:IsNotNull(val, failMessage). + Assert:AreNotEqual(val, "", failMessage). END METHOD. /*---------------------------------------------------------------------------- From b81dc3a9e119aa90f193bb0879415c32b665a2ba Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Thu, 28 Aug 2014 17:13:37 +0100 Subject: [PATCH 02/33] Fixes #10 - JUnit Package name - Package name to be extracted from full class name and used in JUnit Reporter. --- src/OEUnit/Automation/JUnitReporter.cls | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/OEUnit/Automation/JUnitReporter.cls b/src/OEUnit/Automation/JUnitReporter.cls index 7234823..0641fef 100644 --- a/src/OEUnit/Automation/JUnitReporter.cls +++ b/src/OEUnit/Automation/JUnitReporter.cls @@ -41,8 +41,9 @@ CLASS OEUnit.Automation.JUnitReporter INHERITS FileReporter: ----------------------------------------------------------------------------*/ METHOD PROTECTED VOID ReportTestClassResult(INPUT hSaxWriter AS HANDLE, INPUT results AS TestClassResult): - DEFINE VARIABLE HasChildSuites AS LOGICAL NO-UNDO INITIAL FALSE. - DEFINE VARIABLE i AS INTEGER NO-UNDO. + DEFINE VARIABLE HasChildSuites AS LOGICAL NO-UNDO INITIAL FALSE. + DEFINE VARIABLE i AS INTEGER NO-UNDO. + DEFINE VARIABLE Package AS CHARACTER NO-UNDO. /* Determine if there are any child TestClassResult items - if so, this * needs to be output as a "testsuites" element, not a "testsuite". @@ -71,11 +72,20 @@ CLASS OEUnit.Automation.JUnitReporter INHERITS FileReporter: IF NOT HasChildSuites THEN DO: hSaxWriter:INSERT-ATTRIBUTE("skipped", STRING(results:CountTestsWithStatus(TestResult:StatusIgnored))). + + /* Determine package name by removing class name from end of full class name */ + ASSIGN Package = results:GetName() + i = R-INDEX(Package, "."). + + IF(i > 1) THEN + ASSIGN Package = SUBSTRING(Package,1, i - 1). + + hSaxWriter:INSERT-ATTRIBUTE("package", TRIM(Package,".")). + /* The following attributes are not implementable at this point in time, but are available in the * JUnit XML format. Uncomment, and implement when possible. */ /* hSaxWriter:INSERT-ATTRIBUTE("id", ""). */ - /* hSaxWriter:INSERT-ATTRIBUTE("package", ""). */ /* hSaxWriter:INSERT-ATTRIBUTE("hostname", ""). */ /* hSaxWriter:INSERT-ATTRIBUTE("timestamp", ""). */ END. From bc5c962e1574fe36d9031011f7c13967fe1ad2e4 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Tue, 14 Oct 2014 09:25:06 +0100 Subject: [PATCH 03/33] Add NamedList class to OEUnit.Util and matching unit tests --- src/OEUnit/Tests/Util/AllTestSuite.cls | 1 + src/OEUnit/Tests/Util/NamedListTest.cls | 101 ++++++++++++++ src/OEUnit/Util/NamedList.cls | 168 ++++++++++++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 src/OEUnit/Tests/Util/NamedListTest.cls create mode 100644 src/OEUnit/Util/NamedList.cls diff --git a/src/OEUnit/Tests/Util/AllTestSuite.cls b/src/OEUnit/Tests/Util/AllTestSuite.cls index 30f498f..d2043f9 100644 --- a/src/OEUnit/Tests/Util/AllTestSuite.cls +++ b/src/OEUnit/Tests/Util/AllTestSuite.cls @@ -8,6 +8,7 @@ CLASS OEUnit.Tests.Util.AllTestSuite INHERITS TestSuite: CONSTRUCTOR AllTestSuite(): AddTest(NEW ListTest()). + AddTest(NEW NamedListTest()). END CONSTRUCTOR. END CLASS. \ No newline at end of file diff --git a/src/OEUnit/Tests/Util/NamedListTest.cls b/src/OEUnit/Tests/Util/NamedListTest.cls new file mode 100644 index 0000000..993763b --- /dev/null +++ b/src/OEUnit/Tests/Util/NamedListTest.cls @@ -0,0 +1,101 @@ + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +USING Progress.Lang.*. +USING OEUnit.Assertion.Assert. +USING OEUnit.Util.*. +USING OEUnit.Tests.Util.*. + +CLASS OEUnit.Tests.Util.NamedListTest : + + DEFINE PRIVATE VARIABLE list1 AS NamedList NO-UNDO. + + DEFINE PRIVATE VARIABLE name1 AS CHARACTER NO-UNDO INITIAL "Name1". + DEFINE PRIVATE VARIABLE value1 AS CHARACTER NO-UNDO INITIAL "Value1". + DEFINE PRIVATE VARIABLE name2 AS CHARACTER NO-UNDO INITIAL "Name2". + DEFINE PRIVATE VARIABLE value2 AS CHARACTER NO-UNDO INITIAL "Value2". + DEFINE PRIVATE VARIABLE name3 AS CHARACTER NO-UNDO INITIAL "Name3". + DEFINE PRIVATE VARIABLE value3 AS CHARACTER NO-UNDO INITIAL "Value3". + DEFINE PRIVATE VARIABLE name4 AS CHARACTER NO-UNDO INITIAL "Name4". + DEFINE PRIVATE VARIABLE value4 AS CHARACTER NO-UNDO INITIAL "Value4". + + @Before. + METHOD PUBLIC VOID CreateList(): + list1 = NEW NamedList(). + list1:Add(name1, value1). + list1:Add(name2, value2). + list1:Add(name3, value3). + list1:Add(name4, value4). + END METHOD. + + @After. + METHOD PUBLIC VOID DeleteList(): + DELETE OBJECT list1 NO-ERROR. + END METHOD. + + @Test. + METHOD PUBLIC VOID AddDuplicate(): + list1:Add(name1, value2). + Assert:AreEqual(list1:GET(name1), value2). + END METHOD. + + @Test. + METHOD PUBLIC VOID TestMoveAndReset(): + list1:MoveFirst(). + Assert:AreEqual(list1:CurrentName, name1). + Assert:AreEqual(list1:CurrentValue, value1). + list1:MoveNext(). + Assert:AreEqual(list1:CurrentName, name2). + Assert:AreEqual(list1:CurrentValue, value2). + list1:Reset(). + list1:MoveNext(). + Assert:AreEqual(list1:CurrentName, name1). + Assert:AreEqual(list1:CurrentValue, value1). + list1:MoveNext(). + Assert:AreEqual(list1:CurrentName, name2). + Assert:AreEqual(list1:CurrentValue, value2). + list1:Reset(). + list1:MovePrevious(). + Assert:AreEqual(list1:CurrentName, name4). + Assert:AreEqual(list1:CurrentValue, value4). + list1:MovePrevious(). + Assert:AreEqual(list1:CurrentName, name3). + Assert:AreEqual(list1:CurrentValue, value3). + list1:MoveFirst(). + Assert:AreEqual(list1:CurrentName, name1). + Assert:AreEqual(list1:CurrentValue, value1). + list1:MoveLast(). + Assert:AreEqual(list1:CurrentName, name4). + Assert:AreEqual(list1:CurrentValue, value4). + END METHOD. + + @Test(expected="Progress.Lang.AppError"). + METHOD PUBLIC VOID Remove(): + Assert:AreEqual(list1:Get(name1), value1). + list1:Remove(name1). + list1:Get(name1). + END METHOD. + + @Test(expected="Progress.Lang.AppError"). + METHOD PUBLIC VOID RemoveNonExisting(): + list1:Remove("does not exist"). + END METHOD. + + @Test. + METHOD PUBLIC VOID Get(): + Assert:AreEqual(list1:Get(name1), value1). + END METHOD. + + @Test(expected="Progress.Lang.AppError"). + METHOD PUBLIC VOID GetNonExisting(): + list1:Get("does not exist"). + END METHOD. + + @Test. + METHOD PUBLIC VOID HasValue(): + Assert:IsTrue(list1:HasValue(name1)). + Assert:IsFalse(list1:HasValue("does not exist")). + END METHOD. + +END CLASS. + diff --git a/src/OEUnit/Util/NamedList.cls b/src/OEUnit/Util/NamedList.cls new file mode 100644 index 0000000..92998ee --- /dev/null +++ b/src/OEUnit/Util/NamedList.cls @@ -0,0 +1,168 @@ + /*------------------------------------------------------------------------------ + File : NamedList.cls + Package : OEUnit.Util + Description : Stores a named list of strings. List elements can be accessed + by their name only. +------------------------------------------------------------------------------*/ + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +USING Progress.Lang.*. + +CLASS OEUnit.Util.NamedList: + + DEFINE PRIVATE VARIABLE reset AS LOGICAL NO-UNDO. + + /*---------------------------------------------------------------------------- + Temp table to store elements (integer-object pairs). + ----------------------------------------------------------------------------*/ + DEFINE PROTECTED TEMP-TABLE element NO-UNDO + FIELD name AS CHARACTER + FIELD val AS CHARACTER + INDEX sequence IS PRIMARY UNIQUE name ASCENDING. + + /*---------------------------------------------------------------------------- + The number of elements in the list + ----------------------------------------------------------------------------*/ + DEFINE PUBLIC PROPERTY Size AS INTEGER NO-UNDO INIT 0 + GET. + PRIVATE SET. + + /*---------------------------------------------------------------------------- + Return the name of item in the list that is currently being pointed to. + ----------------------------------------------------------------------------*/ + DEFINE PUBLIC PROPERTY CurrentName AS CHARACTER NO-UNDO + GET(): + IF AVAILABLE(element) THEN + RETURN element.name. + RETURN ?. + END GET. + /*SET. */ + + /*---------------------------------------------------------------------------- + Return the value of item in the list that is currently being pointed to. + ----------------------------------------------------------------------------*/ + DEFINE PUBLIC PROPERTY CurrentValue AS CHARACTER NO-UNDO + GET(): + IF AVAILABLE(element) THEN + RETURN element.val. + RETURN ?. + END GET. + /*SET. */ + + /*---------------------------------------------------------------------------- + Default Constructor. + ----------------------------------------------------------------------------*/ + CONSTRUCTOR NamedList(): + END CONSTRUCTOR. + + DESTRUCTOR NamedList(): + FOR EACH element: + DELETE element. + END. + END DESTRUCTOR. + + /*---------------------------------------------------------------------------- + Add the name and value pair to the list. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC VOID Add(INPUT nam AS CHARACTER, INPUT val AS CHARACTER): + FIND element WHERE element.name = nam NO-ERROR. + IF NOT AVAILABLE(element) THEN + DO: + Size = Size + 1. + CREATE element. + ASSIGN element.name = nam + element.val = val. + END. + ELSE ASSIGN element.val = val. + END METHOD. + + /*---------------------------------------------------------------------------- + Returns the value matching the given name from the list. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC CHARACTER Get(INPUT name AS CHARACTER): + FIND element WHERE element.name = name NO-ERROR. + IF AVAILABLE(element) THEN RETURN element.val. + RETURN ERROR NEW AppError("Value not found with name: " + name,0). + END METHOD. + + /*---------------------------------------------------------------------------- + Removes the given object from the list. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC VOID Remove(INPUT name AS CHARACTER): + FIND element WHERE element.name = name NO-ERROR. + IF AVAILABLE(element) THEN + RemoveCurrent(). + ELSE + RETURN ERROR NEW AppError("Value not found in list with name: " + name,0). + END METHOD. + + /*---------------------------------------------------------------------------- + Removes the current element from the list. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC VOID RemoveCurrent(): + IF AVAILABLE(element) THEN DO: + DELETE element. + Size = Size - 1. + END. + END METHOD. + + /*---------------------------------------------------------------------------- + Reset the current pointer position. Calling MoveNext() after calling this + method will position the pointer at the first element in the list. Whereas + calling MovePrevious() will position the pointer at the last element in the + list. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC VOID Reset(): + reset = TRUE. + END METHOD. + + /*---------------------------------------------------------------------------- + Positions the pointer at the first element in the list. Returns true if exists. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL MoveFirst(): + FIND FIRST element NO-ERROR. + RETURN AVAILABLE(element). + END METHOD. + + /*---------------------------------------------------------------------------- + Positions the pointer at the last element in the list. Returns true if exists. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL MoveLast(): + FIND LAST element NO-ERROR. + RETURN AVAILABLE(element). + END METHOD. + + /*---------------------------------------------------------------------------- + Position the pointer at the next element in the list. Returns true if exists. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL MoveNext(): + IF reset THEN DO: + reset = FALSE. + RETURN MoveFirst(). + END. + FIND NEXT element NO-ERROR. + RETURN AVAILABLE(element). + END METHOD. + + /*---------------------------------------------------------------------------- + Position the pointer at the previous element in the list. Returns true if + exists. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL MovePrevious(): + IF reset THEN DO: + reset = FALSE. + RETURN MoveLast(). + END. + FIND PREV element NO-ERROR. + RETURN AVAILABLE(element). + END METHOD. + + /*---------------------------------------------------------------------------- + Return true is a list element with the given name is in the list. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL HasValue(INPUT name AS CHARACTER): + RETURN CAN-FIND(FIRST element WHERE element.name = name). + END METHOD. + +END CLASS. \ No newline at end of file From 36cfac5cc0fac4ce152873695659187218d37b24 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Thu, 30 Oct 2014 13:47:10 +0000 Subject: [PATCH 04/33] Add core DataProvider class, error class, and associated unit tests --- src/OEUnit/Data/DataProvider.cls | 141 +++++++++++++++++++++ src/OEUnit/Data/DataProviderError.cls | 18 +++ src/OEUnit/Tests/Data/AllTestSuite.cls | 12 ++ src/OEUnit/Tests/Data/DataProviderTest.cls | 137 ++++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 src/OEUnit/Data/DataProvider.cls create mode 100644 src/OEUnit/Data/DataProviderError.cls create mode 100644 src/OEUnit/Tests/Data/AllTestSuite.cls create mode 100644 src/OEUnit/Tests/Data/DataProviderTest.cls diff --git a/src/OEUnit/Data/DataProvider.cls b/src/OEUnit/Data/DataProvider.cls new file mode 100644 index 0000000..f897be9 --- /dev/null +++ b/src/OEUnit/Data/DataProvider.cls @@ -0,0 +1,141 @@ +/*------------------------------------------------------------------------------ + File : DataProvider.cls + Package : OEUnit.Data + Description : Stores and uses data provided in associated methods when + calling a test case so that one test case can be called + multiple times. +------------------------------------------------------------------------------*/ +USING Progress.Lang.*. +USING OEUnit.Reflection.*. +USING OEUnit.Data.*. + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +CLASS OEUnit.Data.DataProvider: + + DEFINE PROTECTED VARIABLE ttData AS HANDLE NO-UNDO. + DEFINE PROTECTED VARIABLE ttQuery AS HANDLE NO-UNDO. + + /*---------------------------------------------------------------------------- + Property that holds the current size of data + ----------------------------------------------------------------------------*/ + DEFINE PUBLIC PROPERTY Size AS INTEGER NO-UNDO GET. PRIVATE SET. + + CONSTRUCTOR PUBLIC DataProvider(): + SUPER(). + Size = 0. + END CONSTRUCTOR. + + DESTRUCTOR PUBLIC DataProvider(): + IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. + IF VALID-HANDLE(ttQuery) THEN + DO: + ttQuery:QUERY-CLOSE(). + DELETE OBJECT ttQuery. + END. + END DESTRUCTOR. + + METHOD PROTECTED VOID CountSize(): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + Size = 0. + ResetQuery(). + DO WHILE MoveNext() NE FALSE: + ASSIGN Size = Size + 1. + END. + ResetQuery(). + END. + + METHOD PUBLIC LOGICAL FromJSON(INPUT json AS LONGCHAR): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(ttQuery) THEN DELETE OBJECT ttQuery. + IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. + CREATE TEMP-TABLE ttData. + res = ttData:READ-JSON("LONGCHAR", json, "EMPTY"). + CountSize(). + RETURN res. + END METHOD. + + METHOD PUBLIC LOGICAL FromJSONFile(INPUT path AS CHARACTER): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(ttQuery) THEN DELETE OBJECT ttQuery. + IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. + CREATE TEMP-TABLE ttData. + res = ttData:READ-JSON("FILE", path, "EMPTY"). + CountSize(). + RETURN res. + END METHOD. + + METHOD PUBLIC Progress.Lang.ParameterList GetParameterList(): + DEFINE VARIABLE numParams AS INTEGER NO-UNDO. + DEFINE VARIABLE bufHandle AS HANDLE NO-UNDO. + DEFINE VARIABLE i AS INTEGER NO-UNDO. + DEFINE VARIABLE fieldHandle AS HANDLE NO-UNDO. + DEFINE VARIABLE params AS Progress.Lang.ParameterList NO-UNDO. + IF NOT VALID-HANDLE(ttData) THEN RETURN ERROR NEW DataProviderError("Data has not been loaded into DataProvider"). + IF NOT VALID-HANDLE(ttQuery) OR ttQuery:IS-OPEN = FALSE THEN ResetQuery(). + IF ttQuery:QUERY-OFF-END = FALSE THEN + DO: + bufHandle = ttQuery:GET-BUFFER-HANDLE(1). + IF NOT bufHandle:AVAILABLE THEN MoveFirst(). + numParams = bufHandle:NUM-FIELDS. + params = NEW Progress.Lang.ParameterList(numParams). + DO i = 1 TO numParams: + fieldHandle = bufHandle:BUFFER-FIELD(i). + params:SetParameter(i, fieldHandle:DATA-TYPE, "INPUT", fieldHandle:BUFFER-VALUE()). + END. + END. + RETURN params. + END METHOD. + + METHOD PROTECTED VOID ResetQuery(): + DEFINE VARIABLE qry AS CHARACTER NO-UNDO. + IF NOT VALID-HANDLE(ttData) THEN RETURN. + IF VALID-HANDLE(ttQuery) THEN + DO: + ttQuery:QUERY-CLOSE(). + DELETE OBJECT ttQuery. + END. + qry = "FOR EACH " + ttData:NAME. + CREATE QUERY ttQuery. + ttQuery:SET-BUFFERS(ttData:DEFAULT-BUFFER-HANDLE). + IF ttQuery:QUERY-PREPARE(qry) THEN ttQuery:QUERY-OPEN(). + ELSE IF VALID-HANDLE(ttQuery) THEN DELETE OBJECT ttQuery. + END METHOD. + + METHOD PUBLIC LOGICAL MoveFirst(): + DEFINE VARIABLE res AS LOGICAL NO-UNDO INITIAL FALSE. + IF NOT VALID-HANDLE(ttQuery) THEN + ResetQuery(). + IF VALID-HANDLE(ttQuery) THEN + res = ttQuery:GET-FIRST(NO-LOCK). + RETURN res. + END METHOD. + + METHOD PUBLIC LOGICAL MoveLast(): + DEFINE VARIABLE res AS LOGICAL NO-UNDO INITIAL FALSE. + IF NOT VALID-HANDLE(ttQuery) THEN + ResetQuery(). + IF VALID-HANDLE(ttQuery) THEN + res = ttQuery:GET-LAST(NO-LOCK). + RETURN res. + END METHOD. + + METHOD PUBLIC LOGICAL MoveNext(): + DEFINE VARIABLE res AS LOGICAL NO-UNDO INITIAL FALSE. + IF NOT VALID-HANDLE(ttQuery) THEN + ResetQuery(). + IF VALID-HANDLE(ttQuery) THEN + res = ttQuery:GET-NEXT(NO-LOCK). + RETURN res. + END METHOD. + + METHOD PUBLIC LOGICAL MovePrev(): + DEFINE VARIABLE res AS LOGICAL NO-UNDO INITIAL FALSE. + IF NOT VALID-HANDLE(ttQuery) THEN + ResetQuery(). + IF VALID-HANDLE(ttQuery) THEN + res = ttQuery:GET-PREV(NO-LOCK). + RETURN res. + END METHOD. + +END CLASS. \ No newline at end of file diff --git a/src/OEUnit/Data/DataProviderError.cls b/src/OEUnit/Data/DataProviderError.cls new file mode 100644 index 0000000..762ff99 --- /dev/null +++ b/src/OEUnit/Data/DataProviderError.cls @@ -0,0 +1,18 @@ +/*------------------------------------------------------------------------------ + File : DataProvider.cls + Package : OEUnit.Data + Description : The exception thrown when DataProvider setup is not complete. +------------------------------------------------------------------------------*/ + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +CLASS OEUnit.Data.DataProviderError INHERITS Progress.Lang.AppError: + + /*---------------------------------------------------------------------------- + Constructor. Accepts an error message. + ----------------------------------------------------------------------------*/ + CONSTRUCTOR PUBLIC DataProviderError(INPUT errorMessage AS CHARACTER): + SUPER(errorMessage, 0). + END CONSTRUCTOR. + +END CLASS. \ No newline at end of file diff --git a/src/OEUnit/Tests/Data/AllTestSuite.cls b/src/OEUnit/Tests/Data/AllTestSuite.cls new file mode 100644 index 0000000..8772bbf --- /dev/null +++ b/src/OEUnit/Tests/Data/AllTestSuite.cls @@ -0,0 +1,12 @@ +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +USING OEUnit.Runner.TestSuite. +USING OEUnit.Tests.Data.*. + +CLASS OEUnit.Tests.Data.AllTestSuite INHERITS TestSuite: + + CONSTRUCTOR AllTestSuite(): + AddTest(NEW DataProviderTest()). + END CONSTRUCTOR. + +END CLASS. \ No newline at end of file diff --git a/src/OEUnit/Tests/Data/DataProviderTest.cls b/src/OEUnit/Tests/Data/DataProviderTest.cls new file mode 100644 index 0000000..7beb53c --- /dev/null +++ b/src/OEUnit/Tests/Data/DataProviderTest.cls @@ -0,0 +1,137 @@ + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +USING Progress.Lang.*. +USING OEUnit.Tests.Data.*. +USING OEUnit.Assertion.Assert. +USING OEUnit.Data.DataProvider. + +CLASS OEUnit.Tests.Data.DataProviderTest: + + DEFINE VARIABLE dataProvider AS DataProvider NO-UNDO. + + @After. + METHOD PUBLIC VOID DeleteDataProvider(): + DELETE OBJECT dataProvider NO-ERROR. + END METHOD. + + @Test. + METHOD PUBLIC VOID FromJSON(): + dataProvider = NEW DataProvider(). + dataProvider:FromJSON("~{ ~"data~": [" + + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "]}"). + Assert:AreEqual(dataProvider:Size, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromJSON_Reset(): + dataProvider = NEW DataProvider(). + dataProvider:FromJSON("~{ ~"data~": [" + + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "]}"). + Assert:AreEqual(dataProvider:Size, 2). + dataProvider:FromJSON("~{ ~"data~": [" + + "~{ ~"ame~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "]}"). + Assert:AreEqual(dataProvider:Size, 4). + END METHOD. + + @Test. + METHOD PUBLIC VOID MoveFirst(): + dataProvider = NEW DataProvider(). + + /* Object not fully initialise, should return false */ + Assert:IsFalse(dataProvider:MoveFirst()). + + dataProvider:FromJSON("~{ ~"data~": [" + + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "]}"). + Assert:IsTrue(dataProvider:MoveFirst()). + END METHOD. + + @Test. + METHOD PUBLIC VOID MoveLast(): + dataProvider = NEW DataProvider(). + + /* Object not fully initialise, should return false */ + Assert:IsFalse(dataProvider:MoveLast()). + + dataProvider:FromJSON("~{ ~"data~": [" + + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "]}"). + Assert:IsTrue(dataProvider:MoveLast()). + END METHOD. + + @Test. + METHOD PUBLIC VOID MoveNext(): + dataProvider = NEW DataProvider(). + + /* Object not fully initialise, should return false */ + Assert:IsFalse(dataProvider:MoveNext()). + + + dataProvider:FromJSON("~{ ~"data~": [" + + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "]}"). + dataProvider:MoveLast(). + Assert:IsFalse(dataProvider:MoveNext()). + dataProvider:MoveFirst(). + Assert:IsTrue(dataProvider:MoveNext()). + END METHOD. + + @Test. + METHOD PUBLIC VOID MovePrev(): + dataProvider = NEW DataProvider(). + + /* Object not fully initialise, should return false */ + Assert:IsFalse(dataProvider:MovePrev()). + + + dataProvider:FromJSON("~{ ~"data~": [" + + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "]}"). + dataProvider:MoveFirst(). + Assert:IsFalse(dataProvider:MovePrev()). + dataProvider:MoveLast(). + Assert:IsTrue(dataProvider:MovePrev()). + END METHOD. + + @Test. + METHOD PUBLIC VOID GetParameterList(): + DEFINE VARIABLE params AS Progress.Lang.ParameterList NO-UNDO. + dataProvider = NEW DataProvider(). + dataProvider:FromJSON("~{ ~"data~": [" + + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "]}"). + params = dataProvider:GetParameterList(). + Assert:IsNotNull(params). + Assert:AreEqual(params:NumParameters, 4). + DELETE OBJECT params. + dataProvider:MoveNext(). + params = dataProvider:GetParameterList(). + Assert:IsNotNull(params). + Assert:AreEqual(params:NumParameters, 4). + DELETE OBJECT params. + dataProvider:MoveNext(). + params = dataProvider:GetParameterList(). + Assert:IsNull(params). + END METHOD. + + @Test(expected="OEUnit.Data.DataProviderError"). + METHOD PUBLIC VOID GetParameterList_NotInitialised(): + dataProvider = NEW DataProvider(). + dataProvider:GetParameterList(). + END METHOD. + +END CLASS. \ No newline at end of file From d733cbb5df082266823f460a427845ecc586359f Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Thu, 30 Oct 2014 13:49:23 +0000 Subject: [PATCH 05/33] Ensure new Data directory is included when all unit tests are run. --- src/OEUnit/Tests/AllTestSuite.cls | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OEUnit/Tests/AllTestSuite.cls b/src/OEUnit/Tests/AllTestSuite.cls index 789da08..3ea21c6 100644 --- a/src/OEUnit/Tests/AllTestSuite.cls +++ b/src/OEUnit/Tests/AllTestSuite.cls @@ -7,6 +7,7 @@ CLASS OEUnit.Tests.AllTestSuite INHERITS TestSuite: CONSTRUCTOR AllTestSuite(): AddTest(NEW OEUnit.Tests.Assertion.AllTestSuite()). + AddTest(NEW OEUnit.Tests.Data.AllTestSuite()). AddTest(NEW OEUnit.Tests.Reflection.AllTestSuite()). AddTest(NEW OEUnit.Tests.Runner.AllTestSuite()). AddTest(NEW OEUnit.Tests.Runners.AllTestSuite()). From 469cb2c46ca4e10e2dfa2daabdee38b5d908c6dc Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Thu, 30 Oct 2014 14:00:47 +0000 Subject: [PATCH 06/33] Define new annotation types, and attribute types --- src/OEUnit/Runners/OEUnitAnnotations.cls | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/OEUnit/Runners/OEUnitAnnotations.cls b/src/OEUnit/Runners/OEUnitAnnotations.cls index 699e3de..2aaa0e5 100644 --- a/src/OEUnit/Runners/OEUnitAnnotations.cls +++ b/src/OEUnit/Runners/OEUnitAnnotations.cls @@ -11,16 +11,19 @@ CLASS OEUnit.Runners.OEUnitAnnotations: /*---------------------------------------------------------------------------- OEUnit Annotation Types - Read Only Properties ----------------------------------------------------------------------------*/ - DEFINE PUBLIC STATIC PROPERTY Test AS CHARACTER NO-UNDO INIT "Test" GET. - DEFINE PUBLIC STATIC PROPERTY Ignore AS CHARACTER NO-UNDO INIT "Ignore" GET. - DEFINE PUBLIC STATIC PROPERTY Before AS CHARACTER NO-UNDO INIT "Before" GET. - DEFINE PUBLIC STATIC PROPERTY After AS CHARACTER NO-UNDO INIT "After" GET. - DEFINE PUBLIC STATIC PROPERTY BeforeClass AS CHARACTER NO-UNDO INIT "BeforeClass" GET. - DEFINE PUBLIC STATIC PROPERTY AfterClass AS CHARACTER NO-UNDO INIT "AfterClass" GET. + DEFINE PUBLIC STATIC PROPERTY Test AS CHARACTER NO-UNDO INIT "Test" GET. + DEFINE PUBLIC STATIC PROPERTY Ignore AS CHARACTER NO-UNDO INIT "Ignore" GET. + DEFINE PUBLIC STATIC PROPERTY Before AS CHARACTER NO-UNDO INIT "Before" GET. + DEFINE PUBLIC STATIC PROPERTY After AS CHARACTER NO-UNDO INIT "After" GET. + DEFINE PUBLIC STATIC PROPERTY BeforeClass AS CHARACTER NO-UNDO INIT "BeforeClass" GET. + DEFINE PUBLIC STATIC PROPERTY AfterClass AS CHARACTER NO-UNDO INIT "AfterClass" GET. + DEFINE PUBLIC STATIC PROPERTY DataProvider AS CHARACTER NO-UNDO INIT "DataProvider" GET. /*---------------------------------------------------------------------------- Expected Attribute for the Test Annotation. ----------------------------------------------------------------------------*/ - DEFINE PUBLIC STATIC PROPERTY TestExpectedAttribute AS CHARACTER NO-UNDO INIT "Expected" GET. + DEFINE PUBLIC STATIC PROPERTY TestExpectedAttribute AS CHARACTER NO-UNDO INIT "Expected" GET. + DEFINE PUBLIC STATIC PROPERTY TestDataProviderAttribute AS CHARACTER NO-UNDO INIT "DataProvider" GET. + DEFINE PUBLIC STATIC PROPERTY DataProviderNameAttribute AS CHARACTER NO-UNDO INIT "Name" GET. END CLASS. \ No newline at end of file From 56949acc6619ea570459fd6453de72bbf40ef518 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Mon, 3 Nov 2014 14:18:44 +0000 Subject: [PATCH 07/33] Allow multiple attributes to be defined inside of one annotation --- src/OEUnit/Reflection/AnnotationInfo.cls | 48 +++++++++++++++++++ .../Tests/Reflection/AnnotationInfoTest.cls | 33 ++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/OEUnit/Reflection/AnnotationInfo.cls b/src/OEUnit/Reflection/AnnotationInfo.cls index dc46771..d296537 100644 --- a/src/OEUnit/Reflection/AnnotationInfo.cls +++ b/src/OEUnit/Reflection/AnnotationInfo.cls @@ -10,6 +10,8 @@ ROUTINE-LEVEL ON ERROR UNDO, THROW. +USING OEUnit.Util.NamedList. + CLASS OEUnit.Reflection.AnnotationInfo: /*---------------------------------------------------------------------------- @@ -20,10 +22,19 @@ CLASS OEUnit.Reflection.AnnotationInfo: DEFINE PUBLIC PROPERTY AttributeName AS CHARACTER NO-UNDO GET. PRIVATE SET. DEFINE PUBLIC PROPERTY AttributeValue AS CHARACTER NO-UNDO GET. PRIVATE SET. + /*---------------------------------------------------------------------------- + Annotation attributes. Defined by the syntax below: + AnnotationType(AttributeName=AttributeValue,AttributeName=AttributeValue) + ----------------------------------------------------------------------------*/ + DEFINE PUBLIC PROPERTY Attributes AS NamedList NO-UNDO + GET. + PROTECTED SET. + /*---------------------------------------------------------------------------- Constructor. Accepts the annotation string. Some input examples: Test Test(expected=Progress.Lang.Error) + Test(expected=Progress.Lang.Error,dataProvider=GenerateTestMatrix) Ignore ----------------------------------------------------------------------------*/ CONSTRUCTOR PUBLIC AnnotationInfo(INPUT annotationString AS CHARACTER): @@ -34,6 +45,43 @@ CLASS OEUnit.Reflection.AnnotationInfo: attribute = TRIM(SUBSTRING(annotationString, LENGTH(AnnotationType) + 1),"()") AttributeName = ENTRY(1, attribute, "=") AttributeValue = SUBSTRING(attribute, LENGTH(AttributeName) + 2). + + Attributes = NEW NamedList(). + IF attribute NE "" AND attribute NE ? THEN ParseAttributes(attribute). END CONSTRUCTOR. + + DESTRUCTOR AnnotationInfo(): + DELETE OBJECT Attributes NO-ERROR. + END DESTRUCTOR. + + METHOD PROTECTED VOID ParseAttributes(INPUT attribs AS CHARACTER): + + DEFINE VARIABLE startPos AS INTEGER NO-UNDO INITIAL 1. + DEFINE VARIABLE endPos AS INTEGER NO-UNDO. + DEFINE VARIABLE attribName AS CHARACTER NO-UNDO. + DEFINE VARIABLE attribValue AS CHARACTER NO-UNDO. + + attribLoop: + DO WHILE startPos < LENGTH(attribs): + endPos = INDEX(attribs,"=", startPos). + IF(endPos = 0) THEN LEAVE attribLoop. + attribName = TRIM(SUBSTRING(attribs, startPos, endPos - startPos)). + startPos = endPos + 1. + endPos = INDEX(attribs, ",", startPos). + IF(endPos = 0) THEN endPos = LENGTH(attribs) + 1. + attribValue = TRIM(SUBSTRING(attribs, startPos, endPos - startPos)). + startPos = endPos + 1. + Attributes:Add(attribName, attribValue). + END. + END METHOD. + + METHOD PUBLIC LOGICAL HasAttribute(INPUT attribName AS CHARACTER): + RETURN Attributes:HasValue(INPUT attribName). + END METHOD. + + METHOD PUBLIC CHARACTER GetAttribute(INPUT attribName AS CHARACTER): + IF HasAttribute(attribName) = TRUE THEN RETURN Attributes:Get(attribName). + ELSE RETURN ?. + END METHOD. END CLASS. \ No newline at end of file diff --git a/src/OEUnit/Tests/Reflection/AnnotationInfoTest.cls b/src/OEUnit/Tests/Reflection/AnnotationInfoTest.cls index 33aa147..cb49fe5 100644 --- a/src/OEUnit/Tests/Reflection/AnnotationInfoTest.cls +++ b/src/OEUnit/Tests/Reflection/AnnotationInfoTest.cls @@ -26,6 +26,9 @@ CLASS OEUnit.Tests.Reflection.AnnotationInfoTest: Assert:AreEqual(annotation:AnnotationType, "Annotation"). Assert:AreEqual(annotation:AttributeName, "Attribute"). Assert:AreEqual(annotation:AttributeValue, "Value"). + Assert:AreEqual(annotation:Attributes:Size, 1). + Assert:IsTrue(annotation:HasAttribute("Attribute")). + Assert:AreEqual(annotation:GetAttribute("Attribute"), "Value"). END METHOD. @Test. @@ -34,6 +37,34 @@ CLASS OEUnit.Tests.Reflection.AnnotationInfoTest: Assert:AreEqual(annotation:AnnotationType, "Annotation"). Assert:AreEqual(annotation:AttributeName, "a"). Assert:AreEqual(annotation:AttributeValue, "5+1=6"). - END METHOD. + Assert:AreEqual(annotation:Attributes:Size, 1). + Assert:IsTrue(annotation:HasAttribute("a")). + Assert:AreEqual(annotation:GetAttribute("a"), "5+1=6"). + END METHOD. + + @Test. + METHOD PUBLIC VOID ParseAnnotationMultipleAttributes(): + annotation = NEW AnnotationInfo("Annotation(Attribute1=Value1,Attribute2=Value2,Attribute3=Value3)"). + Assert:AreEqual(annotation:Attributes:Size, 3). + Assert:IsTrue(annotation:HasAttribute("Attribute1")). + Assert:IsTrue(annotation:HasAttribute("Attribute2")). + Assert:IsTrue(annotation:HasAttribute("Attribute3")). + END METHOD. + + @Test. + METHOD PUBLIC VOID AnnotationHasAttribute(): + annotation = NEW AnnotationInfo("Annotation(Attribute=Value)"). + Assert:IsTrue(annotation:HasAttribute("Attribute")). + Assert:IsFalse(annotation:HasAttribute("DoesNotExist")). + END METHOD. + + @Test. + METHOD PUBLIC VOID AnnotationGetAttribute(): + annotation = NEW AnnotationInfo("Annotation(Attribute1=Value1,Attribute2=Value2,Attribute3=Value3)"). + Assert:AreEqual(annotation:GetAttribute("Attribute1"), "Value1"). + Assert:AreEqual(annotation:GetAttribute("Attribute2"), "Value2"). + Assert:AreEqual(annotation:GetAttribute("Attribute3"), "Value3"). + Assert:IsNull(annotation:GetAttribute("Attribute4")). + END METHOD. END CLASS. \ No newline at end of file From 25c29a900c2922e943fabe92df1a7e3116bc4830 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Tue, 4 Nov 2014 08:49:21 +0000 Subject: [PATCH 08/33] Remove definitions of, and references to, AnnotationInfo:AttributeName and AnnotationInfo:AttributeValue. Replace with calls to AnnotationInfo:HasAttribute and AnnotationInfo:GetAttribute --- src/OEUnit/Reflection/AnnotationInfo.cls | 4 ---- src/OEUnit/Runners/OEUnitRunner.cls | 8 ++++---- src/OEUnit/Tests/Reflection/AnnotationInfoTest.cls | 7 +------ 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/OEUnit/Reflection/AnnotationInfo.cls b/src/OEUnit/Reflection/AnnotationInfo.cls index d296537..c1b4505 100644 --- a/src/OEUnit/Reflection/AnnotationInfo.cls +++ b/src/OEUnit/Reflection/AnnotationInfo.cls @@ -19,8 +19,6 @@ CLASS OEUnit.Reflection.AnnotationInfo: AnnotationType(AttributeName=AttributeValue) ----------------------------------------------------------------------------*/ DEFINE PUBLIC PROPERTY AnnotationType AS CHARACTER NO-UNDO GET. PRIVATE SET. - DEFINE PUBLIC PROPERTY AttributeName AS CHARACTER NO-UNDO GET. PRIVATE SET. - DEFINE PUBLIC PROPERTY AttributeValue AS CHARACTER NO-UNDO GET. PRIVATE SET. /*---------------------------------------------------------------------------- Annotation attributes. Defined by the syntax below: @@ -43,8 +41,6 @@ CLASS OEUnit.Reflection.AnnotationInfo: ASSIGN AnnotationType = ENTRY(1, annotationString, "(") attribute = TRIM(SUBSTRING(annotationString, LENGTH(AnnotationType) + 1),"()") - AttributeName = ENTRY(1, attribute, "=") - AttributeValue = SUBSTRING(attribute, LENGTH(AttributeName) + 2). Attributes = NEW NamedList(). IF attribute NE "" AND attribute NE ? THEN ParseAttributes(attribute). diff --git a/src/OEUnit/Runners/OEUnitRunner.cls b/src/OEUnit/Runners/OEUnitRunner.cls index bd0fa08..ea3d548 100644 --- a/src/OEUnit/Runners/OEUnitRunner.cls +++ b/src/OEUnit/Runners/OEUnitRunner.cls @@ -208,16 +208,16 @@ CLASS OEUnit.Runners.OEUnitRunner INHERITS BaseRunner: testAnnotation = testMethod:GetAnnotationOfType(OEUnitAnnotations:Test). testMethod:Invoke(). - IF testAnnotation:AttributeName = OEUnitAnnotations:TestExpectedAttribute THEN - RETURN ERROR NEW AssertionFailedError("Expecting error: " + testAnnotation:AttributeValue). + IF testAnnotation:HasAttribute(OEUnitAnnotations:TestExpectedAttribute) THEN + RETURN ERROR NEW AssertionFailedError("Expecting error: " + testAnnotation:GetAttribute(OEUnitAnnotations:TestExpectedAttribute)). CATCH assertionFailed AS AssertionFailedError: RETURN ERROR assertionFailed. END CATCH. CATCH err AS Progress.Lang.Error: - IF testAnnotation:AttributeName = OEUnitAnnotations:TestExpectedAttribute THEN DO: - IF IsTypeOf(err, GetExpectedErrorType(testAnnotation:AttributeValue)) THEN DO: + IF testAnnotation:HasAttribute(OEUnitAnnotations:TestExpectedAttribute) THEN DO: + IF IsTypeOf(err, GetExpectedErrorType(testAnnotation:GetAttribute(OEUnitAnnotations:TestExpectedAttribute))) THEN DO: DELETE OBJECT err NO-ERROR. END. ELSE diff --git a/src/OEUnit/Tests/Reflection/AnnotationInfoTest.cls b/src/OEUnit/Tests/Reflection/AnnotationInfoTest.cls index cb49fe5..437f788 100644 --- a/src/OEUnit/Tests/Reflection/AnnotationInfoTest.cls +++ b/src/OEUnit/Tests/Reflection/AnnotationInfoTest.cls @@ -16,16 +16,13 @@ CLASS OEUnit.Tests.Reflection.AnnotationInfoTest: METHOD PUBLIC VOID ParseAnnotationNoAttribute(): annotation = NEW AnnotationInfo("Annotation"). Assert:AreEqual(annotation:AnnotationType, "Annotation"). - Assert:AreEqual(annotation:AttributeName, ""). - Assert:AreEqual(annotation:AttributeValue, ""). + Assert:AreEqual(annotation:Attributes:Size, 0). END METHOD. @Test. METHOD PUBLIC VOID ParseAnnotationWithAttribute(): annotation = NEW AnnotationInfo("Annotation(Attribute=Value)"). Assert:AreEqual(annotation:AnnotationType, "Annotation"). - Assert:AreEqual(annotation:AttributeName, "Attribute"). - Assert:AreEqual(annotation:AttributeValue, "Value"). Assert:AreEqual(annotation:Attributes:Size, 1). Assert:IsTrue(annotation:HasAttribute("Attribute")). Assert:AreEqual(annotation:GetAttribute("Attribute"), "Value"). @@ -35,8 +32,6 @@ CLASS OEUnit.Tests.Reflection.AnnotationInfoTest: METHOD PUBLIC VOID ParseAnnotationComplexAttribute(): annotation = NEW AnnotationInfo("Annotation(a=5+1=6)"). Assert:AreEqual(annotation:AnnotationType, "Annotation"). - Assert:AreEqual(annotation:AttributeName, "a"). - Assert:AreEqual(annotation:AttributeValue, "5+1=6"). Assert:AreEqual(annotation:Attributes:Size, 1). Assert:IsTrue(annotation:HasAttribute("a")). Assert:AreEqual(annotation:GetAttribute("a"), "5+1=6"). From 4d8ec2574f2116cdc1fac5b4b40bf5c03ea3c0bf Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Tue, 4 Nov 2014 08:54:09 +0000 Subject: [PATCH 09/33] Add methods to MethodInfo to Invoke a method with a ParameterList object, and to interact with a method's DataProvider object. --- src/OEUnit/Reflection/MethodInfo.cls | 103 +++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/OEUnit/Reflection/MethodInfo.cls b/src/OEUnit/Reflection/MethodInfo.cls index 92461cf..f109b86 100644 --- a/src/OEUnit/Reflection/MethodInfo.cls +++ b/src/OEUnit/Reflection/MethodInfo.cls @@ -9,6 +9,8 @@ ROUTINE-LEVEL ON ERROR UNDO, THROW. USING OEUnit.Reflection.*. USING OEUnit.Util.*. +USING OEUnit.Runners.*. +USING OEUnit.Data.*. CLASS OEUnit.Reflection.MethodInfo INHERITS StatementInfo: @@ -59,5 +61,106 @@ CLASS OEUnit.Reflection.MethodInfo INHERITS StatementInfo: END METHOD. + /*---------------------------------------------------------------------------- + Invoke the method being represented, with a parameter list. The method being + called must be a public method accepting the same parameters as are listed + in params. A StopConditionError will be thrown if the method cannot be found. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC VOID Invoke(INPUT params AS Progress.Lang.ParameterList): + DEFINE VARIABLE classInf AS Progress.Lang.Class NO-UNDO. + DO ON ERROR UNDO, THROW + ON QUIT UNDO, RETURN ERROR NEW QuitConditionError("Quit condition occured") + ON STOP UNDO, LEAVE: + classInf = Progress.Lang.Class:GetClass(parentInfo:Name). + IF IsStatic THEN + classInf:Invoke(Name, params). + ELSE + classInf:Invoke(parentInfo:ClassInstance, Name, params). + + RETURN. + END. + + /* HACK: To accomodate bug in OpenEdge runtime, crashes when returning custom + error instances on stop conditions */ + RETURN ERROR NEW StopConditionError("Stop condition occured"). + END METHOD. + + /*---------------------------------------------------------------------------- + Returns another MethodInfo object which holds the information regarding the + data provider method for this MethodInfo. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC MethodInfo GetDataProviderInfo(): + + DEFINE VARIABLE annotation AS AnnotationInfo NO-UNDO. + DEFINE VARIABLE dataProviderAnnotation AS AnnotationInfo NO-UNDO. + DEFINE VARIABLE dataProviders AS List NO-UNDO. + DEFINE VARIABLE dataProviderName AS CHARACTER NO-UNDO. + DEFINE VARIABLE dataProvider AS MethodInfo NO-UNDO. + DEFINE VARIABLE result AS LOGICAL NO-UNDO INITIAL FALSE. + + /* If this is a @Test, with a "DataProvider=" attribute, then attempt to + * find the data provider method + */ + annotation = GetAnnotationOfType(OEUnitAnnotations:Test). + + IF annotation NE ? AND annotation:HasAttribute("dataProvider") THEN + DO: + dataProviderName = annotation:Attributes:Get(OEUnitAnnotations:TestDataProviderAttribute). + dataProviders = parentInfo:GetAnnotatedMethods(OEUnitAnnotations:DataProvider). + + /* Find first data provider with that name attribute or method name */ + dataProviders:MoveFirst(). + dataProviderLoop: + DO WHILE dataProviders:CURRENT NE ?: + dataProvider = CAST(dataProviders:CURRENT,"MethodInfo"). + dataProviderAnnotation = dataProvider:GetAnnotationOfType(OEUnitAnnotations:DataProvider). + IF (dataProviderAnnotation:HasAttribute("name") = TRUE) THEN + DO: + IF dataProviderName = dataProviderAnnotation:Attributes:Get(OEUnitAnnotations:DataProviderNameAttribute) THEN + LEAVE dataProviderLoop. + END. + ELSE IF dataProvider:Name = dataProviderName THEN LEAVE dataProviderLoop. + ELSE dataProvider = ?. + dataProviders:MoveNext(). + END. + END. + + RETURN dataProvider. + END METHOD. + + /*---------------------------------------------------------------------------- + Determines whether this method has a @Test annotation with a DataProvider + attribute, and a method with a matching @DataProvider attribute exists. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL RequiresDataProvider(): + RETURN (GetDataProviderInfo() NE ?). + END METHOD. + + /*---------------------------------------------------------------------------- + Returns a DataProvider object from the invocation of a DataProvider method. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC DataProvider GetDataProvider(): + DEFINE VARIABLE dataProvMethod AS MethodInfo NO-UNDO. + DEFINE VARIABLE dataProvider AS DataProvider NO-UNDO. + DO ON ERROR UNDO, THROW + ON QUIT UNDO, RETURN ERROR NEW QuitConditionError("Quit condition occured") + ON STOP UNDO, LEAVE: + dataProvMethod = GetDataProviderInfo(). + IF dataProvMethod NE ? AND VALID-OBJECT(dataProvMethod) THEN + DO: + IF dataProvMethod:IsStatic THEN + dataProvider = DYNAMIC-INVOKE(dataProvMethod:ParentInfo:Name, dataProvMethod:Name). + ELSE + dataProvider = DYNAMIC-INVOKE(dataProvMethod:ParentInfo:ClassInstance, dataProvMethod:Name). + END. + + RETURN dataProvider. + END. + + /* HACK: To accomodate bug in OpenEdge runtime, crashes when returning custom + error instances on stop conditions */ + RETURN ERROR NEW StopConditionError("Stop condition occured"). + END METHOD. + END CLASS. From 9265be3d2707ff273a4ba8cd2ff2805231d48f3d Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Tue, 4 Nov 2014 13:38:20 +0000 Subject: [PATCH 10/33] Change OEUnitRunner to recognise test methods which require a DataProvider, and to invoke the test method correctly. --- src/OEUnit/Runners/OEUnitRunner.cls | 57 +++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/src/OEUnit/Runners/OEUnitRunner.cls b/src/OEUnit/Runners/OEUnitRunner.cls index ea3d548..e7daf4b 100644 --- a/src/OEUnit/Runners/OEUnitRunner.cls +++ b/src/OEUnit/Runners/OEUnitRunner.cls @@ -17,6 +17,7 @@ USING OEUnit.Reflection.*. USING OEUnit.Runner.*. USING OEUnit.Runners.OEUnitAnnotations. USING OEUnit.Util.*. +USING OEUnit.Data.*. USING Progress.Lang.*. CLASS OEUnit.Runners.OEUnitRunner INHERITS BaseRunner: @@ -158,20 +159,56 @@ CLASS OEUnit.Runners.OEUnitRunner INHERITS BaseRunner: Run all of the test methods in the given list. ----------------------------------------------------------------------------*/ METHOD PROTECTED VOID RunTestMethods(INPUT testMethods AS List): + DEFINE VARIABLE meth AS MethodInfo NO-UNDO. testMethods:Reset(). DO WHILE testMethods:MoveNext(): - RunTestMethod(CAST(testMethods:Current, MethodInfo)). + meth = CAST(testMethods:Current, MethodInfo). + IF meth:RequiresDataProvider() THEN + RunTestMethodWithDataProvider(meth). + ELSE + RunTestMethod(meth). END. FINALLY: DELETE OBJECT testMethods NO-ERROR. END FINALLY. END METHOD. + + /*---------------------------------------------------------------------------- + Run a single test method multiple times using the given DataProvider. + ----------------------------------------------------------------------------*/ + METHOD PROTECTED VOID RunTestMethodWithDataProvider(INPUT testMethod AS MethodInfo): + + DEFINE VARIABLE dataProvider AS DataProvider NO-UNDO. + DEFINE VARIABLE moveResult AS LOGICAL NO-UNDO. + DEFINE VARIABLE counter AS INTEGER NO-UNDO INITIAL 0. + DEFINE VARIABLE methodResult AS TestMethodResult NO-UNDO. + DEFINE VARIABLE methodName AS CHARACTER NO-UNDO. + dataProvider = testMethod:GetDataProvider(). + IF NOT VALID-OBJECT(dataProvider) OR dataProvider = ? THEN + RETURN ERROR NEW DataProviderError("Invalid DataProvider object returned from method."). + methodName = testMethod:NAME. + moveResult = dataProvider:MoveFirst(). + DO WHILE moveResult EQ TRUE: + counter = counter + 1. + RunTestMethod(testMethod,dataProvider:GetParameterList()). + moveResult = dataProvider:MoveNext(). + END. + END METHOD. /*---------------------------------------------------------------------------- Run a single test method and store it's result. Any Progress.Lang.Errors thrown during the run are caught and stored in the result. ----------------------------------------------------------------------------*/ METHOD PROTECTED VOID RunTestMethod(INPUT testMethod AS MethodInfo): + RunTestMethod(INPUT testMethod, INPUT ?). + END METHOD. + + /*---------------------------------------------------------------------------- + Run a single test method with the given parameters and store it's result. Any + Progress.Lang.Errors thrown during the run are caught and stored in the + result. + ----------------------------------------------------------------------------*/ + METHOD PROTECTED VOID RunTestMethod(INPUT testMethod AS MethodInfo, INPUT paramList AS Progress.Lang.ParameterList): DEFINE VARIABLE methodResult AS TestMethodResult NO-UNDO. methodResult = NEW TestMethodResult(testMethod). @@ -181,7 +218,7 @@ CLASS OEUnit.Runners.OEUnitRunner INHERITS BaseRunner: ETIME(TRUE). RunBefores(currentInfo:GetAnnotatedMethods(OEUnitAnnotations:Before)). ETIME(TRUE). - CallTestMethod(testMethod). + CallTestMethod(testMethod,paramList). methodResult:SetStatus(TestResult:StatusPassed). CATCH err AS Progress.Lang.Error : methodResult:AddError(err). @@ -203,11 +240,23 @@ CLASS OEUnit.Runners.OEUnitRunner INHERITS BaseRunner: during the test, the error is re-thrown to the caller. ----------------------------------------------------------------------------*/ METHOD PROTECTED VOID CallTestMethod(INPUT testMethod AS MethodInfo): + CallTestMethod(testMethod, ?). + END METHOD. + + /*---------------------------------------------------------------------------- + Invoke the given test method with the given parameter list. If an unexpected + Progress.Lang.Error is thrown during the test, the error is re-thrown to the + caller. + ----------------------------------------------------------------------------*/ + METHOD PROTECTED VOID CallTestMethod(INPUT testMethod AS MethodInfo, INPUT paramList AS Progress.Lang.ParameterList): DEFINE VARIABLE testAnnotation AS AnnotationInfo NO-UNDO. - testAnnotation = testMethod:GetAnnotationOfType(OEUnitAnnotations:Test). - testMethod:Invoke(). + testAnnotation = testMethod:GetAnnotationOfType(OEUnitAnnotations:Test). + IF paramList NE ? AND VALID-OBJECT(paramList) THEN + testMethod:Invoke(paramList). + ELSE + testMethod:Invoke(). IF testAnnotation:HasAttribute(OEUnitAnnotations:TestExpectedAttribute) THEN RETURN ERROR NEW AssertionFailedError("Expecting error: " + testAnnotation:GetAttribute(OEUnitAnnotations:TestExpectedAttribute)). From 0d30ab1065d31da7ce5ef5b0ad5e7393d7c02e35 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Wed, 5 Nov 2014 08:51:56 +0000 Subject: [PATCH 11/33] Add documentation for DataProviders --- doc/changelog.html | 1 + doc/dataprovider.html | 175 ++++++++++++++++++++++++++++++++++++++++ doc/index.html | 1 + doc/installation.html | 1 + doc/reportingtests.html | 1 + doc/runningtests.html | 1 + doc/testcase.html | 14 +++- doc/testsuite.html | 1 + 8 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 doc/dataprovider.html diff --git a/doc/changelog.html b/doc/changelog.html index 70d41bc..8904116 100644 --- a/doc/changelog.html +++ b/doc/changelog.html @@ -16,6 +16,7 @@

OEUnit - Unit Testing Framework

  • Writing a Test Suite
  • Running a Test
  • Reporting Test Results
  • +
  • DataProviders
  • License
  • Change Log
  • diff --git a/doc/dataprovider.html b/doc/dataprovider.html new file mode 100644 index 0000000..3621c2c --- /dev/null +++ b/doc/dataprovider.html @@ -0,0 +1,175 @@ + + + + + OEUnit - DataProviders + + + + + + + +

    + DataProviders +

    +

    What is a DataProvider?

    +

    + A DataProvider is a class method inside of a test case, which provides data which is passed + to individual test methods as method parameters.
    +
    + A test method declares that is requires a DataProvider when it is defined, using the dataProvider + attribute, supplying the name of a DataProvider method as the attribute value.
    +
    + A class method is defined with the @DataProvider annotation, with an optional + name attribute. This method returns an object of type OEUnit.Data.DataProvider which + contains the data that will be used to repeatedly invoke the test method. +

    +

    How to use a DataProvider

    +

    + 1. Define a test method, with INPUT parameters for each test variable.
    + Use the dataProvider attribute to specify the name of a class method which will provide data + for the test variables.
    + For example:

    +
     ROUTINE-LEVEL ON ERROR UNDO, THROW.
    +
    + USING OEUnit.Assertion.Assert.
    + USING OEUnit.Data.DataProvider.
    +
    + CLASS SimpleTest:
    +   
    +   @Test (dataProvider=StatusChangeProvider). 
    +   METHOD PUBLIC VOID AcceptStatusChange(INPUT varStatus AS CHARACTER, INPUT varAccepted AS LOGICAL): 
    +     DEFINE VARIABLE result AS LOGICAL NO-UNDO.
    +     result = Order:ChangeStatus(INPUT varStatus). 
    +     Assert:AreEqual(result,varAccepted). 
    +   END METHOD.    
    +
    + END CLASS.
    +

    +
    + 2. Add a method to the class which returns a DataProvider object.
    + Use the @DataProvider annotation to indicate that the class is a DataProvider method.
    + For example:

    +
       @DataProvider. 
    +   METHOD PUBLIC DataProvider StatusChangeProvider(): 
    +     DEFINE VARIABLE dataProvider AS DataProvider NO-UNDO.
    +     dataProvider = NEW DataProvider().
    +     dataProvider:FromJSON("~{ ~"data~": ["
    +                            + "~{ ~"status~": ~"NEW~", ~"accepted~": true},"
    +                            + "~{ ~"status~": ~"ACCEPTED~", ~"accepted": true},"
    +                            + "~{ ~"status~": ~"PICKING~", ~"accepted": true},"
    +                            + "~{ ~"status~": ~"POSTED~", ~"accepted": false},"
    +                            + "~{ ~"status~": ~"DELIVERED~", ~"accepted": false},"
    +                            + "~{ ~"status~": ~"CANCELLED~", ~"accepted": true},"
    +                            + "]}").
    +     RETURN dataProvider.
    +   END METHOD.

    + +
    + Important Notes:

    +
      +
    • The name of the DataProvider class method must match the value of the dataProvider + attribute on the test method, or the @DataProvider annotation must + have a name attribute which matches the value of the dataProvider + attribute on the test method.
    • +
    • Execution of a DataProvider method will stop when an assertion fails or a Progress.Lang.Error + is thrown.
    • +
    • There are no special naming requirements for DataProvider methods.
    • +
    • DataProvider methods must be PUBLIC
    • +
    • DataProvider methods must accept no parameters.
    • +
    • DataProvider methods can be STATIC.
    • +
    • DataProvider methods can be used by more than one test method.
    • +
    • Any @Before methods are run before each test method invocation.
    • +
    • Any @After methods are run after each test method invocation.
    • +
    +

    +
    + 3. Run the test case as per normal.

    +

    +
    + 4. In the test case results, the test method will be listed multiple times with a separate status per invocation.

    + +

    Name Attribute

    +

    + Each method annotated with @DataProvider can specify a name attribute which is used + when searching for a DataProvider method, instead of the method name. +

    +

    + Syntax:

    +

    +

       @DataProvider[(name="DataProviderName")].

    +

    + DataProviderName
    +     The Name of the DataProvider. This name can then be specified by + a test method as its DataProvider, in the dataProvider attribute
    +

    +

    + +
    + Example:
    +

    +
       @Test (dataProvider=StatusChangeProvider). 
    +   METHOD PUBLIC VOID AcceptStatusChange(INPUT varStatus AS CHARACTER, INPUT varAccepted AS LOGICAL): 
    +     DEFINE VARIABLE result AS LOGICAL NO-UNDO.
    +     result = Order:ChangeStatus(INPUT varStatus). 
    +     Assert:AreEqual(result,varAccepted). 
    +   END METHOD.
    +   
    +      @DataProvider(name=StatusChangeProvider). 
    +   METHOD PUBLIC DataProvider myDataProvider(): 
    +     DEFINE VARIABLE dataProvider AS DataProvider NO-UNDO.
    +     dataProvider = NEW DataProvider().
    +     dataProvider:FromJSON("~{ ~"data~": ["
    +                            + "~{ ~"status~": ~"NEW~", ~"accepted~": true},"
    +                            + "~{ ~"status~": ~"ACCEPTED~", ~"accepted": true},"
    +                            + "~{ ~"status~": ~"PICKING~", ~"accepted": true},"
    +                            + "~{ ~"status~": ~"POSTED~", ~"accepted": false},"
    +                            + "~{ ~"status~": ~"DELIVERED~", ~"accepted": false},"
    +                            + "~{ ~"status~": ~"CANCELLED~", ~"accepted": true},"
    +                            + "]}").
    +     RETURN dataProvider.
    +   END METHOD.
    +

    DataProvider Methods

    +

    The DataProvider class provides a range of methods for loading data into the DataProvider.

    +

    METHOD PUBLIC LOGICAL FromJSON(INPUT json AS LONGCHAR)

    +

    This method is used to load data from JSON text stored in a LONGCHAR.

    +

    + +
    + Notes:

    +
      +
    • The structure of the JSON data should match that which is accepted by an OpenEdge DATASET + or TEMP-TABLE when using the READ-JSON method.
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    +

    METHOD PUBLIC LOGICAL FromJSONFile(INPUT path AS CHARACTER):

    +

    This method is used to load data from JSON text stored in a file. The file path should be provided as the + INPUT parameter.

    +

    + +
    + Notes:

    +
      +
    • The structure of the JSON data in the file should match that which is accepted by an OpenEdge + DATASET or TEMP-TABLE when using the + READ-JSON method.
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    + + + diff --git a/doc/index.html b/doc/index.html index 846a450..e9b274f 100644 --- a/doc/index.html +++ b/doc/index.html @@ -16,6 +16,7 @@

    OEUnit - Unit Testing Framework

  • Writing a Test Suite
  • Running a Test
  • Reporting Test Results
  • +
  • DataProviders
  • License
  • Change Log
  • diff --git a/doc/installation.html b/doc/installation.html index efce2b5..7e64c7c 100644 --- a/doc/installation.html +++ b/doc/installation.html @@ -16,6 +16,7 @@

    OEUnit - Unit Testing Framework

  • Writing a Test Suite
  • Running a Test
  • Reporting Test Results
  • +
  • DataProviders
  • License
  • Change Log
  • diff --git a/doc/reportingtests.html b/doc/reportingtests.html index 030faa2..0863687 100644 --- a/doc/reportingtests.html +++ b/doc/reportingtests.html @@ -16,6 +16,7 @@

    OEUnit - Unit Testing Framework

  • Writing a Test Suite
  • Running a Test
  • Reporting Test Results
  • +
  • DataProviders
  • License
  • Change Log
  • diff --git a/doc/runningtests.html b/doc/runningtests.html index 5ae59e3..5f42b1a 100644 --- a/doc/runningtests.html +++ b/doc/runningtests.html @@ -16,6 +16,7 @@

    OEUnit - Unit Testing Framework

  • Writing a Test Suite
  • Running a Test
  • Reporting Test Results
  • +
  • DataProviders
  • License
  • Change Log
  • diff --git a/doc/testcase.html b/doc/testcase.html index 4ef4b51..f8d7174 100644 --- a/doc/testcase.html +++ b/doc/testcase.html @@ -16,6 +16,7 @@

    OEUnit - Unit Testing Framework

  • Writing a Test Suite
  • Running a Test
  • Reporting Test Results
  • +
  • DataProviders
  • License
  • Change Log
  • @@ -77,7 +78,7 @@

    Test Methods

    Syntax:

    -

       @Test[(expected="ErrorTypeName")].

    +
       @Test[([expected="ErrorTypeName"][,dataProvider="DataProviderMethod"])].

    ErrorTypeName
        The Type-Name of a class that inherits from Progress.Lang.Error. @@ -85,6 +86,11 @@

    Test Methods

    Test method. If the expected error is thrown, the test passes, otherwise the test fails.

    +

    + DataProviderMethod
    +     The name of a method that has been defined with a @DataProvider annotation. + For more information on DataProviders, see Data Providers. +


    @@ -120,7 +126,11 @@

    Test Methods

  • If no errors are thrown by while running a Test method, the test is assumed to have succeeded.
  • There are no special naming requirements for Test methods.
  • -
  • Test methods must be PUBLIC and accept no parameters.
  • +
  • Test methods must be PUBLIC
  • +
  • Test methods must accept no parameters, unless they have been defined with the DataProvider + attribute. In which case, the number of parameters, data types, and order must match the order of + the data provided in the @DataProvider method. Only the INPUT parameter type is supported. For more + infomation on DataProviders, see DataProviders.
  • Test methods can be STATIC.
  • Before Methods

    diff --git a/doc/testsuite.html b/doc/testsuite.html index c23c419..a0af385 100644 --- a/doc/testsuite.html +++ b/doc/testsuite.html @@ -16,6 +16,7 @@

    OEUnit - Unit Testing Framework

  • Writing a Test Suite
  • Running a Test
  • Reporting Test Results
  • +
  • DataProviders
  • License
  • Change Log
  • From 3190132d776c2819ad2a5d3dda572a32ab585631 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Wed, 5 Nov 2014 13:46:33 +0000 Subject: [PATCH 12/33] Add functionality to load DataProvider data from XML --- doc/dataprovider.html | 26 +++++++++++ src/OEUnit/Data/DataProvider.cls | 20 ++++++++ src/OEUnit/Tests/Data/DataProviderTest.cls | 54 ++++++++++++++++++++++ 3 files changed, 100 insertions(+) diff --git a/doc/dataprovider.html b/doc/dataprovider.html index 3621c2c..998e655 100644 --- a/doc/dataprovider.html +++ b/doc/dataprovider.html @@ -169,6 +169,32 @@

    DataProvider Methods

    READ-JSON method.
  • The method will return TRUE if the data was successfully loaded.
  • +

    METHOD PUBLIC LOGICAL FromXML(INPUT xml AS LONGCHAR)

    +

    This method is used to load data from XML data stored in a LONGCHAR.

    +

    + +
    + Notes:

    +
      +
    • The structure of the XML data should match that which is accepted by an OpenEdge DATASET + or TEMP-TABLE when using the READ-XML method.
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    • It is advised to specify the XML Schema in the XML data in order for data types to be correctly interpreted.
    • +
    +

    METHOD PUBLIC LOGICAL FromXMLFile(INPUT path AS CHARACTER):

    +

    This method is used to load data from XML data stored in a file. The file path should be provided as the + INPUT parameter.

    +

    + +
    + Notes:

    +
      +
    • The structure of the XML data in the file should match that which is accepted by an OpenEdge + DATASET or TEMP-TABLE when using the + READ-XML method.
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    • It is advised to specify the XML Schema in the XML data in order for data types to be correctly interpreted.
    • +
    diff --git a/src/OEUnit/Data/DataProvider.cls b/src/OEUnit/Data/DataProvider.cls index f897be9..9af041d 100644 --- a/src/OEUnit/Data/DataProvider.cls +++ b/src/OEUnit/Data/DataProvider.cls @@ -65,6 +65,26 @@ CLASS OEUnit.Data.DataProvider: RETURN res. END METHOD. + METHOD PUBLIC LOGICAL FromXML(INPUT xml AS LONGCHAR): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(ttQuery) THEN DELETE OBJECT ttQuery. + IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. + CREATE TEMP-TABLE ttData. + res = ttData:READ-XML("LONGCHAR", xml, "EMPTY", ?, ?). + CountSize(). + RETURN res. + END METHOD. + + METHOD PUBLIC LOGICAL FromXMLFile(INPUT path AS CHARACTER): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(ttQuery) THEN DELETE OBJECT ttQuery. + IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. + CREATE TEMP-TABLE ttData. + res = ttData:READ-XML("FILE", path, "EMPTY", ?, ?). + CountSize(). + RETURN res. + END METHOD. + METHOD PUBLIC Progress.Lang.ParameterList GetParameterList(): DEFINE VARIABLE numParams AS INTEGER NO-UNDO. DEFINE VARIABLE bufHandle AS HANDLE NO-UNDO. diff --git a/src/OEUnit/Tests/Data/DataProviderTest.cls b/src/OEUnit/Tests/Data/DataProviderTest.cls index 7beb53c..7b35957 100644 --- a/src/OEUnit/Tests/Data/DataProviderTest.cls +++ b/src/OEUnit/Tests/Data/DataProviderTest.cls @@ -42,6 +42,60 @@ CLASS OEUnit.Tests.Data.DataProviderTest: Assert:AreEqual(dataProvider:Size, 4). END METHOD. + @Test. + METHOD PUBLIC VOID FromXML(): + dataProvider = NEW DataProvider(). + dataProvider:FromXML('' + + '' + + '' + + ' NEW' + + ' true' + + '' + + '' + + ' ACCEPTED' + + ' true' + + '' + + ''). + Assert:AreEqual(dataProvider:Size, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromXML_Reset(): + dataProvider = NEW DataProvider(). + dataProvider:FromXML('' + + '' + + '' + + ' NEW' + + ' true' + + '' + + '' + + ' ACCEPTED' + + ' true' + + '' + + ''). + Assert:AreEqual(dataProvider:Size, 2). + dataProvider:FromXML('' + + '' + + '' + + ' NEW' + + ' true' + + '' + + '' + + ' ACCEPTED' + + ' true' + + '' + + '' + + ' PICKING' + + ' true' + + '' + + '' + + ' POSTED' + + ' false' + + '' + + ''). + Assert:AreEqual(dataProvider:Size, 4). + END METHOD. + @Test. METHOD PUBLIC VOID MoveFirst(): dataProvider = NEW DataProvider(). From d412826788dd4363991eeb61ed1b673626f17a2d Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Wed, 5 Nov 2014 14:03:05 +0000 Subject: [PATCH 13/33] Add 'FromTempTable' method to DataProvider to allow data and schema to be copied from an existing temp-table. --- doc/dataprovider.html | 12 ++++++ src/OEUnit/Data/DataProvider.cls | 10 +++++ src/OEUnit/Tests/Data/DataProviderTest.cls | 47 ++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/doc/dataprovider.html b/doc/dataprovider.html index 998e655..8112932 100644 --- a/doc/dataprovider.html +++ b/doc/dataprovider.html @@ -195,6 +195,18 @@

    DataProvider Methods

  • The method will return TRUE if the data was successfully loaded.
  • It is advised to specify the XML Schema in the XML data in order for data types to be correctly interpreted.
  • +

    METHOD PUBLIC LOGICAL FromTempTable(INPUT ttSrc AS HANDLE):

    +

    This method is used to load data from an existing temp-table, via the provided HANDLE INPUT parameter.

    +

    + +
    + Notes:

    +
      +
    • The entire data and metaschema of the temp-table are copied.
    • +
    • Data is copied in EMPTY mode
    • +
    • The data and metaschema of the provided source temp-table are not affected.
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    diff --git a/src/OEUnit/Data/DataProvider.cls b/src/OEUnit/Data/DataProvider.cls index 9af041d..99c1768 100644 --- a/src/OEUnit/Data/DataProvider.cls +++ b/src/OEUnit/Data/DataProvider.cls @@ -84,6 +84,16 @@ CLASS OEUnit.Data.DataProvider: CountSize(). RETURN res. END METHOD. + + METHOD PUBLIC LOGICAL FromTempTable(INPUT ttSrc AS HANDLE): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(ttQuery) THEN DELETE OBJECT ttQuery. + IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. + CREATE TEMP-TABLE ttData. + res = ttData:COPY-TEMP-TABLE(ttSrc). + CountSize(). + RETURN res. + END METHOD. METHOD PUBLIC Progress.Lang.ParameterList GetParameterList(): DEFINE VARIABLE numParams AS INTEGER NO-UNDO. diff --git a/src/OEUnit/Tests/Data/DataProviderTest.cls b/src/OEUnit/Tests/Data/DataProviderTest.cls index 7b35957..177a1e9 100644 --- a/src/OEUnit/Tests/Data/DataProviderTest.cls +++ b/src/OEUnit/Tests/Data/DataProviderTest.cls @@ -8,6 +8,10 @@ USING OEUnit.Data.DataProvider. CLASS OEUnit.Tests.Data.DataProviderTest: + DEFINE PROTECTED TEMP-TABLE ttTestTable NO-UNDO + FIELD StatusCode AS CHARACTER + FIELD Accepted AS LOGICAL. + DEFINE VARIABLE dataProvider AS DataProvider NO-UNDO. @After. @@ -96,6 +100,49 @@ CLASS OEUnit.Tests.Data.DataProviderTest: Assert:AreEqual(dataProvider:Size, 4). END METHOD. + @Test. + METHOD PUBLIC VOID FromTempTable(): + dataProvider = NEW DataProvider(). + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + dataProvider:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). + Assert:AreEqual(dataProvider:Size, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromTempTable_Reset(): + dataProvider = NEW DataProvider(). + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "PICKING" + ttTestTable.Accepted = FALSE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "POSTED" + ttTestTable.Accepted = FALSE. + dataProvider:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). + Assert:AreEqual(dataProvider:Size, 4). + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + dataProvider:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). + Assert:AreEqual(dataProvider:Size, 2). + END METHOD. + @Test. METHOD PUBLIC VOID MoveFirst(): dataProvider = NEW DataProvider(). From ce5e599f9d70f3f6c4347c12dcb1979094ed4685 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Tue, 16 Dec 2014 16:00:46 +0000 Subject: [PATCH 14/33] Create class to hold Fixture data as a DataSet, and associated error classes. --- src/OEUnit/Data/Fixture.cls | 173 +++++++++++++++++++++++++ src/OEUnit/Data/FixtureCreateError.cls | 18 +++ src/OEUnit/Data/FixtureError.cls | 18 +++ 3 files changed, 209 insertions(+) create mode 100644 src/OEUnit/Data/Fixture.cls create mode 100644 src/OEUnit/Data/FixtureCreateError.cls create mode 100644 src/OEUnit/Data/FixtureError.cls diff --git a/src/OEUnit/Data/Fixture.cls b/src/OEUnit/Data/Fixture.cls new file mode 100644 index 0000000..3efee78 --- /dev/null +++ b/src/OEUnit/Data/Fixture.cls @@ -0,0 +1,173 @@ +/*------------------------------------------------------------------------------ + File : Fixture.cls + Package : OEUnit.Data + Description : Stores and uses data provided in associated methods when + calling a test case to pre-load database tables for a test. +------------------------------------------------------------------------------*/ +USING Progress.Lang.*. +USING OEUnit.Data.*. + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +CLASS OEUnit.Data.Fixture: + + DEFINE PROTECTED VARIABLE dsData AS HANDLE NO-UNDO. + + /*---------------------------------------------------------------------------- + Read-only Property that returns the number of top level buffers in dataset + ----------------------------------------------------------------------------*/ + DEFINE PUBLIC PROPERTY TableCount AS INTEGER NO-UNDO + GET (): + IF VALID-HANDLE(dsData) THEN RETURN dsData:NUM-TOP-BUFFERS. + ELSE RETURN 0. + END GET. + + CONSTRUCTOR PUBLIC Fixture(): + SUPER (). + END CONSTRUCTOR. + + DESTRUCTOR PUBLIC Fixture(): + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + END DESTRUCTOR. + + /*---------------------------------------------------------------------------- + Import fixture data from dataset encoded in JSON via parameter + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromJSON(INPUT json AS LONGCHAR): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + res = dsData:READ-JSON("LONGCHAR", json, "EMPTY"). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Import fixture data from data encoded in JSON in given file + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromJSONFile(INPUT path AS CHARACTER): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + res = dsData:READ-JSON("FILE", path, "EMPTY"). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Import fixture data from dataset encoded in XML via parameter + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromXML(INPUT xml AS LONGCHAR): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + res = dsData:READ-XML("LONGCHAR", xml, "EMPTY", ?, ?). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Import fixture data from data encoded in XML in given file + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromXMLFile(INPUT path AS CHARACTER): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + res = dsData:READ-XML("FILE", path, "EMPTY", ?, ?). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Import fixture data by copying from an existing dataset + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromDataSet(INPUT dsSrc AS HANDLE): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + res = dsData:COPY-DATASET(dsSrc). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Import fixture data by copying from a temp-table + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromTempTable(INPUT ttSrc AS HANDLE): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + DEFINE VARIABLE ttSrcCpy AS HANDLE NO-UNDO. + DEFINE VARIABLE ttData AS HANDLE NO-UNDO. + DEFINE VARIABLE ttDataBuf AS HANDLE NO-UNDO. + DEFINE VARIABLE hSource AS HANDLE NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + IF NOT VALID-HANDLE(dsData) THEN RETURN FALSE. + CREATE TEMP-TABLE ttData. + res = ttData:COPY-TEMP-TABLE(ttSrc,FALSE,FALSE,FALSE,""). + IF res = FALSE THEN + DO: + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. + RETURN res. + END. + CREATE TEMP-TABLE ttSrcCpy. + res = ttSrcCpy:COPY-TEMP-TABLE(ttSrc,FALSE,FALSE,FALSE,""). + IF res = FALSE THEN + DO: + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. + IF VALID-HANDLE(ttSrcCpy) THEN DELETE OBJECT ttSrcCpy. + RETURN res. + END. + ttDataBuf = ttData:DEFAULT-BUFFER-HANDLE. + dsData:ADD-BUFFER(ttDataBuf). + CREATE DATA-SOURCE hSource. + IF NOT VALID-HANDLE(hSource) THEN + DO: + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + DELETE OBJECT hSource. + END. + hSource:ADD-SOURCE-BUFFER(ttSrcCpy:DEFAULT-BUFFER-HANDLE,?). + ttDataBuf:ATTACH-DATA-SOURCE(hSource). + dsData:FILL(). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Create data in the attached databases, based on data in dataset tables. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL CreateData(): + DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO. + DEFINE VARIABLE hQuery AS HANDLE NO-UNDO. + DEFINE VARIABLE hQBuffer AS HANDLE NO-UNDO. + DEFINE VARIABLE hRBuffer AS HANDLE NO-UNDO. + DEFINE VARIABLE iCount AS INTEGER NO-UNDO. + + /* Ensure that any errors are thrown properly */ + DO ON ERROR UNDO, THROW: + IF NOT VALID-HANDLE(dsData) THEN RETURN FALSE. + DO iCount = 1 TO dsData:NUM-TOP-BUFFERS + ON ERROR UNDO, THROW: + hBuffer = dsData:GET-TOP-BUFFER(iCount). + IF NOT VALID-HANDLE(hBuffer) THEN RETURN ERROR NEW FixtureError("Failed to fetch buffer from DataSet"). + IF VALID-HANDLE(hQuery) THEN DELETE OBJECT hQuery. + IF VALID-HANDLE(hQBuffer) THEN DELETE OBJECT hQBuffer. + CREATE BUFFER hQBuffer FOR TABLE hBuffer. + CREATE BUFFER hRBuffer FOR TABLE hBuffer:NAME NO-ERROR. + IF ERROR-STATUS:ERROR THEN RETURN ERROR NEW FixtureError(SUBSTITUTE("Could not create buffer for destination table &1.", hBuffer:NAME)). + CREATE QUERY hQuery. + hQuery:SET-BUFFERS(hQBuffer). /* NOTE: Because this is taken from Dataset, names of tables can overlap and doesn't cause a problem */ + IF(hQuery:QUERY-PREPARE("FOR EACH " + hBuffer:NAME + " NO-LOCK:") = FALSE) THEN + RETURN ERROR NEW FixtureError(SUBSTITUTE("Could not query data in source &1.", hBuffer:NAME)). + hQuery:QUERY-OPEN(). + hQuery:GET-FIRST(NO-LOCK). + DO WHILE NOT hQuery:QUERY-OFF-END + ON ERROR UNDO, THROW: + hRBuffer:BUFFER-CREATE(). + hRBuffer:BUFFER-COPY(hQBuffer). + hRBuffer:BUFFER-RELEASE(). + hQuery:GET-NEXT(). + END. + IF VALID-HANDLE(hRBuffer) THEN DELETE OBJECT hRBuffer. + IF VALID-HANDLE(hQBuffer) THEN DELETE OBJECT hQBuffer. + IF VALID-HANDLE(hQuery) THEN DELETE OBJECT hQuery. + END. + END. + END METHOD. + +END CLASS. \ No newline at end of file diff --git a/src/OEUnit/Data/FixtureCreateError.cls b/src/OEUnit/Data/FixtureCreateError.cls new file mode 100644 index 0000000..465a7c4 --- /dev/null +++ b/src/OEUnit/Data/FixtureCreateError.cls @@ -0,0 +1,18 @@ +/*------------------------------------------------------------------------------ + File : FixtureCreateError.cls + Package : OEUnit.Data + Description : The exception thrown when Fixture encounters a problem. +------------------------------------------------------------------------------*/ + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +CLASS OEUnit.Data.FixtureCreateError INHERITS Progress.Lang.AppError: + + /*---------------------------------------------------------------------------- + Constructor. Accepts an error message. + ----------------------------------------------------------------------------*/ + CONSTRUCTOR PUBLIC FixtureCreateError(INPUT errorMessage AS CHARACTER): + SUPER(SUBSTITUTE("Fixture Error: &1",errorMessage), 0). + END CONSTRUCTOR. + +END CLASS. \ No newline at end of file diff --git a/src/OEUnit/Data/FixtureError.cls b/src/OEUnit/Data/FixtureError.cls new file mode 100644 index 0000000..a07d447 --- /dev/null +++ b/src/OEUnit/Data/FixtureError.cls @@ -0,0 +1,18 @@ +/*------------------------------------------------------------------------------ + File : FixtureError.cls + Package : OEUnit.Data + Description : The exception thrown when Fixture encounters a problem. +------------------------------------------------------------------------------*/ + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +CLASS OEUnit.Data.FixtureError INHERITS Progress.Lang.AppError: + + /*---------------------------------------------------------------------------- + Constructor. Accepts an error message. + ----------------------------------------------------------------------------*/ + CONSTRUCTOR PUBLIC FixtureError(INPUT errorMessage AS CHARACTER): + SUPER(errorMessage, 0). + END CONSTRUCTOR. + +END CLASS. \ No newline at end of file From 6a9c85034e1b7a04e5b5fcf68308db5e796901bb Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Tue, 16 Dec 2014 17:04:18 +0000 Subject: [PATCH 15/33] Add annotation and attribute names for Fixtures --- src/OEUnit/Runners/OEUnitAnnotations.cls | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/OEUnit/Runners/OEUnitAnnotations.cls b/src/OEUnit/Runners/OEUnitAnnotations.cls index 2aaa0e5..19a67b1 100644 --- a/src/OEUnit/Runners/OEUnitAnnotations.cls +++ b/src/OEUnit/Runners/OEUnitAnnotations.cls @@ -18,12 +18,23 @@ CLASS OEUnit.Runners.OEUnitAnnotations: DEFINE PUBLIC STATIC PROPERTY BeforeClass AS CHARACTER NO-UNDO INIT "BeforeClass" GET. DEFINE PUBLIC STATIC PROPERTY AfterClass AS CHARACTER NO-UNDO INIT "AfterClass" GET. DEFINE PUBLIC STATIC PROPERTY DataProvider AS CHARACTER NO-UNDO INIT "DataProvider" GET. + DEFINE PUBLIC STATIC PROPERTY Fixture AS CHARACTER NO-UNDO INIT "Fixture" GET. /*---------------------------------------------------------------------------- Expected Attribute for the Test Annotation. ----------------------------------------------------------------------------*/ DEFINE PUBLIC STATIC PROPERTY TestExpectedAttribute AS CHARACTER NO-UNDO INIT "Expected" GET. DEFINE PUBLIC STATIC PROPERTY TestDataProviderAttribute AS CHARACTER NO-UNDO INIT "DataProvider" GET. + DEFINE PUBLIC STATIC PROPERTY TestFixtureAttribute AS CHARACTER NO-UNDO INIT "Fixture" GET. + + /*---------------------------------------------------------------------------- + Expected Attribute for the DataProvider Annotation. + ----------------------------------------------------------------------------*/ DEFINE PUBLIC STATIC PROPERTY DataProviderNameAttribute AS CHARACTER NO-UNDO INIT "Name" GET. + /*---------------------------------------------------------------------------- + Expected Attribute for the Fixture Annotation. + ----------------------------------------------------------------------------*/ + DEFINE PUBLIC STATIC PROPERTY FixtureNameAttribute AS CHARACTER NO-UNDO INIT "Name" GET. + END CLASS. \ No newline at end of file From 8dafc04076db5c9d3005ed8acac46916a107c0ac Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Wed, 17 Dec 2014 13:39:16 +0000 Subject: [PATCH 16/33] Add unit tests for Fixtures --- src/OEUnit/Tests/Data/AllTestSuite.cls | 1 + src/OEUnit/Tests/Data/FixtureTest.cls | 198 +++++++++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 src/OEUnit/Tests/Data/FixtureTest.cls diff --git a/src/OEUnit/Tests/Data/AllTestSuite.cls b/src/OEUnit/Tests/Data/AllTestSuite.cls index 8772bbf..a43d69e 100644 --- a/src/OEUnit/Tests/Data/AllTestSuite.cls +++ b/src/OEUnit/Tests/Data/AllTestSuite.cls @@ -7,6 +7,7 @@ CLASS OEUnit.Tests.Data.AllTestSuite INHERITS TestSuite: CONSTRUCTOR AllTestSuite(): AddTest(NEW DataProviderTest()). + AddTest(NEW FixtureTest()). END CONSTRUCTOR. END CLASS. \ No newline at end of file diff --git a/src/OEUnit/Tests/Data/FixtureTest.cls b/src/OEUnit/Tests/Data/FixtureTest.cls new file mode 100644 index 0000000..4a5d1b1 --- /dev/null +++ b/src/OEUnit/Tests/Data/FixtureTest.cls @@ -0,0 +1,198 @@ + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +USING Progress.Lang.*. +USING OEUnit.Tests.Data.*. +USING OEUnit.Assertion.Assert. +USING OEUnit.Data.Fixture. + +CLASS OEUnit.Tests.Data.FixtureTest: + + DEFINE PROTECTED TEMP-TABLE ttTestTable NO-UNDO + FIELD StatusCode AS CHARACTER + FIELD Accepted AS LOGICAL + INDEX StatusCode IS PRIMARY UNIQUE StatusCode ASCENDING. + + DEFINE VARIABLE fixture AS Fixture NO-UNDO. + + @After. + METHOD PUBLIC VOID DeleteFixture(): + DELETE OBJECT fixture NO-ERROR. + END METHOD. + + @Test. + METHOD PUBLIC VOID FromJSON(): + fixture = NEW Fixture(). + fixture:FromJSON("~{ ~"FirstTable~": [" + + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + " ], " + + " ~"SecondTable~": [" + + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}" + + "]}"). + Assert:AreEqual(fixture:TableCount, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromJSON_Reset(): + fixture = NEW Fixture(). + fixture:FromJSON("~{ ~"FirstTable~": [" + + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "]}"). + Assert:AreEqual(fixture:TableCount, 1). + fixture:FromJSON("~{ ~"FirstTable~": [" + + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + " ], " + + " ~"SecondTable~": [" + + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}" + + "]}"). + Assert:AreEqual(fixture:TableCount, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromXML(): + fixture = NEW Fixture(). + fixture:FromXML('' + + '' + + '' + + 'NEW' + + 'true' + + '' + + '' + + 'ACCEPTED' + + 'true' + + '' + + '' + + 'ACCEPTED' + + 'true' + + '' + + ''). + Assert:AreEqual(fixture:TableCount, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromXML_Reset(): + fixture = NEW Fixture(). + fixture:FromXML('' + + '' + + '' + + 'NEW' + + 'true' + + '' + + '' + + 'ACCEPTED' + + 'true' + + '' + + ''). + Assert:AreEqual(fixture:TableCount, 1). + fixture:FromXML('' + + '' + + '' + + 'NEW' + + 'true' + + '' + + '' + + 'ACCEPTED' + + 'true' + + '' + + '' + + 'ACCEPTED' + + 'true' + + '' + + ''). + Assert:AreEqual(fixture:TableCount, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromDataSet(): + + DEFINE VARIABLE httTest AS HANDLE NO-UNDO. + DEFINE VARIABLE hdSet AS HANDLE NO-UNDO. + DEFINE VARIABLE htt AS HANDLE NO-UNDO. + DEFINE VARIABLE hdSource AS HANDLE NO-UNDO. + DEFINE VARIABLE httBuffer AS HANDLE NO-UNDO. + + fixture = NEW Fixture(). + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + + ASSIGN httTest = TEMP-TABLE ttTestTable:HANDLE. + + CREATE TEMP-TABLE htt. + htt:COPY-TEMP-TABLE(httTest, FALSE, TRUE). + + httBuffer = htt:DEFAULT-BUFFER-HANDLE. + + CREATE DATASET hdSet. + hdSet:ADD-BUFFER(httBuffer). + + CREATE DATA-SOURCE hdSource. + hdSource:ADD-SOURCE-BUFFER(httTest:DEFAULT-BUFFER-HANDLE,?). + httBuffer:ATTACH-DATA-SOURCE(hdSource). + hdSet:FILL(). + fixture:FromDataSet(hdSet). + Assert:AreEqual(fixture:TableCount, 1). + + END METHOD. + /* + @Test. + METHOD PUBLIC VOID FromTempTable_Reset(): + fixture = NEW Fixture(). + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "PICKING" + ttTestTable.Accepted = FALSE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "POSTED" + ttTestTable.Accepted = FALSE. + fixture:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). + /*Assert:AreEqual(fixture:Size, 4).*/ + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + fixture:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). + /*Assert:AreEqual(fixture:Size, 2).*/ + END METHOD. + */ + + @Test. + METHOD PUBLIC VOID FromTempTable(): + + DEFINE VARIABLE httTest AS HANDLE NO-UNDO. + DEFINE VARIABLE hdSet AS HANDLE NO-UNDO. + DEFINE VARIABLE htt AS HANDLE NO-UNDO. + DEFINE VARIABLE hdSource AS HANDLE NO-UNDO. + DEFINE VARIABLE httBuffer AS HANDLE NO-UNDO. + + fixture = NEW Fixture(). + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + + fixture:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). + Assert:AreEqual(fixture:TableCount,1). + END. +END CLASS. \ No newline at end of file From 1176b508c32a55fbfd3a63003040766e8389644d Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Wed, 17 Dec 2014 15:12:48 +0000 Subject: [PATCH 17/33] Refactor MethodInfo:GetDataProviderInfo into GetAssociatedMethodInfo in order for it to be reused with Fixtures. --- src/OEUnit/Reflection/MethodInfo.cls | 85 ++++++++++++++++------------ 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/src/OEUnit/Reflection/MethodInfo.cls b/src/OEUnit/Reflection/MethodInfo.cls index f109b86..836761e 100644 --- a/src/OEUnit/Reflection/MethodInfo.cls +++ b/src/OEUnit/Reflection/MethodInfo.cls @@ -90,42 +90,9 @@ CLASS OEUnit.Reflection.MethodInfo INHERITS StatementInfo: data provider method for this MethodInfo. ----------------------------------------------------------------------------*/ METHOD PUBLIC MethodInfo GetDataProviderInfo(): - - DEFINE VARIABLE annotation AS AnnotationInfo NO-UNDO. - DEFINE VARIABLE dataProviderAnnotation AS AnnotationInfo NO-UNDO. - DEFINE VARIABLE dataProviders AS List NO-UNDO. - DEFINE VARIABLE dataProviderName AS CHARACTER NO-UNDO. - DEFINE VARIABLE dataProvider AS MethodInfo NO-UNDO. - DEFINE VARIABLE result AS LOGICAL NO-UNDO INITIAL FALSE. - - /* If this is a @Test, with a "DataProvider=" attribute, then attempt to - * find the data provider method - */ - annotation = GetAnnotationOfType(OEUnitAnnotations:Test). - - IF annotation NE ? AND annotation:HasAttribute("dataProvider") THEN - DO: - dataProviderName = annotation:Attributes:Get(OEUnitAnnotations:TestDataProviderAttribute). - dataProviders = parentInfo:GetAnnotatedMethods(OEUnitAnnotations:DataProvider). - - /* Find first data provider with that name attribute or method name */ - dataProviders:MoveFirst(). - dataProviderLoop: - DO WHILE dataProviders:CURRENT NE ?: - dataProvider = CAST(dataProviders:CURRENT,"MethodInfo"). - dataProviderAnnotation = dataProvider:GetAnnotationOfType(OEUnitAnnotations:DataProvider). - IF (dataProviderAnnotation:HasAttribute("name") = TRUE) THEN - DO: - IF dataProviderName = dataProviderAnnotation:Attributes:Get(OEUnitAnnotations:DataProviderNameAttribute) THEN - LEAVE dataProviderLoop. - END. - ELSE IF dataProvider:Name = dataProviderName THEN LEAVE dataProviderLoop. - ELSE dataProvider = ?. - dataProviders:MoveNext(). - END. - END. - - RETURN dataProvider. + RETURN GetAssociatedMethodInfo(INPUT OEUnitAnnotations:TestDataProviderAttribute, + INPUT OEUnitAnnotations:DataProvider, + INPUT OEUnitAnnotations:DataProviderNameAttribute). END METHOD. /*---------------------------------------------------------------------------- @@ -162,5 +129,51 @@ CLASS OEUnit.Reflection.MethodInfo INHERITS StatementInfo: RETURN ERROR NEW StopConditionError("Stop condition occured"). END METHOD. + + /*---------------------------------------------------------------------------- + Returns another MethodInfo object for a method indicated in the attributes + in this MethodInfo. + ----------------------------------------------------------------------------*/ + METHOD PROTECTED MethodInfo GetAssociatedMethodInfo(INPUT methodAttribute AS CHARACTER, + INPUT associatedAnnotation AS CHARACTER, + INPUT associatedAttribute AS CHARACTER): + + DEFINE VARIABLE TestAnnotation AS AnnotationInfo NO-UNDO. + DEFINE VARIABLE MethodAnnotation AS AnnotationInfo NO-UNDO. + DEFINE VARIABLE AnnotatedMethods AS List NO-UNDO. + DEFINE VARIABLE AssociatedMethodName AS CHARACTER NO-UNDO. + DEFINE VARIABLE AssociatedMethodInfo AS MethodInfo NO-UNDO. + DEFINE VARIABLE result AS LOGICAL NO-UNDO INITIAL FALSE. + + /* If this is a @Test, with a "Fixture=" attribute, then attempt to + * find the data provider method + */ + TestAnnotation = GetAnnotationOfType(OEUnitAnnotations:Test). + + IF TestAnnotation NE ? AND TestAnnotation:HasAttribute(methodAttribute) THEN + DO: + AssociatedMethodName = TestAnnotation:Attributes:Get(methodAttribute). + AnnotatedMethods = parentInfo:GetAnnotatedMethods(associatedAnnotation). + + /* Find first data provider with that name attribute or method name */ + AnnotatedMethods:MoveFirst(). + MethodLoop: + DO WHILE AnnotatedMethods:CURRENT NE ?: + AssociatedMethodInfo = CAST(AnnotatedMethods:CURRENT,"MethodInfo"). + MethodAnnotation = AssociatedMethodInfo:GetAnnotationOfType(associatedAnnotation). + IF (MethodAnnotation:HasAttribute(associatedAttribute) = TRUE) THEN + DO: + IF AssociatedMethodName = MethodAnnotation:Attributes:Get(associatedAttribute) THEN + LEAVE MethodLoop. + END. + ELSE IF AssociatedMethodInfo:Name = AssociatedMethodName THEN LEAVE MethodLoop. + ELSE AssociatedMethodInfo = ?. + AnnotatedMethods:MoveNext(). + END. + END. + + RETURN AssociatedMethodInfo. + END METHOD. + END CLASS. From 840cd9c12b683c1c4f7afa3b461d9bc9aae72370 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Wed, 17 Dec 2014 15:58:09 +0000 Subject: [PATCH 18/33] Add functionality to MethodInfo to return Fixture information --- src/OEUnit/Reflection/MethodInfo.cls | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/OEUnit/Reflection/MethodInfo.cls b/src/OEUnit/Reflection/MethodInfo.cls index 836761e..c5ca24c 100644 --- a/src/OEUnit/Reflection/MethodInfo.cls +++ b/src/OEUnit/Reflection/MethodInfo.cls @@ -129,6 +129,49 @@ CLASS OEUnit.Reflection.MethodInfo INHERITS StatementInfo: RETURN ERROR NEW StopConditionError("Stop condition occured"). END METHOD. + /*---------------------------------------------------------------------------- + Returns another MethodInfo object which holds the information regarding the + fixture method for this MethodInfo. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC MethodInfo GetFixtureInfo(): + RETURN GetAssociatedMethodInfo(INPUT OEUnitAnnotations:TestFixtureAttribute, + INPUT OEUnitAnnotations:Fixture, + INPUT OEUnitAnnotations:FixtureNameAttribute). + END METHOD. + + /*---------------------------------------------------------------------------- + Determines whether this method has a @Test annotation with a Fixture + attribute, and a method with a matching @Fixture attribute exists. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL RequiresFixture(): + RETURN (GetFixtureInfo() NE ?). + END METHOD. + + /*---------------------------------------------------------------------------- + Returns a Fixture object from the invocation of a Fixture method. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC Fixture GetFixture(): + DEFINE VARIABLE fixtureMethod AS MethodInfo NO-UNDO. + DEFINE VARIABLE Fixture AS Fixture NO-UNDO. + DO ON ERROR UNDO, THROW + ON QUIT UNDO, RETURN ERROR NEW QuitConditionError("Quit condition occured") + ON STOP UNDO, LEAVE: + fixtureMethod = GetFixtureInfo(). + IF fixtureMethod NE ? AND VALID-OBJECT(fixtureMethod) THEN + DO: + IF fixtureMethod:IsStatic THEN + Fixture = DYNAMIC-INVOKE(fixtureMethod:ParentInfo:Name, fixtureMethod:Name). + ELSE + Fixture = DYNAMIC-INVOKE(fixtureMethod:ParentInfo:ClassInstance, fixtureMethod:Name). + END. + + RETURN Fixture. + END. + + /* HACK: To accomodate bug in OpenEdge runtime, crashes when returning custom + error instances on stop conditions */ + RETURN ERROR NEW StopConditionError("Stop condition occured"). + END METHOD. /*---------------------------------------------------------------------------- Returns another MethodInfo object for a method indicated in the attributes From 753f6017a5c4b68e6c8cb1fb2e96c154eb2d84a3 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Thu, 18 Dec 2014 11:05:52 +0000 Subject: [PATCH 19/33] Refactor RunTestMethod to include Fixtures and to create a transaction where needed. --- src/OEUnit/Runners/OEUnitRunner.cls | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/OEUnit/Runners/OEUnitRunner.cls b/src/OEUnit/Runners/OEUnitRunner.cls index e7daf4b..22acd72 100644 --- a/src/OEUnit/Runners/OEUnitRunner.cls +++ b/src/OEUnit/Runners/OEUnitRunner.cls @@ -204,17 +204,40 @@ CLASS OEUnit.Runners.OEUnitRunner INHERITS BaseRunner: END METHOD. /*---------------------------------------------------------------------------- - Run a single test method with the given parameters and store it's result. Any - Progress.Lang.Errors thrown during the run are caught and stored in the + Run a single test method with the given parameters and store it's result. If + a test fixture is required, it will be extracted and a transaction started. + Any Progress.Lang.Errors thrown during the run are caught and stored in the result. ----------------------------------------------------------------------------*/ METHOD PROTECTED VOID RunTestMethod(INPUT testMethod AS MethodInfo, INPUT paramList AS Progress.Lang.ParameterList): + + IF testMethod:RequiresFixture() THEN + DO: + OEUnitFixtureTransaction: + DO TRANSACTION + ON ERROR UNDO, THROW: + RunTestMethod(INPUT testMethod, testMethod:GetFixture(), INPUT paramList). + UNDO OEUnitFixtureTransaction, LEAVE OEUnitFixtureTransaction. + END. + END. + ELSE + RunTestMethod(INPUT testMethod, INPUT ?, INPUT paramList). + END METHOD. + + /*---------------------------------------------------------------------------- + Run a single test method with the given fixure object and parameters and + store it's result. If a fixture is provided, no transaction is started in + this method. Any Progress.Lang.Errors thrown during the run are caught and + stored in the result. + ----------------------------------------------------------------------------*/ + METHOD PROTECTED VOID RunTestMethod(INPUT testMethod AS MethodInfo, INPUT testFixture AS Fixture, INPUT paramList AS Progress.Lang.ParameterList): DEFINE VARIABLE methodResult AS TestMethodResult NO-UNDO. methodResult = NEW TestMethodResult(testMethod). currentResult:AddResult(methodResult). IF ShouldRun(testMethod) THEN DO ON ERROR UNDO, THROW: NotifyOfTestStart(testMethod). + IF testFixture NE ? AND VALID-OBJECT(testFixture) THEN testFixture:CreateData(). ETIME(TRUE). RunBefores(currentInfo:GetAnnotatedMethods(OEUnitAnnotations:Before)). ETIME(TRUE). From 8e45f2ce670f7fcc098abca701a895452968b949 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Mon, 22 Dec 2014 10:02:13 +0000 Subject: [PATCH 20/33] Duplicate functionality from OEUnit.Data.Fixture to OEUnit.Data.FixtureDataSet as part of refactoring to enable multiple Data Sets to be loaded into a Fixture. --- src/OEUnit/Data/FixtureDataSet.cls | 173 ++++++++++++++++ src/OEUnit/Tests/Data/AllTestSuite.cls | 1 + src/OEUnit/Tests/Data/FixtureDataSetTest.cls | 198 +++++++++++++++++++ 3 files changed, 372 insertions(+) create mode 100644 src/OEUnit/Data/FixtureDataSet.cls create mode 100644 src/OEUnit/Tests/Data/FixtureDataSetTest.cls diff --git a/src/OEUnit/Data/FixtureDataSet.cls b/src/OEUnit/Data/FixtureDataSet.cls new file mode 100644 index 0000000..92c73d3 --- /dev/null +++ b/src/OEUnit/Data/FixtureDataSet.cls @@ -0,0 +1,173 @@ +/*------------------------------------------------------------------------------ + File : FixtureDataSet.cls + Package : OEUnit.Data + Description : Stores and uses data provided in associated methods when + calling a test case to pre-load database tables for a test. +------------------------------------------------------------------------------*/ +USING Progress.Lang.*. +USING OEUnit.Data.*. + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +CLASS OEUnit.Data.FixtureDataSet: + + DEFINE PROTECTED VARIABLE dsData AS HANDLE NO-UNDO. + + /*---------------------------------------------------------------------------- + Read-only Property that returns the number of top level buffers in dataset + ----------------------------------------------------------------------------*/ + DEFINE PUBLIC PROPERTY TableCount AS INTEGER NO-UNDO + GET (): + IF VALID-HANDLE(dsData) THEN RETURN dsData:NUM-TOP-BUFFERS. + ELSE RETURN 0. + END GET. + + CONSTRUCTOR PUBLIC FixtureDataSet(): + SUPER (). + END CONSTRUCTOR. + + DESTRUCTOR PUBLIC FixtureDataSet(): + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + END DESTRUCTOR. + + /*---------------------------------------------------------------------------- + Import fixture data from dataset encoded in JSON via parameter + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromJSON(INPUT json AS LONGCHAR): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + res = dsData:READ-JSON("LONGCHAR", json, "EMPTY"). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Import fixture data from data encoded in JSON in given file + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromJSONFile(INPUT path AS CHARACTER): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + res = dsData:READ-JSON("FILE", path, "EMPTY"). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Import fixture data from dataset encoded in XML via parameter + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromXML(INPUT xml AS LONGCHAR): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + res = dsData:READ-XML("LONGCHAR", xml, "EMPTY", ?, ?). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Import fixture data from data encoded in XML in given file + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromXMLFile(INPUT path AS CHARACTER): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + res = dsData:READ-XML("FILE", path, "EMPTY", ?, ?). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Import fixture data by copying from an existing dataset + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromDataSet(INPUT dsSrc AS HANDLE): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + res = dsData:COPY-DATASET(dsSrc). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Import fixture data by copying from a temp-table + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL FromTempTable(INPUT ttSrc AS HANDLE): + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + DEFINE VARIABLE ttSrcCpy AS HANDLE NO-UNDO. + DEFINE VARIABLE ttData AS HANDLE NO-UNDO. + DEFINE VARIABLE ttDataBuf AS HANDLE NO-UNDO. + DEFINE VARIABLE hSource AS HANDLE NO-UNDO. + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + CREATE DATASET dsData. + IF NOT VALID-HANDLE(dsData) THEN RETURN FALSE. + CREATE TEMP-TABLE ttData. + res = ttData:COPY-TEMP-TABLE(ttSrc,FALSE,FALSE,FALSE,""). + IF res = FALSE THEN + DO: + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. + RETURN res. + END. + CREATE TEMP-TABLE ttSrcCpy. + res = ttSrcCpy:COPY-TEMP-TABLE(ttSrc,FALSE,FALSE,FALSE,""). + IF res = FALSE THEN + DO: + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. + IF VALID-HANDLE(ttSrcCpy) THEN DELETE OBJECT ttSrcCpy. + RETURN res. + END. + ttDataBuf = ttData:DEFAULT-BUFFER-HANDLE. + dsData:ADD-BUFFER(ttDataBuf). + CREATE DATA-SOURCE hSource. + IF NOT VALID-HANDLE(hSource) THEN + DO: + IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + DELETE OBJECT hSource. + END. + hSource:ADD-SOURCE-BUFFER(ttSrcCpy:DEFAULT-BUFFER-HANDLE,?). + ttDataBuf:ATTACH-DATA-SOURCE(hSource). + dsData:FILL(). + RETURN res. + END METHOD. + + /*---------------------------------------------------------------------------- + Create data in the attached databases, based on data in dataset tables. + ----------------------------------------------------------------------------*/ + METHOD PUBLIC LOGICAL CreateData(): + DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO. + DEFINE VARIABLE hQuery AS HANDLE NO-UNDO. + DEFINE VARIABLE hQBuffer AS HANDLE NO-UNDO. + DEFINE VARIABLE hRBuffer AS HANDLE NO-UNDO. + DEFINE VARIABLE iCount AS INTEGER NO-UNDO. + + /* Ensure that any errors are thrown properly */ + DO ON ERROR UNDO, THROW: + IF NOT VALID-HANDLE(dsData) THEN RETURN FALSE. + DO iCount = 1 TO dsData:NUM-TOP-BUFFERS + ON ERROR UNDO, THROW: + hBuffer = dsData:GET-TOP-BUFFER(iCount). + IF NOT VALID-HANDLE(hBuffer) THEN RETURN ERROR NEW FixtureError("Failed to fetch buffer from DataSet"). + IF VALID-HANDLE(hQuery) THEN DELETE OBJECT hQuery. + IF VALID-HANDLE(hQBuffer) THEN DELETE OBJECT hQBuffer. + CREATE BUFFER hQBuffer FOR TABLE hBuffer. + CREATE BUFFER hRBuffer FOR TABLE hBuffer:NAME NO-ERROR. + IF ERROR-STATUS:ERROR THEN RETURN ERROR NEW FixtureError(SUBSTITUTE("Could not create buffer for destination table &1.", hBuffer:NAME)). + CREATE QUERY hQuery. + hQuery:SET-BUFFERS(hQBuffer). /* NOTE: Because this is taken from Dataset, names of tables can overlap and doesn't cause a problem */ + IF(hQuery:QUERY-PREPARE("FOR EACH " + hBuffer:NAME + " NO-LOCK:") = FALSE) THEN + RETURN ERROR NEW FixtureError(SUBSTITUTE("Could not query data in source &1.", hBuffer:NAME)). + hQuery:QUERY-OPEN(). + hQuery:GET-FIRST(NO-LOCK). + DO WHILE NOT hQuery:QUERY-OFF-END + ON ERROR UNDO, THROW: + hRBuffer:BUFFER-CREATE(). + hRBuffer:BUFFER-COPY(hQBuffer). + hRBuffer:BUFFER-RELEASE(). + hQuery:GET-NEXT(). + END. + IF VALID-HANDLE(hRBuffer) THEN DELETE OBJECT hRBuffer. + IF VALID-HANDLE(hQBuffer) THEN DELETE OBJECT hQBuffer. + IF VALID-HANDLE(hQuery) THEN DELETE OBJECT hQuery. + END. + END. + END METHOD. + +END CLASS. \ No newline at end of file diff --git a/src/OEUnit/Tests/Data/AllTestSuite.cls b/src/OEUnit/Tests/Data/AllTestSuite.cls index a43d69e..0ed42f1 100644 --- a/src/OEUnit/Tests/Data/AllTestSuite.cls +++ b/src/OEUnit/Tests/Data/AllTestSuite.cls @@ -7,6 +7,7 @@ CLASS OEUnit.Tests.Data.AllTestSuite INHERITS TestSuite: CONSTRUCTOR AllTestSuite(): AddTest(NEW DataProviderTest()). + AddTest(NEW FixtureDataSetTest()). AddTest(NEW FixtureTest()). END CONSTRUCTOR. diff --git a/src/OEUnit/Tests/Data/FixtureDataSetTest.cls b/src/OEUnit/Tests/Data/FixtureDataSetTest.cls new file mode 100644 index 0000000..e1bbbff --- /dev/null +++ b/src/OEUnit/Tests/Data/FixtureDataSetTest.cls @@ -0,0 +1,198 @@ + +ROUTINE-LEVEL ON ERROR UNDO, THROW. + +USING Progress.Lang.*. +USING OEUnit.Tests.Data.*. +USING OEUnit.Assertion.Assert. +USING OEUnit.Data.Fixture. + +CLASS OEUnit.Tests.Data.FixtureDataSetTest: + + DEFINE PROTECTED TEMP-TABLE ttTestTable NO-UNDO + FIELD StatusCode AS CHARACTER + FIELD Accepted AS LOGICAL + INDEX StatusCode IS PRIMARY UNIQUE StatusCode ASCENDING. + + DEFINE VARIABLE fixture AS Fixture NO-UNDO. + + @After. + METHOD PUBLIC VOID DeleteFixture(): + DELETE OBJECT fixture NO-ERROR. + END METHOD. + + @Test. + METHOD PUBLIC VOID FromJSON(): + fixture = NEW Fixture(). + fixture:FromJSON("~{ ~"FirstTable~": [" + + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + " ], " + + " ~"SecondTable~": [" + + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}" + + "]}"). + Assert:AreEqual(fixture:TableCount, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromJSON_Reset(): + fixture = NEW Fixture(). + fixture:FromJSON("~{ ~"FirstTable~": [" + + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + "]}"). + Assert:AreEqual(fixture:TableCount, 1). + fixture:FromJSON("~{ ~"FirstTable~": [" + + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + + " ], " + + " ~"SecondTable~": [" + + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}" + + "]}"). + Assert:AreEqual(fixture:TableCount, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromXML(): + fixture = NEW Fixture(). + fixture:FromXML('' + + '' + + '' + + 'NEW' + + 'true' + + '' + + '' + + 'ACCEPTED' + + 'true' + + '' + + '' + + 'ACCEPTED' + + 'true' + + '' + + ''). + Assert:AreEqual(fixture:TableCount, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromXML_Reset(): + fixture = NEW Fixture(). + fixture:FromXML('' + + '' + + '' + + 'NEW' + + 'true' + + '' + + '' + + 'ACCEPTED' + + 'true' + + '' + + ''). + Assert:AreEqual(fixture:TableCount, 1). + fixture:FromXML('' + + '' + + '' + + 'NEW' + + 'true' + + '' + + '' + + 'ACCEPTED' + + 'true' + + '' + + '' + + 'ACCEPTED' + + 'true' + + '' + + ''). + Assert:AreEqual(fixture:TableCount, 2). + END METHOD. + + @Test. + METHOD PUBLIC VOID FromDataSet(): + + DEFINE VARIABLE httTest AS HANDLE NO-UNDO. + DEFINE VARIABLE hdSet AS HANDLE NO-UNDO. + DEFINE VARIABLE htt AS HANDLE NO-UNDO. + DEFINE VARIABLE hdSource AS HANDLE NO-UNDO. + DEFINE VARIABLE httBuffer AS HANDLE NO-UNDO. + + fixture = NEW Fixture(). + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + + ASSIGN httTest = TEMP-TABLE ttTestTable:HANDLE. + + CREATE TEMP-TABLE htt. + htt:COPY-TEMP-TABLE(httTest, FALSE, TRUE). + + httBuffer = htt:DEFAULT-BUFFER-HANDLE. + + CREATE DATASET hdSet. + hdSet:ADD-BUFFER(httBuffer). + + CREATE DATA-SOURCE hdSource. + hdSource:ADD-SOURCE-BUFFER(httTest:DEFAULT-BUFFER-HANDLE,?). + httBuffer:ATTACH-DATA-SOURCE(hdSource). + hdSet:FILL(). + fixture:FromDataSet(hdSet). + Assert:AreEqual(fixture:TableCount, 1). + + END METHOD. + /* + @Test. + METHOD PUBLIC VOID FromTempTable_Reset(): + fixture = NEW Fixture(). + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "PICKING" + ttTestTable.Accepted = FALSE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "POSTED" + ttTestTable.Accepted = FALSE. + fixture:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). + /*Assert:AreEqual(fixture:Size, 4).*/ + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + fixture:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). + /*Assert:AreEqual(fixture:Size, 2).*/ + END METHOD. + */ + + @Test. + METHOD PUBLIC VOID FromTempTable(): + + DEFINE VARIABLE httTest AS HANDLE NO-UNDO. + DEFINE VARIABLE hdSet AS HANDLE NO-UNDO. + DEFINE VARIABLE htt AS HANDLE NO-UNDO. + DEFINE VARIABLE hdSource AS HANDLE NO-UNDO. + DEFINE VARIABLE httBuffer AS HANDLE NO-UNDO. + + fixture = NEW Fixture(). + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + + fixture:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). + Assert:AreEqual(fixture:TableCount,1). + END. +END CLASS. \ No newline at end of file From 27c1bf526d76f04ce9f33456c8e464cf76f6dd00 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Mon, 22 Dec 2014 11:20:36 +0000 Subject: [PATCH 21/33] Refactor Fixture to use FixtureDataSet, and to store multiple datasets (and apply them in order). --- src/OEUnit/Data/Fixture.cls | 173 +++++++++++++------------- src/OEUnit/Tests/Data/FixtureTest.cls | 46 ++++++- 2 files changed, 131 insertions(+), 88 deletions(-) diff --git a/src/OEUnit/Data/Fixture.cls b/src/OEUnit/Data/Fixture.cls index 3efee78..2774ce2 100644 --- a/src/OEUnit/Data/Fixture.cls +++ b/src/OEUnit/Data/Fixture.cls @@ -6,38 +6,71 @@ ------------------------------------------------------------------------------*/ USING Progress.Lang.*. USING OEUnit.Data.*. +USING OEUnit.Util.*. ROUTINE-LEVEL ON ERROR UNDO, THROW. CLASS OEUnit.Data.Fixture: DEFINE PROTECTED VARIABLE dsData AS HANDLE NO-UNDO. + DEFINE PROTECTED VARIABLE Fixtures AS List NO-UNDO. /*---------------------------------------------------------------------------- Read-only Property that returns the number of top level buffers in dataset ----------------------------------------------------------------------------*/ DEFINE PUBLIC PROPERTY TableCount AS INTEGER NO-UNDO GET (): + DEFINE VARIABLE tCount AS INTEGER NO-UNDO INITIAL 0. + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + DEFINE VARIABLE fix AS FixtureDataSet NO-UNDO. + IF VALID-OBJECT(Fixtures) THEN + DO: + res = Fixtures:MoveFirst(). + DO WHILE res = TRUE + ON ERROR UNDO, THROW: + fix = CAST(Fixtures:CURRENT, "OEUnit.Data.FixtureDataSet"). + tCount = tCount + fix:TableCount. + res = Fixtures:MoveNext(). + END. + RETURN tCount. + END. IF VALID-HANDLE(dsData) THEN RETURN dsData:NUM-TOP-BUFFERS. ELSE RETURN 0. END GET. + /*---------------------------------------------------------------------------- + The number of elements in the list + ----------------------------------------------------------------------------*/ + DEFINE PUBLIC PROPERTY Size AS INTEGER NO-UNDO INIT 0 + GET (): + IF VALID-OBJECT(Fixtures) THEN RETURN Fixtures:Size. + ELSE RETURN 0. + END GET. + PRIVATE SET. + CONSTRUCTOR PUBLIC Fixture(): SUPER (). + Fixtures = NEW List(TRUE). /* TRUE => destory list objects on destruction */ END CONSTRUCTOR. DESTRUCTOR PUBLIC Fixture(): IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. + IF VALID-OBJECT(Fixtures) THEN DELETE OBJECT Fixtures. END DESTRUCTOR. /*---------------------------------------------------------------------------- Import fixture data from dataset encoded in JSON via parameter ----------------------------------------------------------------------------*/ METHOD PUBLIC LOGICAL FromJSON(INPUT json AS LONGCHAR): + DEFINE VARIABLE fix AS FixtureDataSet NO-UNDO. DEFINE VARIABLE res AS LOGICAL NO-UNDO. - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - CREATE DATASET dsData. - res = dsData:READ-JSON("LONGCHAR", json, "EMPTY"). + fix = NEW FixtureDataSet(). + res = fix:FromJSON(INPUT json). + IF res = TRUE THEN + Fixtures:Add(fix). + ELSE + IF VALID-OBJECT(fix) THEN + DELETE OBJECT fix. RETURN res. END METHOD. @@ -45,10 +78,15 @@ CLASS OEUnit.Data.Fixture: Import fixture data from data encoded in JSON in given file ----------------------------------------------------------------------------*/ METHOD PUBLIC LOGICAL FromJSONFile(INPUT path AS CHARACTER): + DEFINE VARIABLE fix AS FixtureDataSet NO-UNDO. DEFINE VARIABLE res AS LOGICAL NO-UNDO. - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - CREATE DATASET dsData. - res = dsData:READ-JSON("FILE", path, "EMPTY"). + fix = NEW FixtureDataSet(). + res = fix:FromJSONFile(INPUT path). + IF res = TRUE THEN + Fixtures:Add(fix). + ELSE + IF VALID-OBJECT(fix) THEN + DELETE OBJECT fix. RETURN res. END METHOD. @@ -56,10 +94,15 @@ CLASS OEUnit.Data.Fixture: Import fixture data from dataset encoded in XML via parameter ----------------------------------------------------------------------------*/ METHOD PUBLIC LOGICAL FromXML(INPUT xml AS LONGCHAR): + DEFINE VARIABLE fix AS FixtureDataSet NO-UNDO. DEFINE VARIABLE res AS LOGICAL NO-UNDO. - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - CREATE DATASET dsData. - res = dsData:READ-XML("LONGCHAR", xml, "EMPTY", ?, ?). + fix = NEW FixtureDataSet(). + res = fix:FromXML(INPUT xml). + IF res = TRUE THEN + Fixtures:Add(fix). + ELSE + IF VALID-OBJECT(fix) THEN + DELETE OBJECT fix. RETURN res. END METHOD. @@ -67,10 +110,15 @@ CLASS OEUnit.Data.Fixture: Import fixture data from data encoded in XML in given file ----------------------------------------------------------------------------*/ METHOD PUBLIC LOGICAL FromXMLFile(INPUT path AS CHARACTER): + DEFINE VARIABLE fix AS FixtureDataSet NO-UNDO. DEFINE VARIABLE res AS LOGICAL NO-UNDO. - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - CREATE DATASET dsData. - res = dsData:READ-XML("FILE", path, "EMPTY", ?, ?). + fix = NEW FixtureDataSet(). + res = fix:FromXMLFile(INPUT path). + IF res = TRUE THEN + Fixtures:Add(fix). + ELSE + IF VALID-OBJECT(fix) THEN + DELETE OBJECT fix. RETURN res. END METHOD. @@ -78,10 +126,15 @@ CLASS OEUnit.Data.Fixture: Import fixture data by copying from an existing dataset ----------------------------------------------------------------------------*/ METHOD PUBLIC LOGICAL FromDataSet(INPUT dsSrc AS HANDLE): + DEFINE VARIABLE fix AS FixtureDataSet NO-UNDO. DEFINE VARIABLE res AS LOGICAL NO-UNDO. - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - CREATE DATASET dsData. - res = dsData:COPY-DATASET(dsSrc). + fix = NEW FixtureDataSet(). + res = fix:FromDataSet(INPUT dsSrc). + IF res = TRUE THEN + Fixtures:Add(fix). + ELSE + IF VALID-OBJECT(fix) THEN + DELETE OBJECT fix. RETURN res. END METHOD. @@ -89,42 +142,15 @@ CLASS OEUnit.Data.Fixture: Import fixture data by copying from a temp-table ----------------------------------------------------------------------------*/ METHOD PUBLIC LOGICAL FromTempTable(INPUT ttSrc AS HANDLE): - DEFINE VARIABLE res AS LOGICAL NO-UNDO. - DEFINE VARIABLE ttSrcCpy AS HANDLE NO-UNDO. - DEFINE VARIABLE ttData AS HANDLE NO-UNDO. - DEFINE VARIABLE ttDataBuf AS HANDLE NO-UNDO. - DEFINE VARIABLE hSource AS HANDLE NO-UNDO. - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - CREATE DATASET dsData. - IF NOT VALID-HANDLE(dsData) THEN RETURN FALSE. - CREATE TEMP-TABLE ttData. - res = ttData:COPY-TEMP-TABLE(ttSrc,FALSE,FALSE,FALSE,""). - IF res = FALSE THEN - DO: - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. - RETURN res. - END. - CREATE TEMP-TABLE ttSrcCpy. - res = ttSrcCpy:COPY-TEMP-TABLE(ttSrc,FALSE,FALSE,FALSE,""). - IF res = FALSE THEN - DO: - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. - IF VALID-HANDLE(ttSrcCpy) THEN DELETE OBJECT ttSrcCpy. - RETURN res. - END. - ttDataBuf = ttData:DEFAULT-BUFFER-HANDLE. - dsData:ADD-BUFFER(ttDataBuf). - CREATE DATA-SOURCE hSource. - IF NOT VALID-HANDLE(hSource) THEN - DO: - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - DELETE OBJECT hSource. - END. - hSource:ADD-SOURCE-BUFFER(ttSrcCpy:DEFAULT-BUFFER-HANDLE,?). - ttDataBuf:ATTACH-DATA-SOURCE(hSource). - dsData:FILL(). + DEFINE VARIABLE fix AS FixtureDataSet NO-UNDO. + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + fix = NEW FixtureDataSet(). + res = fix:FromTempTable(INPUT ttSrc). + IF res = TRUE THEN + Fixtures:Add(fix). + ELSE + IF VALID-OBJECT(fix) THEN + DELETE OBJECT fix. RETURN res. END METHOD. @@ -132,41 +158,16 @@ CLASS OEUnit.Data.Fixture: Create data in the attached databases, based on data in dataset tables. ----------------------------------------------------------------------------*/ METHOD PUBLIC LOGICAL CreateData(): - DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO. - DEFINE VARIABLE hQuery AS HANDLE NO-UNDO. - DEFINE VARIABLE hQBuffer AS HANDLE NO-UNDO. - DEFINE VARIABLE hRBuffer AS HANDLE NO-UNDO. - DEFINE VARIABLE iCount AS INTEGER NO-UNDO. - - /* Ensure that any errors are thrown properly */ - DO ON ERROR UNDO, THROW: - IF NOT VALID-HANDLE(dsData) THEN RETURN FALSE. - DO iCount = 1 TO dsData:NUM-TOP-BUFFERS - ON ERROR UNDO, THROW: - hBuffer = dsData:GET-TOP-BUFFER(iCount). - IF NOT VALID-HANDLE(hBuffer) THEN RETURN ERROR NEW FixtureError("Failed to fetch buffer from DataSet"). - IF VALID-HANDLE(hQuery) THEN DELETE OBJECT hQuery. - IF VALID-HANDLE(hQBuffer) THEN DELETE OBJECT hQBuffer. - CREATE BUFFER hQBuffer FOR TABLE hBuffer. - CREATE BUFFER hRBuffer FOR TABLE hBuffer:NAME NO-ERROR. - IF ERROR-STATUS:ERROR THEN RETURN ERROR NEW FixtureError(SUBSTITUTE("Could not create buffer for destination table &1.", hBuffer:NAME)). - CREATE QUERY hQuery. - hQuery:SET-BUFFERS(hQBuffer). /* NOTE: Because this is taken from Dataset, names of tables can overlap and doesn't cause a problem */ - IF(hQuery:QUERY-PREPARE("FOR EACH " + hBuffer:NAME + " NO-LOCK:") = FALSE) THEN - RETURN ERROR NEW FixtureError(SUBSTITUTE("Could not query data in source &1.", hBuffer:NAME)). - hQuery:QUERY-OPEN(). - hQuery:GET-FIRST(NO-LOCK). - DO WHILE NOT hQuery:QUERY-OFF-END - ON ERROR UNDO, THROW: - hRBuffer:BUFFER-CREATE(). - hRBuffer:BUFFER-COPY(hQBuffer). - hRBuffer:BUFFER-RELEASE(). - hQuery:GET-NEXT(). - END. - IF VALID-HANDLE(hRBuffer) THEN DELETE OBJECT hRBuffer. - IF VALID-HANDLE(hQBuffer) THEN DELETE OBJECT hQBuffer. - IF VALID-HANDLE(hQuery) THEN DELETE OBJECT hQuery. - END. + DEFINE VARIABLE fix AS FixtureDataSet NO-UNDO. + DEFINE VARIABLE res AS LOGICAL NO-UNDO. + IF NOT VALID-OBJECT(Fixtures) THEN RETURN FALSE. + res = fixtures:MoveFirst(). + DO WHILE res = TRUE + ON ERROR UNDO, THROW: + fix = CAST(fixtures:CURRENT, "OEUnit.Data.FixtureDataSet"). + IF VALID-OBJECT(fix) THEN + fix:CreateData(). + res = fixtures:MoveNext(). END. END METHOD. diff --git a/src/OEUnit/Tests/Data/FixtureTest.cls b/src/OEUnit/Tests/Data/FixtureTest.cls index 4a5d1b1..af496ae 100644 --- a/src/OEUnit/Tests/Data/FixtureTest.cls +++ b/src/OEUnit/Tests/Data/FixtureTest.cls @@ -13,6 +13,9 @@ CLASS OEUnit.Tests.Data.FixtureTest: FIELD Accepted AS LOGICAL INDEX StatusCode IS PRIMARY UNIQUE StatusCode ASCENDING. + DEFINE PROTECTED TEMP-TABLE ttSecondTestTable NO-UNDO + LIKE ttTestTable. + DEFINE VARIABLE fixture AS Fixture NO-UNDO. @After. @@ -32,6 +35,7 @@ CLASS OEUnit.Tests.Data.FixtureTest: + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}" + "]}"). Assert:AreEqual(fixture:TableCount, 2). + Assert:AreEqual(fixture:Size, 1). END METHOD. @Test. @@ -42,6 +46,7 @@ CLASS OEUnit.Tests.Data.FixtureTest: + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," + "]}"). Assert:AreEqual(fixture:TableCount, 1). + Assert:AreEqual(fixture:Size, 1). fixture:FromJSON("~{ ~"FirstTable~": [" + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," @@ -50,7 +55,8 @@ CLASS OEUnit.Tests.Data.FixtureTest: + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}" + "]}"). - Assert:AreEqual(fixture:TableCount, 2). + Assert:AreEqual(fixture:TableCount, 3). + Assert:AreEqual(fixture:Size, 2). END METHOD. @Test. @@ -72,6 +78,7 @@ CLASS OEUnit.Tests.Data.FixtureTest: + '' + ''). Assert:AreEqual(fixture:TableCount, 2). + Assert:AreEqual(fixture:Size, 1). END METHOD. @Test. @@ -89,6 +96,7 @@ CLASS OEUnit.Tests.Data.FixtureTest: + '' + ''). Assert:AreEqual(fixture:TableCount, 1). + Assert:AreEqual(fixture:Size, 1). fixture:FromXML('' + '' + '' @@ -104,7 +112,8 @@ CLASS OEUnit.Tests.Data.FixtureTest: + 'true' + '' + ''). - Assert:AreEqual(fixture:TableCount, 2). + Assert:AreEqual(fixture:TableCount, 3). + Assert:AreEqual(fixture:Size, 2). END METHOD. @Test. @@ -141,6 +150,7 @@ CLASS OEUnit.Tests.Data.FixtureTest: hdSet:FILL(). fixture:FromDataSet(hdSet). Assert:AreEqual(fixture:TableCount, 1). + Assert:AreEqual(fixture:Size, 1). END METHOD. /* @@ -194,5 +204,37 @@ CLASS OEUnit.Tests.Data.FixtureTest: fixture:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). Assert:AreEqual(fixture:TableCount,1). + Assert:AreEqual(fixture:Size, 1). END. + + @Test. + METHOD PUBLIC VOID FromTempTable_Multiple(): + fixture = NEW Fixture(). + EMPTY TEMP-TABLE ttTestTable. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "NEW" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "ACCEPTED" + ttTestTable.Accepted = TRUE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "PICKING" + ttTestTable.Accepted = FALSE. + CREATE ttTestTable. + ASSIGN ttTestTable.StatusCode = "POSTED" + ttTestTable.Accepted = FALSE. + fixture:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). + Assert:AreEqual(fixture:TableCount, 1). + Assert:AreEqual(fixture:Size, 1). + EMPTY TEMP-TABLE ttSecondTestTable. + CREATE ttSecondTestTable. + ASSIGN ttSecondTestTable.StatusCode = "NEW" + ttSecondTestTable.Accepted = TRUE. + CREATE ttSecondTestTable. + ASSIGN ttSecondTestTable.StatusCode = "ACCEPTED" + ttSecondTestTable.Accepted = TRUE. + fixture:FromTempTable(TEMP-TABLE ttSecondTestTable:HANDLE). + Assert:AreEqual(fixture:TableCount, 2). + Assert:AreEqual(fixture:Size, 2). + END METHOD. END CLASS. \ No newline at end of file From 78e07c51f8eb73cc23c0b1f255d1526cac1d852e Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Mon, 22 Dec 2014 11:37:55 +0000 Subject: [PATCH 22/33] Change name of several tests for Fixture class to better reflect their purpose after the refactoring of Fixture for multiple Data Sets. --- src/OEUnit/Tests/Data/FixtureTest.cls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OEUnit/Tests/Data/FixtureTest.cls b/src/OEUnit/Tests/Data/FixtureTest.cls index af496ae..34075d0 100644 --- a/src/OEUnit/Tests/Data/FixtureTest.cls +++ b/src/OEUnit/Tests/Data/FixtureTest.cls @@ -39,7 +39,7 @@ CLASS OEUnit.Tests.Data.FixtureTest: END METHOD. @Test. - METHOD PUBLIC VOID FromJSON_Reset(): + METHOD PUBLIC VOID FromJSON_Multiple(): fixture = NEW Fixture(). fixture:FromJSON("~{ ~"FirstTable~": [" + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," @@ -82,7 +82,7 @@ CLASS OEUnit.Tests.Data.FixtureTest: END METHOD. @Test. - METHOD PUBLIC VOID FromXML_Reset(): + METHOD PUBLIC VOID FromXML_Multiple(): fixture = NEW Fixture(). fixture:FromXML('' + '' From 78e13b3c854015e0fc3769ee7e1805eabbb6853b Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Mon, 22 Dec 2014 11:41:39 +0000 Subject: [PATCH 23/33] Remove unrequired dsData property from Fixture class --- src/OEUnit/Data/Fixture.cls | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/OEUnit/Data/Fixture.cls b/src/OEUnit/Data/Fixture.cls index 2774ce2..bf0dd84 100644 --- a/src/OEUnit/Data/Fixture.cls +++ b/src/OEUnit/Data/Fixture.cls @@ -12,7 +12,6 @@ ROUTINE-LEVEL ON ERROR UNDO, THROW. CLASS OEUnit.Data.Fixture: - DEFINE PROTECTED VARIABLE dsData AS HANDLE NO-UNDO. DEFINE PROTECTED VARIABLE Fixtures AS List NO-UNDO. /*---------------------------------------------------------------------------- @@ -34,8 +33,7 @@ CLASS OEUnit.Data.Fixture: END. RETURN tCount. END. - IF VALID-HANDLE(dsData) THEN RETURN dsData:NUM-TOP-BUFFERS. - ELSE RETURN 0. + RETURN 0. END GET. /*---------------------------------------------------------------------------- @@ -54,7 +52,6 @@ CLASS OEUnit.Data.Fixture: END CONSTRUCTOR. DESTRUCTOR PUBLIC Fixture(): - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. IF VALID-OBJECT(Fixtures) THEN DELETE OBJECT Fixtures. END DESTRUCTOR. From eb1a513ef8e24610b95c8f6a051ba95668b3ee07 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Mon, 22 Dec 2014 12:45:44 +0000 Subject: [PATCH 24/33] Refactor unit tests for Fixture class, and implement test for multiple Data Sets --- src/OEUnit/Tests/Data/FixtureTest.cls | 78 +++++++++++++++------------ 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/src/OEUnit/Tests/Data/FixtureTest.cls b/src/OEUnit/Tests/Data/FixtureTest.cls index 34075d0..74c47c8 100644 --- a/src/OEUnit/Tests/Data/FixtureTest.cls +++ b/src/OEUnit/Tests/Data/FixtureTest.cls @@ -116,46 +116,36 @@ CLASS OEUnit.Tests.Data.FixtureTest: Assert:AreEqual(fixture:Size, 2). END METHOD. - @Test. - METHOD PUBLIC VOID FromDataSet(): + METHOD PROTECTED HANDLE CreateDataSetFromTempTable(INPUT httTest AS HANDLE): - DEFINE VARIABLE httTest AS HANDLE NO-UNDO. DEFINE VARIABLE hdSet AS HANDLE NO-UNDO. DEFINE VARIABLE htt AS HANDLE NO-UNDO. DEFINE VARIABLE hdSource AS HANDLE NO-UNDO. DEFINE VARIABLE httBuffer AS HANDLE NO-UNDO. - - fixture = NEW Fixture(). - EMPTY TEMP-TABLE ttTestTable. - CREATE ttTestTable. - ASSIGN ttTestTable.StatusCode = "NEW" - ttTestTable.Accepted = TRUE. - CREATE ttTestTable. - ASSIGN ttTestTable.StatusCode = "ACCEPTED" - ttTestTable.Accepted = TRUE. - - ASSIGN httTest = TEMP-TABLE ttTestTable:HANDLE. - + DEFINE VARIABLE httTestBuf AS HANDLE NO-UNDO. + CREATE TEMP-TABLE htt. htt:COPY-TEMP-TABLE(httTest, FALSE, TRUE). - - httBuffer = htt:DEFAULT-BUFFER-HANDLE. + + /* Create buffers for temp-tables */ + CREATE BUFFER httBuffer FOR TABLE htt. + CREATE BUFFER httTestBuf FOR TABLE httTest. CREATE DATASET hdSet. hdSet:ADD-BUFFER(httBuffer). CREATE DATA-SOURCE hdSource. - hdSource:ADD-SOURCE-BUFFER(httTest:DEFAULT-BUFFER-HANDLE,?). + hdSource:ADD-SOURCE-BUFFER(httTestBuf,?). httBuffer:ATTACH-DATA-SOURCE(hdSource). hdSet:FILL(). - fixture:FromDataSet(hdSet). - Assert:AreEqual(fixture:TableCount, 1). - Assert:AreEqual(fixture:Size, 1). + + RETURN hdSet. END METHOD. - /* + @Test. - METHOD PUBLIC VOID FromTempTable_Reset(): + METHOD PUBLIC VOID FromDataSet(): + fixture = NEW Fixture(). EMPTY TEMP-TABLE ttTestTable. CREATE ttTestTable. @@ -164,14 +154,20 @@ CLASS OEUnit.Tests.Data.FixtureTest: CREATE ttTestTable. ASSIGN ttTestTable.StatusCode = "ACCEPTED" ttTestTable.Accepted = TRUE. - CREATE ttTestTable. - ASSIGN ttTestTable.StatusCode = "PICKING" - ttTestTable.Accepted = FALSE. - CREATE ttTestTable. - ASSIGN ttTestTable.StatusCode = "POSTED" - ttTestTable.Accepted = FALSE. - fixture:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). - /*Assert:AreEqual(fixture:Size, 4).*/ + + fixture:FromDataSet(CreateDataSetFromTempTable(INPUT TEMP-TABLE ttTestTable:HANDLE)). + Assert:AreEqual(fixture:TableCount, 1). + Assert:AreEqual(fixture:Size, 1). + + END METHOD. + + @Test. + METHOD PUBLIC VOID FromDataSet_Multiple(): + + DEFINE BUFFER ttBufTestTable FOR ttTestTable. + DEFINE BUFFER ttSecondTestTable FOR ttSecondTestTable. + + fixture = NEW Fixture(). EMPTY TEMP-TABLE ttTestTable. CREATE ttTestTable. ASSIGN ttTestTable.StatusCode = "NEW" @@ -179,10 +175,24 @@ CLASS OEUnit.Tests.Data.FixtureTest: CREATE ttTestTable. ASSIGN ttTestTable.StatusCode = "ACCEPTED" ttTestTable.Accepted = TRUE. - fixture:FromTempTable(TEMP-TABLE ttTestTable:HANDLE). - /*Assert:AreEqual(fixture:Size, 2).*/ + + fixture:FromDataSet(CreateDataSetFromTempTable(INPUT TEMP-TABLE ttBufTestTable:HANDLE)). + Assert:AreEqual(fixture:TableCount, 1). + Assert:AreEqual(fixture:Size, 1). + + EMPTY TEMP-TABLE ttSecondTestTable. + CREATE ttSecondTestTable. + ASSIGN ttSecondTestTable.StatusCode = "NEW" + ttSecondTestTable.Accepted = TRUE. + CREATE ttSecondTestTable. + ASSIGN ttSecondTestTable.StatusCode = "ACCEPTED" + ttSecondTestTable.Accepted = TRUE. + + fixture:FromDataSet(CreateDataSetFromTempTable(INPUT TEMP-TABLE ttSecondTestTable:HANDLE)). + Assert:AreEqual(fixture:TableCount, 2). + Assert:AreEqual(fixture:Size, 2). + END METHOD. - */ @Test. METHOD PUBLIC VOID FromTempTable(): From 3926d7d633b9d091adda43c5dfe7d5c6d5e0c411 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Mon, 22 Dec 2014 13:18:00 +0000 Subject: [PATCH 25/33] Resolve issue with incorrect class used in FixtureDataSetTest --- src/OEUnit/Tests/Data/FixtureDataSetTest.cls | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/OEUnit/Tests/Data/FixtureDataSetTest.cls b/src/OEUnit/Tests/Data/FixtureDataSetTest.cls index e1bbbff..a7ed3e0 100644 --- a/src/OEUnit/Tests/Data/FixtureDataSetTest.cls +++ b/src/OEUnit/Tests/Data/FixtureDataSetTest.cls @@ -4,7 +4,7 @@ ROUTINE-LEVEL ON ERROR UNDO, THROW. USING Progress.Lang.*. USING OEUnit.Tests.Data.*. USING OEUnit.Assertion.Assert. -USING OEUnit.Data.Fixture. +USING OEUnit.Data.FixtureDataSet. CLASS OEUnit.Tests.Data.FixtureDataSetTest: @@ -13,16 +13,16 @@ CLASS OEUnit.Tests.Data.FixtureDataSetTest: FIELD Accepted AS LOGICAL INDEX StatusCode IS PRIMARY UNIQUE StatusCode ASCENDING. - DEFINE VARIABLE fixture AS Fixture NO-UNDO. + DEFINE VARIABLE fixture AS FixtureDataSet NO-UNDO. @After. - METHOD PUBLIC VOID DeleteFixture(): + METHOD PUBLIC VOID DeleteFixtureDataSet(): DELETE OBJECT fixture NO-ERROR. END METHOD. @Test. METHOD PUBLIC VOID FromJSON(): - fixture = NEW Fixture(). + fixture = NEW FixtureDataSet(). fixture:FromJSON("~{ ~"FirstTable~": [" + " ~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + " ~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," @@ -36,7 +36,7 @@ CLASS OEUnit.Tests.Data.FixtureDataSetTest: @Test. METHOD PUBLIC VOID FromJSON_Reset(): - fixture = NEW Fixture(). + fixture = NEW FixtureDataSet(). fixture:FromJSON("~{ ~"FirstTable~": [" + "~{ ~"name~": ~"Char Value~", ~"intvalue~": 0, ~"bool~": true, ~"nullvalue~": null}," + "~{ ~"name~": ~"Next Value~", ~"intvalue~": 15, ~"bool~": false, ~"nullvalue~": 0}," @@ -55,7 +55,7 @@ CLASS OEUnit.Tests.Data.FixtureDataSetTest: @Test. METHOD PUBLIC VOID FromXML(): - fixture = NEW Fixture(). + fixture = NEW FixtureDataSet(). fixture:FromXML('' + '' + '' @@ -76,7 +76,7 @@ CLASS OEUnit.Tests.Data.FixtureDataSetTest: @Test. METHOD PUBLIC VOID FromXML_Reset(): - fixture = NEW Fixture(). + fixture = NEW FixtureDataSet(). fixture:FromXML('' + '' + '' @@ -116,7 +116,7 @@ CLASS OEUnit.Tests.Data.FixtureDataSetTest: DEFINE VARIABLE hdSource AS HANDLE NO-UNDO. DEFINE VARIABLE httBuffer AS HANDLE NO-UNDO. - fixture = NEW Fixture(). + fixture = NEW FixtureDataSet(). EMPTY TEMP-TABLE ttTestTable. CREATE ttTestTable. ASSIGN ttTestTable.StatusCode = "NEW" @@ -146,7 +146,7 @@ CLASS OEUnit.Tests.Data.FixtureDataSetTest: /* @Test. METHOD PUBLIC VOID FromTempTable_Reset(): - fixture = NEW Fixture(). + fixture = NEW FixtureDataSet(). EMPTY TEMP-TABLE ttTestTable. CREATE ttTestTable. ASSIGN ttTestTable.StatusCode = "NEW" @@ -183,7 +183,7 @@ CLASS OEUnit.Tests.Data.FixtureDataSetTest: DEFINE VARIABLE hdSource AS HANDLE NO-UNDO. DEFINE VARIABLE httBuffer AS HANDLE NO-UNDO. - fixture = NEW Fixture(). + fixture = NEW FixtureDataSet(). EMPTY TEMP-TABLE ttTestTable. CREATE ttTestTable. ASSIGN ttTestTable.StatusCode = "NEW" From 4f757b549221a6b86a1049db95f0bdb043c70712 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Mon, 22 Dec 2014 15:40:07 +0000 Subject: [PATCH 26/33] Ensure that a transaction is in place before using fixture data --- src/OEUnit/Runners/OEUnitRunner.cls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OEUnit/Runners/OEUnitRunner.cls b/src/OEUnit/Runners/OEUnitRunner.cls index 22acd72..f41e7b8 100644 --- a/src/OEUnit/Runners/OEUnitRunner.cls +++ b/src/OEUnit/Runners/OEUnitRunner.cls @@ -237,7 +237,7 @@ CLASS OEUnit.Runners.OEUnitRunner INHERITS BaseRunner: currentResult:AddResult(methodResult). IF ShouldRun(testMethod) THEN DO ON ERROR UNDO, THROW: NotifyOfTestStart(testMethod). - IF testFixture NE ? AND VALID-OBJECT(testFixture) THEN testFixture:CreateData(). + IF testFixture NE ? AND VALID-OBJECT(testFixture) AND TRANSACTION THEN testFixture:CreateData(). ETIME(TRUE). RunBefores(currentInfo:GetAnnotatedMethods(OEUnitAnnotations:Before)). ETIME(TRUE). From ef8db7061f78add72207627e95cf362de08375fc Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Mon, 22 Dec 2014 15:42:12 +0000 Subject: [PATCH 27/33] Add documentation for fixtures --- doc/changelog.html | 1 + doc/dataprovider.html | 1 + doc/fixtures.html | 233 ++++++++++++++++++++++++++++++++++++++++ doc/index.html | 1 + doc/installation.html | 1 + doc/reportingtests.html | 1 + doc/runningtests.html | 1 + doc/testcase.html | 1 + doc/testsuite.html | 1 + 9 files changed, 241 insertions(+) create mode 100644 doc/fixtures.html diff --git a/doc/changelog.html b/doc/changelog.html index 8904116..c050652 100644 --- a/doc/changelog.html +++ b/doc/changelog.html @@ -17,6 +17,7 @@

    OEUnit - Unit Testing Framework

  • Running a Test
  • Reporting Test Results
  • DataProviders
  • +
  • Fixtures
  • License
  • Change Log
  • diff --git a/doc/dataprovider.html b/doc/dataprovider.html index 8112932..a4fe201 100644 --- a/doc/dataprovider.html +++ b/doc/dataprovider.html @@ -17,6 +17,7 @@

    OEUnit - Unit Testing Framework

  • Running a Test
  • Reporting Test Results
  • DataProviders
  • +
  • Fixtures
  • License
  • Change Log
  • diff --git a/doc/fixtures.html b/doc/fixtures.html new file mode 100644 index 0000000..ac335a1 --- /dev/null +++ b/doc/fixtures.html @@ -0,0 +1,233 @@ + + + + + OEUnit - Fixtures + + + + + + + +

    + Fixtures +

    +

    What are Fixtures?

    +

    + A fixture is an object that inserts, or creates, data into one or more database tables before + a unit test is run. At the end of the test, the fixture data is removed.
    +
    + A test method declares that is requires a Fixture when it is defined, using the fixture + attribute, supplying the name of a fixture class method as the attribute value.
    +
    + A class method is defined in the test case, with the @Fixture + annotation, with an optional name attribute. This method returns an object of type + OEUnit.Data.Fixture which will contain the data to be loaded into a database when required. +

    +

    How to use a Fixture

    +

    + 1. Define a test method, using the fixture attribute to specify the name of a class method + which will provide a fixture object.
    + For example:

    +
     ROUTINE-LEVEL ON ERROR UNDO, THROW.
    +
    + USING OEUnit.Assertion.Assert.
    + USING OEUnit.Data.Fixture.
    +
    + CLASS SimpleTest:
    +   
    +   @Test (fixture=OrderStatusFixture). 
    +   METHOD PUBLIC VOID AcceptStatusChange(): 
    +     DEFINE VARIABLE result AS LOGICAL NO-UNDO.
    +     FIND FIRST Order 
    +          WHERE Order.Status = "NEW" NO-LOCK NO-ERROR.
    +     Order:OpenOrder(Order.OrderNo).
    +     result = Order:ChangeStatus(INPUT "ACCEPTED"). 
    +     Assert:AreEqual(result,TRUE).
    +   END METHOD.    
    +
    + END CLASS.
    +

    +
    + 2. Add a method to the class which returns an OEUnit.Data.Fixture object.
    + Use the @Fixture annotation to indicate that the class is a Fixture method.
    + For example:

    +
       @Fixture. 
    +   METHOD PUBLIC Fixture OrderStatusFixture(): 
    +     DEFINE VARIABLE fixture AS Fixture NO-UNDO.
    +     fixture = NEW Fixture().
    +     fixture:FromJSON("~{ ~"Order~": ["
    +                      + "~{ ~"OrderNo~": ~"10000~", ~"CustomerNo~": 99000, ~"Status~": ~"COMPLETED~"},"
    +                      + "~{ ~"OrderNo~": ~"10001~", ~"CustomerNo~": 99001, ~"Status~": ~"CANCELLED~"},"
    +                      + "~{ ~"OrderNo~": ~"10002~", ~"CustomerNo~": 99002, ~"Status~": ~"COMPLETED~"},"
    +                      + "~{ ~"OrderNo~": ~"10003~", ~"CustomerNo~": 99000, ~"Status~": ~"NEW~"},
    +                      + "~{ ~"OrderNo~": ~"10004~", ~"CustomerNo~": 99003, ~"Status~": ~"ACCEPTED~"},"
    +                      + "~{ ~"OrderNo~": ~"10005~", ~"CustomerNo~": 99004, ~"Status~": ~"PAID~"},"
    +                      + "]}").
    +     RETURN fixture.
    +   END METHOD.

    + +
    + Important Notes:

    +
      +
    • The name of the Fixture class method must match the value of the fixture + attribute on the test method, or the @Fixture annotation must + have a name attribute which matches the value of the fixture + attribute on the test method.
    • +
    • Execution of a Fixture method will stop when an assertion fails or a Progress.Lang.Error + is thrown.
    • +
    • There are no special naming requirements for Fixture methods.
    • +
    • Fixture methods must be PUBLIC
    • +
    • Fixture methods must accept no parameters.
    • +
    • Fixture methods can be STATIC.
    • +
    • Fixture methods can be used by more than one test method.
    • +
    • A transaction is created before the records provided in the fixture are loaded, and is rolled-back + after the test method returns.
    • +
    +

    +
    + 3. Run the test case as per normal.

    +

    + +

    Name Attribute

    +

    + Each method annotated with @Fixture can specify a name attribute which is used + when searching for a Fixture method, instead of the method name. +

    +

    + Syntax:

    +

    +

       @Fixture[(name="FixtureName")].

    +

    + FixtureName
    +     The Name of the Fixture. This name can then be specified by + a test method as its Fixture, in the fixture attribute
    +

    +

    + +
    + Example:
    +

    +
       @Test (dataProvider=OrderStatusFixture). 
    +   METHOD PUBLIC VOID AcceptStatusChange(): 
    +     DEFINE VARIABLE result AS LOGICAL NO-UNDO.
    +     FIND FIRST Order 
    +          WHERE Order.Status = "NEW" NO-LOCK NO-ERROR.
    +     Order:OpenOrder(Order.OrderNo).
    +     result = Order:ChangeStatus(INPUT "ACCEPTED"). 
    +     Assert:AreEqual(result,TRUE).
    +   END METHOD. 
    +   
    +   @Fixture (name=OrderStatusFixture). 
    +   METHOD PUBLIC Fixture myFixture(): 
    +     DEFINE VARIABLE fixture AS Fixture NO-UNDO.
    +     fixture = NEW Fixture().
    +     fixture:FromJSON("~{ ~"Order~": ["
    +                      + "~{ ~"OrderNo~": ~"10000~", ~"CustomerNo~": 99000, ~"Status~": ~"COMPLETED~"},"
    +                      + "~{ ~"OrderNo~": ~"10001~", ~"CustomerNo~": 99001, ~"Status~": ~"CANCELLED~"},"
    +                      + "~{ ~"OrderNo~": ~"10002~", ~"CustomerNo~": 99002, ~"Status~": ~"COMPLETED~"},"
    +                      + "~{ ~"OrderNo~": ~"10003~", ~"CustomerNo~": 99000, ~"Status~": ~"NEW~"},"
    +                      + "~{ ~"OrderNo~": ~"10004~", ~"CustomerNo~": 99003, ~"Status~": ~"ACCEPTED~"},"
    +                      + "~{ ~"OrderNo~": ~"10005~", ~"CustomerNo~": 99004, ~"Status~": ~"PAID~"},"
    +                      + "]}").
    +     RETURN fixture.
    +   END METHOD.
    +

    Fixture Methods

    +

    The Fixture class provides a range of methods for loading data into the Fixture.

    +

    Each successive call to one of these methods defines a range of data to be loaded. When + the records are loaded, they are done so in the order that they are specified to the Fixture + object.

    +

    METHOD PUBLIC LOGICAL FromJSON(INPUT json AS LONGCHAR)

    +

    This method is used to load data from JSON text stored in a LONGCHAR.

    +

    + +
    + Notes:

    +
      +
    • The structure of the JSON data should match that which is accepted by an OpenEdge DATASET + when using the READ-JSON method.
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    • Only data in the top-level objects in the JSON data will be loaded. Child objects are ignored.
    • +
    +

    METHOD PUBLIC LOGICAL FromJSONFile(INPUT path AS CHARACTER):

    +

    This method is used to load data from JSON text stored in a file. The file path should be provided as the + INPUT parameter.

    +

    + +
    + Notes:

    +
      +
    • The structure of the JSON data in the file should match that which is accepted by an OpenEdge + DATASET when using the READ-JSON method.
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    • Only data in the top-level objects in the JSON data will be loaded. Child objects are ignored.
    • +
    +

    METHOD PUBLIC LOGICAL FromXML(INPUT xml AS LONGCHAR)

    +

    This method is used to load data from XML data stored in a LONGCHAR.

    +

    + +
    + Notes:

    +
      +
    • The structure of the XML data should match that which is accepted by an OpenEdge DATASET + when using the READ-XML method.
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    • It is advised to specify the XML Schema in the XML data in order for data types to be correctly interpreted.
    • +
    • Only data in the top-level objects in the XML data will be loaded. Child objects are ignored.
    • +
    +

    METHOD PUBLIC LOGICAL FromXMLFile(INPUT path AS CHARACTER):

    +

    This method is used to load data from XML data stored in a file. The file path should be provided as the + INPUT parameter.

    +

    + +
    + Notes:

    +
      +
    • The structure of the XML data in the file should match that which is accepted by an OpenEdge + DATASET when using the READ-XML method.
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    • It is advised to specify the XML Schema in the XML data in order for data types to be correctly interpreted.
    • +
    • Only data in the top-level objects in the XML data will be loaded. Child objects are ignored.
    • +
    +

    METHOD PUBLIC LOGICAL FromTempTable(INPUT ttSrc AS HANDLE):

    +

    This method is used to load data from an existing temp-table, via the provided HANDLE INPUT parameter.

    +

    + +
    + Notes:

    +
      +
    • The entire data and metaschema of the temp-table are copied.
    • +
    • Data is copied in EMPTY mode
    • +
    • The data and metaschema of the provided source temp-table are not affected.
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    +

    METHOD PUBLIC LOGICAL FromDataSet(INPUT dsSrc AS HANDLE):

    +

    This method is used to load data from an existing DataSet, via the provided HANDLE INPUT parameter.

    +

    + +
    + Notes:

    +
      +
    • The entire data and metaschema of the temp-table are copied.
    • +
    • Data is copied in EMPTY mode
    • +
    • The method will return TRUE if the data was successfully loaded.
    • +
    + + + diff --git a/doc/index.html b/doc/index.html index e9b274f..f711665 100644 --- a/doc/index.html +++ b/doc/index.html @@ -17,6 +17,7 @@

    OEUnit - Unit Testing Framework

  • Running a Test
  • Reporting Test Results
  • DataProviders
  • +
  • Fixtures
  • License
  • Change Log
  • diff --git a/doc/installation.html b/doc/installation.html index 7e64c7c..b53f69c 100644 --- a/doc/installation.html +++ b/doc/installation.html @@ -17,6 +17,7 @@

    OEUnit - Unit Testing Framework

  • Running a Test
  • Reporting Test Results
  • DataProviders
  • +
  • Fixtures
  • License
  • Change Log
  • diff --git a/doc/reportingtests.html b/doc/reportingtests.html index 0863687..cdadad8 100644 --- a/doc/reportingtests.html +++ b/doc/reportingtests.html @@ -17,6 +17,7 @@

    OEUnit - Unit Testing Framework

  • Running a Test
  • Reporting Test Results
  • DataProviders
  • +
  • Fixtures
  • License
  • Change Log
  • diff --git a/doc/runningtests.html b/doc/runningtests.html index 5f42b1a..15f4629 100644 --- a/doc/runningtests.html +++ b/doc/runningtests.html @@ -17,6 +17,7 @@

    OEUnit - Unit Testing Framework

  • Running a Test
  • Reporting Test Results
  • DataProviders
  • +
  • Fixtures
  • License
  • Change Log
  • diff --git a/doc/testcase.html b/doc/testcase.html index f8d7174..166c2b6 100644 --- a/doc/testcase.html +++ b/doc/testcase.html @@ -17,6 +17,7 @@

    OEUnit - Unit Testing Framework

  • Running a Test
  • Reporting Test Results
  • DataProviders
  • +
  • Fixtures
  • License
  • Change Log
  • diff --git a/doc/testsuite.html b/doc/testsuite.html index a0af385..12c3785 100644 --- a/doc/testsuite.html +++ b/doc/testsuite.html @@ -17,6 +17,7 @@

    OEUnit - Unit Testing Framework

  • Running a Test
  • Reporting Test Results
  • DataProviders
  • +
  • Fixtures
  • License
  • Change Log
  • From cdc28f7d6f45c0d06153726b630ab275960716c2 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Tue, 23 Dec 2014 11:06:41 +0000 Subject: [PATCH 28/33] Resolve issue with Fixture datasets when loaded from Temp-Tables where data would be loaded twice. --- src/OEUnit/Data/FixtureDataSet.cls | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/OEUnit/Data/FixtureDataSet.cls b/src/OEUnit/Data/FixtureDataSet.cls index 92c73d3..ad4698f 100644 --- a/src/OEUnit/Data/FixtureDataSet.cls +++ b/src/OEUnit/Data/FixtureDataSet.cls @@ -90,14 +90,15 @@ CLASS OEUnit.Data.FixtureDataSet: ----------------------------------------------------------------------------*/ METHOD PUBLIC LOGICAL FromTempTable(INPUT ttSrc AS HANDLE): DEFINE VARIABLE res AS LOGICAL NO-UNDO. - DEFINE VARIABLE ttSrcCpy AS HANDLE NO-UNDO. DEFINE VARIABLE ttData AS HANDLE NO-UNDO. DEFINE VARIABLE ttDataBuf AS HANDLE NO-UNDO. - DEFINE VARIABLE hSource AS HANDLE NO-UNDO. IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. CREATE DATASET dsData. IF NOT VALID-HANDLE(dsData) THEN RETURN FALSE. CREATE TEMP-TABLE ttData. + /* COPY-TEMP-TABLE will also copy data as well, and hence there + * is no need to configure data sources and call DataSet:Fill() + */ res = ttData:COPY-TEMP-TABLE(ttSrc,FALSE,FALSE,FALSE,""). IF res = FALSE THEN DO: @@ -105,27 +106,9 @@ CLASS OEUnit.Data.FixtureDataSet: IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. RETURN res. END. - CREATE TEMP-TABLE ttSrcCpy. - res = ttSrcCpy:COPY-TEMP-TABLE(ttSrc,FALSE,FALSE,FALSE,""). - IF res = FALSE THEN - DO: - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - IF VALID-HANDLE(ttData) THEN DELETE OBJECT ttData. - IF VALID-HANDLE(ttSrcCpy) THEN DELETE OBJECT ttSrcCpy. - RETURN res. - END. ttDataBuf = ttData:DEFAULT-BUFFER-HANDLE. dsData:ADD-BUFFER(ttDataBuf). - CREATE DATA-SOURCE hSource. - IF NOT VALID-HANDLE(hSource) THEN - DO: - IF VALID-HANDLE(dsData) THEN DELETE OBJECT dsData. - DELETE OBJECT hSource. - END. - hSource:ADD-SOURCE-BUFFER(ttSrcCpy:DEFAULT-BUFFER-HANDLE,?). - ttDataBuf:ATTACH-DATA-SOURCE(hSource). - dsData:FILL(). - RETURN res. + RETURN TRUE. END METHOD. /*---------------------------------------------------------------------------- @@ -163,6 +146,7 @@ CLASS OEUnit.Data.FixtureDataSet: hRBuffer:BUFFER-RELEASE(). hQuery:GET-NEXT(). END. + hQuery:QUERY-CLOSE(). IF VALID-HANDLE(hRBuffer) THEN DELETE OBJECT hRBuffer. IF VALID-HANDLE(hQBuffer) THEN DELETE OBJECT hQBuffer. IF VALID-HANDLE(hQuery) THEN DELETE OBJECT hQuery. From 172a443f53bb87609a8d99e6da4ee6af849d2987 Mon Sep 17 00:00:00 2001 From: Mark Abbott Date: Wed, 21 Jan 2015 16:01:48 +0000 Subject: [PATCH 29/33] Add checks to ensure that Fixture data is only created when required, and to ensure that the Fixture object is closed down when no longer needed. --- src/OEUnit/Runners/OEUnitRunner.cls | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/OEUnit/Runners/OEUnitRunner.cls b/src/OEUnit/Runners/OEUnitRunner.cls index f41e7b8..cda5cd8 100644 --- a/src/OEUnit/Runners/OEUnitRunner.cls +++ b/src/OEUnit/Runners/OEUnitRunner.cls @@ -211,17 +211,22 @@ CLASS OEUnit.Runners.OEUnitRunner INHERITS BaseRunner: ----------------------------------------------------------------------------*/ METHOD PROTECTED VOID RunTestMethod(INPUT testMethod AS MethodInfo, INPUT paramList AS Progress.Lang.ParameterList): - IF testMethod:RequiresFixture() THEN + DEFINE VARIABLE fix AS Fixture NO-UNDO. + + IF testMethod:RequiresFixture() AND ShouldRun(testMethod) THEN DO: OEUnitFixtureTransaction: - DO TRANSACTION - ON ERROR UNDO, THROW: - RunTestMethod(INPUT testMethod, testMethod:GetFixture(), INPUT paramList). + DO TRANSACTION ON ERROR UNDO, THROW: + fix = testMethod:GetFixture(). + RunTestMethod(INPUT testMethod, INPUT fix, INPUT paramList). UNDO OEUnitFixtureTransaction, LEAVE OEUnitFixtureTransaction. END. + DELETE OBJECT fix NO-ERROR. END. - ELSE + ELSE + DO: RunTestMethod(INPUT testMethod, INPUT ?, INPUT paramList). + END. END METHOD. /*---------------------------------------------------------------------------- @@ -247,6 +252,7 @@ CLASS OEUnit.Runners.OEUnitRunner INHERITS BaseRunner: methodResult:AddError(err). END CATCH. FINALLY: + IF VALID-OBJECT(testFixture) THEN DELETE OBJECT testFixture. methodResult:SetDuration(ETIME). RunAfters(currentInfo:GetAnnotatedMethods(OEUnitAnnotations:After), methodResult). NotifyOfTestFinish(methodResult). From 1876ceb5c4d3656d945afe3571fc939d2588d2b5 Mon Sep 17 00:00:00 2001 From: Lieven De Foor Date: Mon, 30 Nov 2015 11:44:35 +0100 Subject: [PATCH 30/33] Apply workaround for issue #15 since Progress changed something in OpenEdge 11.5/11.6 causing error 2780 when trying to run a test. --- src/OEUnit/UI/ResultsWindowView.cls | 113 +++++++++++++++------------- 1 file changed, 62 insertions(+), 51 deletions(-) diff --git a/src/OEUnit/UI/ResultsWindowView.cls b/src/OEUnit/UI/ResultsWindowView.cls index f0851ab..bf1d326 100644 --- a/src/OEUnit/UI/ResultsWindowView.cls +++ b/src/OEUnit/UI/ResultsWindowView.cls @@ -2,7 +2,7 @@ File : ResultsWindowView.cls Package : OEUnit.UI Description : Results view for windows based user-interfaces (GUI). Displays - results in a window that can be docked in Progress Developer + results in a window that can be docked in Progress Developer Studio. ------------------------------------------------------------------------------*/ @@ -16,38 +16,43 @@ CLASS OEUnit.UI.ResultsWindowView IMPLEMENTS IResultsView: /*---------------------------------------------------------------------------- Test Result and Error Temp-Tables - ----------------------------------------------------------------------------*/ + ----------------------------------------------------------------------------*/ {OEUnit/UI/ttTestResult.i &access = "STATIC"} {OEUnit/UI/ttError.i &access = "STATIC"} /*---------------------------------------------------------------------------- Total number of records in the ttTestResult temp-table. - ----------------------------------------------------------------------------*/ + ----------------------------------------------------------------------------*/ DEFINE PRIVATE STATIC VARIABLE testCount AS INTEGER NO-UNDO. - + /*---------------------------------------------------------------------------- Store the details of the last test run - so it may be easily rerun. - ----------------------------------------------------------------------------*/ + ----------------------------------------------------------------------------*/ DEFINE PRIVATE STATIC VARIABLE lastClassFile AS CHARACTER NO-UNDO. DEFINE PRIVATE STATIC VARIABLE lastClassName AS CHARACTER NO-UNDO. DEFINE PRIVATE STATIC VARIABLE lastMethodName AS CHARACTER NO-UNDO. - + /*---------------------------------------------------------------------------- - Handle to the persistently run ResultsWindow procedure. + Handle to the persistently run ResultsWindow procedure. + Never directly use this variable, except from GetResultsWindow() ----------------------------------------------------------------------------*/ DEFINE PRIVATE STATIC VARIABLE resultWindow AS HANDLE NO-UNDO. - DEFINE PRIVATE STATIC PROPERTY ResultsWindow AS HANDLE NO-UNDO - GET: + + /*---------------------------------------------------------------------------- + We can't use a property to get the resultWindow, since that somehow triggers + a WAIT-FOR condition, which causes errors later on... + ----------------------------------------------------------------------------*/ + METHOD PRIVATE STATIC VOID GetResultsWindow(OUTPUT resultsWindow AS HANDLE): IF NOT(VALID-HANDLE(resultWindow)) THEN RUN OEUnit/UI/ResultsWindow.w PERSISTENT SET resultWindow. - RETURN resultWindow. - END GET. + ASSIGN resultsWindow = resultWindow. + END METHOD. /*---------------------------------------------------------------------------- Run the given file as a test. Must be a valid class file (.cls). - ----------------------------------------------------------------------------*/ + ----------------------------------------------------------------------------*/ METHOD PUBLIC STATIC VOID RunAsTest(INPUT classFileName AS CHARACTER): - ASSIGN + ASSIGN lastClassName = "" lastMethodName = "" lastClassFile = classFileName. @@ -55,16 +60,16 @@ CLASS OEUnit.UI.ResultsWindowView IMPLEMENTS IResultsView: ResultsPresenter:RunAsTest(classFileName). CATCH e AS Progress.Lang.Error : DisplayError(classFileName, e). - DELETE OBJECT e NO-ERROR. + DELETE OBJECT e NO-ERROR. END CATCH. END METHOD. /*---------------------------------------------------------------------------- - Reruns the given test class (must be the full class type-name). Optionally + Reruns the given test class (must be the full class type-name). Optionally specify the name of a test method name to run that method only. - ----------------------------------------------------------------------------*/ + ----------------------------------------------------------------------------*/ METHOD PUBLIC STATIC VOID RerunTest(INPUT className AS CHARACTER, INPUT methodName AS CHARACTER): - ASSIGN + ASSIGN lastClassName = className lastMethodName = methodName lastClassFile = "". @@ -72,13 +77,13 @@ CLASS OEUnit.UI.ResultsWindowView IMPLEMENTS IResultsView: ResultsPresenter:RerunTest(className, methodName). CATCH e AS Progress.Lang.Error : DisplayError(className, e). - DELETE OBJECT e NO-ERROR. + DELETE OBJECT e NO-ERROR. END CATCH. END METHOD. -/*---------------------------------------------------------------------------- - Reruns the last run test class (and filtered method if set) - ----------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------- + Reruns the last run test class (and filtered method if set) + ----------------------------------------------------------------------------*/ METHOD PUBLIC STATIC VOID RerunTest(): IF lastClassFile <> "" THEN RunAsTest(lastClassFile). @@ -88,8 +93,9 @@ CLASS OEUnit.UI.ResultsWindowView IMPLEMENTS IResultsView: /*---------------------------------------------------------------------------- Display the results window and indicate that testing is in progress - ----------------------------------------------------------------------------*/ - METHOD PRIVATE STATIC LOGICAL DisplayRunning(INPUT className AS CHARACTER): + ----------------------------------------------------------------------------*/ + METHOD PRIVATE STATIC VOID DisplayRunning(INPUT className AS CHARACTER): + DEFINE VARIABLE resultsWindow AS HANDLE NO-UNDO. EMPTY TEMP-TABLE ttTestResult. EMPTY TEMP-TABLE ttError. CREATE ttTestResult. @@ -104,14 +110,16 @@ CLASS OEUnit.UI.ResultsWindowView IMPLEMENTS IResultsView: ttTestResult.ErrorCount = 0 ttTestResult.IsClass = TRUE ttTestResult.HasErrors = FALSE. - RUN setTestResults IN ResultsWindow (INPUT TABLE ttTestResult BIND, + GetResultsWindow(OUTPUT resultsWindow). + RUN setTestResults IN resultsWindow (INPUT TABLE ttTestResult BIND, INPUT TABLE ttError BIND, 1, 0, 0, 0, 0). - END METHOD. + END METHOD. /*---------------------------------------------------------------------------- Display the given error in the results window. - ----------------------------------------------------------------------------*/ - METHOD PRIVATE STATIC LOGICAL DisplayError(INPUT className AS CHARACTER, INPUT err AS Progress.Lang.Error): + ----------------------------------------------------------------------------*/ + METHOD PRIVATE STATIC VOID DisplayError(INPUT className AS CHARACTER, INPUT err AS Progress.Lang.Error): + DEFINE VARIABLE resultsWindow AS HANDLE NO-UNDO. EMPTY TEMP-TABLE ttTestResult. EMPTY TEMP-TABLE ttError. CREATE ttTestResult. @@ -126,30 +134,33 @@ CLASS OEUnit.UI.ResultsWindowView IMPLEMENTS IResultsView: ttTestResult.IsClass = TRUE ttTestResult.HasErrors = TRUE. AddError(err, 1). - RUN setTestResults IN ResultsWindow (INPUT TABLE ttTestResult BIND, + GetResultsWindow(OUTPUT resultsWindow). + RUN setTestResults IN resultsWindow (INPUT TABLE ttTestResult BIND, INPUT TABLE ttError BIND, 1, 0, 0, 1, 0). - END METHOD. + END METHOD. /*---------------------------------------------------------------------------- Displays the given test results in the results window. ----------------------------------------------------------------------------*/ METHOD PUBLIC VOID DisplayResults(INPUT results AS TestClassResult): + DEFINE VARIABLE resultsWindow AS HANDLE NO-UNDO. testCount = 0. EMPTY TEMP-TABLE ttTestResult. EMPTY TEMP-TABLE ttError. AddResult(results,"",0). - RUN setTestResults IN ResultsWindow (INPUT TABLE ttTestResult BIND, + GetResultsWindow(OUTPUT resultsWindow). + RUN setTestResults IN resultsWindow (INPUT TABLE ttTestResult BIND, INPUT TABLE ttError BIND, testCount, - results:CountTestsWithStatus(TestResult:StatusPassed), - results:CountTestsWithStatus(TestResult:StatusFailed), - results:CountTestsWithStatus(TestResult:StatusError), + results:CountTestsWithStatus(TestResult:StatusPassed), + results:CountTestsWithStatus(TestResult:StatusFailed), + results:CountTestsWithStatus(TestResult:StatusError), results:CountTestsWithStatus(TestResult:StatusIgnored)). END METHOD. /*---------------------------------------------------------------------------- Add the given test result to the ttTestResult and ttError tables. - ----------------------------------------------------------------------------*/ - METHOD PRIVATE VOID AddResult(INPUT res AS TestResult, INPUT parentClass AS CHARACTER, + ----------------------------------------------------------------------------*/ + METHOD PRIVATE VOID AddResult(INPUT res AS TestResult, INPUT parentClass AS CHARACTER, INPUT depth AS INTEGER): DEFINE VARIABLE testName AS CHARACTER NO-UNDO. @@ -164,10 +175,10 @@ CLASS OEUnit.UI.ResultsWindowView IMPLEMENTS IResultsView: ttTestResult.ErrorCount = res:GetErrors():Size ttTestResult.ResultMessage = res:GetMessage() ttTestResult.ResultStatus = res:GetStatus() - ttTestResult.ResultStatusString = CAPS(res:GetStatusAsString()). - + ttTestResult.ResultStatusString = CAPS(res:GetStatusAsString()). + AddErrors(res:GetErrors()). - + IF TYPE-OF(res, TestClassResult) THEN DO: DEFINE VARIABLE classResult AS TestClassResult NO-UNDO. ASSIGN @@ -175,15 +186,15 @@ CLASS OEUnit.UI.ResultsWindowView IMPLEMENTS IResultsView: ttTestResult.IsClass = TRUE ttTestResult.HasPasses = (res:CountTestsWithStatus(TestResult:StatusPassed) > 0) ttTestResult.HasFailures = (res:CountTestsWithStatus(TestResult:StatusFailed) > 0) - ttTestResult.HasErrors = ((res:CountTestsWithStatus(TestResult:StatusError) > 0) + ttTestResult.HasErrors = ((res:CountTestsWithStatus(TestResult:StatusError) > 0) OR (classResult:GetStatus() = TestResult:StatusError)). - ttTestResult.HasIgnored = ((res:CountTestsWithStatus(TestResult:StatusIgnored) > 0) - OR (classResult:GetStatus() = TestResult:StatusIgnored)). - IF classResult:GetMessage() = "" AND classResult:GetStatus() > TestResult:StatusNoTests THEN + ttTestResult.HasIgnored = ((res:CountTestsWithStatus(TestResult:StatusIgnored) > 0) + OR (classResult:GetStatus() = TestResult:StatusIgnored)). + IF classResult:GetMessage() = "" AND classResult:GetStatus() > TestResult:StatusNoTests THEN ttTestResult.ResultStatusString = "". - + /* Add child results */ - DEFINE VARIABLE i AS INTEGER NO-UNDO. + DEFINE VARIABLE i AS INTEGER NO-UNDO. DO i = 1 TO classResult:resultCount: AddResult(classResult:GetResult(i), testName, depth + 1). END. @@ -194,7 +205,7 @@ CLASS OEUnit.UI.ResultsWindowView IMPLEMENTS IResultsView: /*---------------------------------------------------------------------------- Add each of the Progress.Lang.Errors in the given list to the ttError table. - ----------------------------------------------------------------------------*/ + ----------------------------------------------------------------------------*/ METHOD PRIVATE STATIC VOID AddErrors(INPUT errors AS List): DEFINE VARIABLE i AS INTEGER NO-UNDO. DO i = 1 TO errors:Size: @@ -202,19 +213,19 @@ CLASS OEUnit.UI.ResultsWindowView IMPLEMENTS IResultsView: END. END METHOD. - + /*---------------------------------------------------------------------------- Add the given error to ttError. - ----------------------------------------------------------------------------*/ + ----------------------------------------------------------------------------*/ METHOD PRIVATE STATIC VOID AddError(INPUT err AS Progress.Lang.Error, INPUT errorId AS INTEGER): CREATE ttError. ASSIGN ttError.TestId = ttTestResult.TestId - ttError.ErrorId = errorId + ttError.ErrorId = errorId ttError.ErrorMessage = Errors:GetMessage(err) - ttError.CallStack = err:GetClass():TypeName + " at~n" + ttError.CallStack = err:GetClass():TypeName + " at~n" + Errors:TrimCallStack(err:CallStack). - + END METHOD. - + END CLASS. \ No newline at end of file From 797d2029441b6dac4af7cf1e8b8232429906bf7e Mon Sep 17 00:00:00 2001 From: jorenb Date: Wed, 3 Aug 2016 10:06:12 +0200 Subject: [PATCH 31/33] OEUnit can handle more unit tests. Resolve issue : 14:06:22 [PCTRun] RUN OEUnit/Automation/Pct/RunFromCommandLine 14:06:22 [PCTRun] Attempt to exceed maximum size of a CHARACTER variable. (9324) 14:06:22 [PCTRun] ** Unable to update Field. (142) --- src/OEUnit/Automation/Pct/RunTests.p | 44 +++++++++++++--------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/OEUnit/Automation/Pct/RunTests.p b/src/OEUnit/Automation/Pct/RunTests.p index dd78f65..025ad48 100644 --- a/src/OEUnit/Automation/Pct/RunTests.p +++ b/src/OEUnit/Automation/Pct/RunTests.p @@ -20,23 +20,26 @@ DEFINE INPUT PARAMETER testLocation AS CHARACTER NO-UNDO. DEFINE OUTPUT PARAMETER hasErrors AS LOGICAL NO-UNDO. /* if the testLocation is a file, assume it's a .cls reference and use it */ -DEFINE VARIABLE classFiles AS LONGCHAR NO-UNDO. +DEFINE TEMP-TABLE ttClassFiles NO-UNDO + FIELD classFile AS CHARACTER. + +DEFINE BUFFER b_ClassFile FOR ttClassFiles. FILE-INFO:FILE-NAME = testLocation. IF SUBSTRING(FILE-INFO:FILE-TYPE, 1, 1) = "F" THEN DO: - classFiles = testLocation. + CREATE b_ClassFile. + b_ClassFile.classFile = testLocation. END. ELSE DO: /* the testLocation is a directory, create a list of test classes */ - RUN FindClassFiles(INPUT testLocation, OUTPUT classFiles). + RUN FindClassFiles(INPUT testLocation). END. DEFINE VARIABLE i AS INTEGER NO-UNDO. DEFINE VARIABLE classFile AS CHARACTER NO-UNDO. -REPEAT i = 1 TO NUM-ENTRIES(classFiles, "*"): - classFile = ENTRY(i, classFiles, "*"). - RUN RunClassAsTest(classFile). +FOR EACH b_ClassFile: + RUN RunClassAsTest(b_ClassFile.classFile). END. @@ -73,42 +76,35 @@ END PROCEDURE. /*---------------------------------------------------------------------------- - Searches recursively for class files in a given path. Full filenames are + Searches recursively for class files in a given path. Full filenames are returned seperated by a star(*) - ----------------------------------------------------------------------------*/ + ----------------------------------------------------------------------------*/ PROCEDURE FindClassFiles PRIVATE: DEFINE INPUT PARAMETER path AS CHARACTER NO-UNDO. - DEFINE OUTPUT PARAMETER classFiles AS CHARACTER NO-UNDO INIT "". - DEFINE VARIABLE childClassFiles AS LONGCHAR NO-UNDO. DEFINE VARIABLE directoryEntry AS CHARACTER NO-UNDO. - + INPUT FROM OS-DIR (path). REPEAT: - + IMPORT directoryEntry. FILE-INFO:FILE-NAME = path + (IF OPSYS = "WIN32" THEN "\" ELSE "/") + directoryEntry. - + CASE SUBSTRING(FILE-INFO:FILE-TYPE, 1, 1): WHEN "F" THEN DO: - IF directoryEntry MATCHES ("*.cls") THEN - classFiles = classFiles - + (IF classFiles <> "" THEN "*" ELSE "") - + FILE-INFO:FULL-PATHNAME. + IF directoryEntry MATCHES ("Test*.cls") THEN DO: + CREATE b_ClassFile. + b_ClassFile.classFile = FILE-INFO:FULL-PATHNAME. + END. END. WHEN "D" THEN DO: IF directoryEntry <> ".." AND directoryEntry <> "." THEN DO: - RUN FindClassFiles(INPUT FILE-INFO:FULL-PATHNAME, OUTPUT childClassFiles). - IF childClassFiles <> "" AND childClassFiles <> ? THEN DO: - classFiles = classFiles - + (IF classFiles <> "" THEN "*" ELSE "") - + childClassFiles. - END. + RUN FindClassFiles(INPUT FILE-INFO:FULL-PATHNAME). END. END. END CASE. END. - + END PROCEDURE. From 8f1d83d06fee97fb7e5db8c10cbee9e6f329fd69 Mon Sep 17 00:00:00 2001 From: jorenb Date: Wed, 3 Aug 2016 14:11:58 +0200 Subject: [PATCH 32/33] OEUnit can handle more unit tests. Fix match all *.cls files. --- src/OEUnit/Automation/Pct/RunTests.p | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OEUnit/Automation/Pct/RunTests.p b/src/OEUnit/Automation/Pct/RunTests.p index 025ad48..3e9670b 100644 --- a/src/OEUnit/Automation/Pct/RunTests.p +++ b/src/OEUnit/Automation/Pct/RunTests.p @@ -94,7 +94,7 @@ PROCEDURE FindClassFiles PRIVATE: CASE SUBSTRING(FILE-INFO:FILE-TYPE, 1, 1): WHEN "F" THEN DO: - IF directoryEntry MATCHES ("Test*.cls") THEN DO: + IF directoryEntry MATCHES ("*.cls") THEN DO: CREATE b_ClassFile. b_ClassFile.classFile = FILE-INFO:FULL-PATHNAME. END. From b494161e41e5725aa4b81434753f72bb891030f9 Mon Sep 17 00:00:00 2001 From: Cameron Wills Date: Thu, 24 Oct 2019 10:37:05 +1100 Subject: [PATCH 33/33] Updated readme.md Syntax of headings not valid in GitHub flavored markdown --- readme.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/readme.md b/readme.md index c35c457..b8298b7 100644 --- a/readme.md +++ b/readme.md @@ -1,19 +1,20 @@ -#OEUnit +# OEUnit OEUnit is a unit testing framework for OpenEdge ABL. OEUnit is intended to help write and run repeatable unit tests - similar to JUnit and other xUnit-based unit testing frameworks. For full documentation, see **doc/index.html** in the repository. -##Download +## Download See the [Releases](https://github.com/CameronWills/OEUnit/releases) page. -##Screenshot +## Screenshot Below is a screenshot of the test results docked in Progress Developer Studio (previously OpenEdge Architect). ![Image](/doc/images/oea_example1.png?raw=true) -##Change Log -###1.4 +## Change Log + +### 1.4 - version 1.4 requires OpenEdge 10.2B03 - Merged changes to better support automation and XML reporting. Thanks to Arek Jaworski and Mark Abbott. @@ -21,7 +22,7 @@ Below is a screenshot of the test results docked in Progress Developer Studio (p - Removed 'Author' from the file headers - a leftover relic from a heading template and not conducive to social coding :) - Tested with OpenEdge 11.3 on Windows 7 64bit -###1.3 +### 1.3 - Version 1.3 requires OpenEdge 10.B03 - Fixed bug where the results window would display for a moment and then disappear. @@ -30,7 +31,7 @@ Below is a screenshot of the test results docked in Progress Developer Studio (p - Improved documentation in line with the new Progress Developer Studio (previously named OpenEdge Architect) - Tested with OpenEdge 11.2 on Windows 7 64bit -###1.2 +### 1.2 - Version 1.2 requires OpenEdge 10.2B - Changes to show the error message returned from simple RETURN ERROR "error message" statements @@ -42,10 +43,10 @@ Below is a screenshot of the test results docked in Progress Developer Studio (p - Simplified interfaces for Util/List.cls and Util/IComparator.cls - Added a change log to the project documentation -###1.1 +### 1.1 - Added changes to support the OpenEdge 10.2a runtime - Corrected the method modifiers in UI/ResultsWindowView.cls - causing compile time errors in 10.2a, but was somehow working in 10.1c ? - Fixed bug in Remove() method of Util/List.cls - elements were being re-indexed incorrectly -###1.0 +### 1.0 - Initial release - basic functionality to run test cases and suites.