├── README.md ├── annotations └── test.th ├── devops ├── ci │ └── ci-azure.yaml └── docker │ └── Dockerfile ├── example └── test-simple.spec.tlpp ├── package.yaml ├── src ├── assistants │ └── tlppRestMock.tlpp ├── core │ ├── assert.tlpp │ └── testEngine.tlpp ├── main │ ├── debugTest.tlpp │ └── executeByFile.tlpp └── progress │ ├── consoleProgressEvent.tlpp │ ├── jsonProgressEvent.tlpp │ ├── lconWithJsonProgressEvent.tlpp │ ├── progressEvent.tlpp │ └── progressEventHandler.tlpp └── test └── runlib.tlpp /README.md: -------------------------------------------------------------------------------- 1 | # Ablon 2 | 3 | Simplest and Lightest unit test framework for TLPP. 4 | 5 | ## Como buildar 6 | 7 | Compilar a pasta src inteira no repo 8 | 9 | 10 | # Como usar 11 | ## Configure seu IDE 12 | Adicionar a pasta \annotations no seu include path ( Conforme a extensão utilizada) 13 | ## Use boas praticas 14 | Essa lib de test recomenda o uso do padrão (NOMEDOFONTE.spec.tlpp ) aonde o nome do fonte, é fonte que esta em tlpp 15 | 16 | ## Exemplos 17 | simple.spec.tlpp 18 | ``` 19 | #include "test.th" 20 | @test("Eu sou outro Teste, eu estou correto") 21 | function mytlpptest2() 22 | Assert():AreEqual(3,3) 23 | return 24 | 25 | ``` 26 | 27 | ## Testando Rests 28 | Utilizando o rest do [TLPP](https://tdn.totvs.com/display/tec/Rest) 29 | 30 | myservice.tlpp 31 | ``` 32 | #include "test.th" 33 | 34 | #include "tlpp-core.th" 35 | namespace sample.customer 36 | using namespace sample.customer.util 37 | 38 | @post("/api/sample/customer/") 39 | function post() 40 | local cBody := oRest:getBodyRequest() 41 | local jBody 42 | local cErrorParser 43 | local oService := CustomerService():getInstance() 44 | if (empty(cBody)) 45 | oRest:setFault("Body invalid") 46 | oRest:setStatusCode(403) 47 | else 48 | jBody := JsonObject():new() 49 | cErrorParser := jBody:fromJson(cBody) 50 | if (empty(cErrorParser)) 51 | oService:Insert(jBody) 52 | else 53 | oRest:setFault("Body invalid") 54 | oRest:setStatusCode(403) 55 | endif 56 | endif 57 | 58 | return 59 | 60 | 61 | ``` 62 | 63 | myservice.spec.tlpp 64 | ``` 65 | #include "test.th" 66 | 67 | using namespace tunittest.core 68 | using namespace tunittest.assistant 69 | using namespace sample.customer 70 | 71 | @test("testa Post em branco, espero que retorne erro") 72 | function postCustomertest01() 73 | //Mockando alguem enviando o request 74 | 75 | TlppRestMock():createPostRequest() 76 | //Chamo o servico 77 | post() 78 | Assert():AreEqual(oRest:getStatusCode(),403,"Body errado") 79 | return 80 | ``` 81 | # Rodando seus testes 82 | ## Utilizando extesão do Vscode 83 | A extensão [Ablon an Unit Test for TLPP and Advpl](https://marketplace.visualstudio.com/items?itemName=KillerAll.advpl-unit-test) , está disponivel para que utiliza a extensão [I Love Advpl](https://marketplace.visualstudio.com/items?itemName=KillerAll.advpl-vscode) 84 | Ainda não é conhecido suporte pela extensão TDS. 85 | 86 | ## Para rodar manualmente 87 | ``` 88 | tunittest.main.u_executeTestByFile("test-simple.spec.tlpp") 89 | ``` 90 | 91 | ## Debug do teste 92 | 93 | Chamar no launch do debug a função: 94 | ``` 95 | tunittest.main.u_testDebug(cFileName as character,cFunctionName as character) 96 | ``` 97 | 98 | -------------------------------------------------------------------------------- /annotations/test.th: -------------------------------------------------------------------------------- 1 | @annotation Test 2 | description as char default "" 3 | throwException as logical default .f. 4 | @end 5 | -------------------------------------------------------------------------------- /devops/ci/ci-azure.yaml: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /devops/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- /example/test-simple.spec.tlpp: -------------------------------------------------------------------------------- 1 | #include "test.th" 2 | 3 | using namespace tunittest.core 4 | @test("Teste simples. afrimacao de soma correta" ) 5 | function mytlpptest0() 6 | ablon.example.cov_test() 7 | Assert():AreEqual(ablon.example.soma(2,3),5) 8 | return 9 | 10 | @test("Teste simples. afrimacao errada" ) 11 | function mytlpptest1() 12 | sleep(300) 13 | conout("Sou um teste") 14 | Assert():AreEqual(2,3) 15 | return 16 | 17 | @test("Eu sou outro Teste, eu estou correto") 18 | function mytlpptest2() 19 | conout("Sou um teste") 20 | Assert():AreEqual(3,3) 21 | return 22 | 23 | @test("Eu sou outro Teste, esquesi o assert") 24 | function mytlpptest3() 25 | conout("Sou um teste") 26 | //Assert():AreEqual(3,3) 27 | return 28 | 29 | @test(description = "Teste de Exception-Esperada" ,throwException= .t. ) 30 | function mytlpptestexcpexperada() 31 | UserException("Pega essa") 32 | return 33 | 34 | @test("Teste de Exception-inesperada" ) 35 | function mytlpptestexcpinsp() 36 | UserException("fiz coisa errada") 37 | return 38 | -------------------------------------------------------------------------------- /package.yaml: -------------------------------------------------------------------------------- 1 | name: ablon-tlpp-unittest 2 | version: 0.0.2 3 | synopsis: Simplest and Lightest unit test framework for TLPP 4 | maintainer: Rodrigo Antonio Godinho 5 | license: MIT 6 | repository: https://github.com/totvs/ablon-tlpp-unittest 7 | category: test 8 | type: source 9 | 10 | exposed-includes: 11 | 12 | library: 13 | source-dirs: src 14 | tests: 15 | source-dirs: test 16 | dependencies: tlpp-core 17 | -------------------------------------------------------------------------------- /src/assistants/tlppRestMock.tlpp: -------------------------------------------------------------------------------- 1 | #include "tlpp-core.th" 2 | namespace tunittest.assistant 3 | 4 | class TlppRestMock 5 | public data statusCode 6 | public data faultMessage 7 | public data body 8 | public data response 9 | public data pathParam 10 | public data queryRequest 11 | public data headerRequest 12 | public data headerReponse 13 | public data fullURLRequest 14 | public data methodName 15 | public method new() 16 | 17 | public method setFault() 18 | public method setStatusCode() 19 | public method setResponse() 20 | public method setPathParamsRequest() 21 | public method setQueryRequest() 22 | public method setHeaderRequest() 23 | public method setHeaderResponse() 24 | public method setFullURLRequest() 25 | public method setMethodRequest() 26 | 27 | public method getMethodRequest() 28 | public method getHeaderRequest() 29 | public method getHeaderResponse() 30 | public method getFullURLRequest() 31 | 32 | public method getBodyRequest() 33 | public method getResponse() 34 | public method getStatusCode() 35 | public method getPathParamsRequest() 36 | public method getQueryRequest() 37 | 38 | static method createRequest() 39 | static method createPostRequest() 40 | static method createGetRequest() 41 | static method createPutRequest() 42 | static method createDeleteRequest() 43 | endclass 44 | 45 | method new() class TlppRestMock 46 | 47 | return 48 | method createPostRequest(body) class TlppRestMock 49 | public oRest := TlppRestMock():new() 50 | oRest:body := body 51 | oRest:methodName := "POST" 52 | return 53 | method createGetRequest() class TlppRestMock 54 | public oRest := TlppRestMock():new() 55 | oRest:methodName := "GET" 56 | return 57 | method createPutRequest(body) class TlppRestMock 58 | public oRest := TlppRestMock():new() 59 | oRest:body := body 60 | oRest:methodName := "PUT" 61 | return 62 | method createDeleteRequest() class TlppRestMock 63 | public oRest := TlppRestMock():new() 64 | oRest:methodName := "DELETE" 65 | return 66 | 67 | method createRequest() class TlppRestMock 68 | public oRest := TlppRestMock():new() 69 | return 70 | 71 | method getResponse() class TlppRestMock 72 | return self:response 73 | 74 | method setResponse(response) class TlppRestMock 75 | self:response := response 76 | self:statusCode := 200 77 | return 78 | method getBodyRequest() class TlppRestMock 79 | return self:body 80 | 81 | method setFault(cMsg) class TlppRestMock 82 | self:faultMessage := cMsg 83 | return 84 | 85 | method setStatusCode(nCode) class TlppRestMock 86 | self:statusCode := nCode 87 | return 88 | method getStatusCode() class TlppRestMock 89 | return self:statusCode 90 | method setPathParamsRequest(jpathParam) class TlppRestMock 91 | self:pathParam := jpathParam 92 | return 93 | method getPathParamsRequest() class TlppRestMock 94 | return self:pathParam 95 | 96 | method setQueryRequest(query) class TlppRestMock 97 | self:queryRequest := query 98 | return 99 | 100 | method getQueryRequest() class TlppRestMock 101 | return self:queryRequest 102 | 103 | 104 | 105 | method getHeaderRequest() class TlppRestMock 106 | return self:headerRequest 107 | method getHeaderResponse() class TlppRestMock 108 | return self:headerReponse 109 | method getFullURLRequest() class TlppRestMock 110 | return self:fullURLRequest 111 | 112 | method setHeaderRequest(header) class TlppRestMock 113 | self:headerRequest := header 114 | return 115 | method setHeaderResponse(header) class TlppRestMock 116 | self:headerReponse := header 117 | return 118 | method setFullURLRequest(fullUrlReq) class TlppRestMock 119 | self:fullURLRequest := fullUrlReq 120 | return 121 | 122 | method setMethodRequest(methodName) class TlppRestMock 123 | self:methodName := methodName 124 | return 125 | method getMethodRequest() class TlppRestMock 126 | return self:methodName -------------------------------------------------------------------------------- /src/core/assert.tlpp: -------------------------------------------------------------------------------- 1 | #include "tlpp-core.th" 2 | namespace tunittest.core 3 | static __oinstance := nil 4 | //------------------------------------------------------------------- 5 | /*/{Protheus.doc} function 6 | description 7 | @author Rodrigo Antonio 8 | 9 | /*/ 10 | //------------------------------------------------------------------- 11 | class Assert 12 | data jResults 13 | public method new() 14 | public method putResult() 15 | public method getResult(cSource,cFunction) 16 | static method getInstance() as Object 17 | static method isTrue(condition as logical, message as character) 18 | static method isFalse(condition as logical, message as character) 19 | static method areEqual(expected, actual, message as character) 20 | static method isEmpty(xValue, message as character) 21 | 22 | endclass 23 | method new() class Assert 24 | if (__oinstance == Nil) 25 | __oinstance := self 26 | self:jResults := JsonObject():new() 27 | else 28 | UserException("Too many Asserts") 29 | endif 30 | return 31 | 32 | method getInstance() class Assert 33 | 34 | return __oinstance 35 | method putResult(lSuccess as logical, message as character, cSource as character, cfunction as character) class Assert 36 | local jNewResult 37 | local cKey 38 | default cSource := ProcSource(2) 39 | default cfunction := ProcName(2) 40 | //default lExceptionIsExpected := .f. 41 | cKey := cSource+cfunction 42 | jNewResult := JsonObject():new() 43 | jNewResult["success"] := lSuccess 44 | jNewResult["message"] := message 45 | //jNewResult["lExceptionIsExpected"] := lExceptionIsExpected 46 | __oinstance:jResults[cKey] := jNewResult 47 | return 48 | 49 | method getResult(cSource,cFunction) class Assert 50 | local jResult := __oinstance:jResults[cSource+cfunction] 51 | if (jResult == Nil) 52 | self:putResult(.F.,"No assert to this test.",cSource,cfunction) 53 | jResult := __oinstance:jResults[cSource+cfunction] 54 | endif 55 | return jResult 56 | 57 | 58 | method isTrue(condition as logical, message as character) class Assert 59 | default message := "Expected true" 60 | __oinstance:putResult(condition,message) 61 | return 62 | 63 | method isFalse(condition as logical, message as character) class Assert 64 | default message := "Expected false" 65 | __oinstance:putResult(!condition,message) 66 | return 67 | 68 | method isEmpty(xValue, message as character) class Assert 69 | default message := "Expected empty" 70 | __oinstance:putResult(empty(xvalue),message) 71 | return 72 | 73 | method AreEqual(expected, actual,message as character) class Assert 74 | local typeExpected := valtype( expected) 75 | local typeActual := valtype( actual) 76 | local lEqual 77 | default message := "" 78 | if (typeActual == typeExpected) 79 | if typeActual $ "CNDL" 80 | lEqual := (expected == actual) 81 | else 82 | UserException("Type is not valid.") 83 | endif 84 | else 85 | lEqual := .F. 86 | endif 87 | if empty(message) 88 | message := "Expected that '" + cValtoChar(expected) + "' should be equals to '" + cValtoChar(actual) + "'" 89 | endif 90 | __oinstance:putResult(lEqual,message) 91 | return -------------------------------------------------------------------------------- /src/core/testEngine.tlpp: -------------------------------------------------------------------------------- 1 | #include "tlpp-core.th" 2 | namespace tunittest.core 3 | using namespace tunittest.progress 4 | class TestEngine 5 | private data lCoverage 6 | private data aCoverage 7 | private data oAssert 8 | private data oProgressEventHandler 9 | private data oCoverageEventHandler 10 | private data jProgressInfo 11 | 12 | public method new() 13 | public method enableCoverage() 14 | public method executeTestFunction(cFunctionName as character) 15 | public method runTestsByFile(cFileName as character) 16 | public method runTestsFunction(cFileName as character, cFunction as character) 17 | public method getProgress(ckey as character) 18 | public method getCoverage(ckey as character) 19 | public method catchError(oError as object,lErrorExpected as logical) 20 | public method addProgress() 21 | public method addCoverage() 22 | private method startCoverageIfEnable() 23 | private method stopCoverageIfEnable() 24 | 25 | private method fireProgress() 26 | 27 | endclass 28 | method new() class TestEngine 29 | self:aCoverage := {} 30 | self:lCoverage := .f. 31 | self:oAssert := Assert():new() 32 | self:jProgressInfo := JsonObject():New() 33 | self:oCoverageEventHandler := ProgressEventHandler():new() 34 | 35 | self:oProgressEventHandler := ProgressEventHandler():new() 36 | self:oProgressEventHandler:addEvent("console",ConsoleProgressEvent():new()) 37 | return 38 | method addProgress(cKey, oEvent) class TestEngine 39 | self:oProgressEventHandler:addEvent(cKey, oEvent) 40 | return 41 | method addCoverage(cKey, oEvent) class TestEngine 42 | self:oCoverageEventHandler:addEvent(cKey, oEvent) 43 | return 44 | method enableCoverage() class TestEngine 45 | self:lCoverage := .T. 46 | return 47 | method getProgress(ckey as character) class TestEngine 48 | return self:oProgressEventHandler:getEvent(ckey) 49 | 50 | method getCoverage(ckey as character) class TestEngine 51 | return self:oCoverageEventHandler:getEvent(ckey) 52 | 53 | method runTestsByFile(cFileName as Character) class TestEngine 54 | local aFunctionToTest 55 | local nx 56 | local nCount 57 | local jFunctionAnnotationInfo 58 | local lok := .f. 59 | aFunctionToTest := Reflection.getProgramFunctionsByAnnotation(cFileName,"test") 60 | if !empty(aFunctionToTest) 61 | nCount := Len(aFunctionToTest) 62 | 63 | self:jProgressInfo["source"] := cFileName 64 | self:jProgressInfo["tests"] := nCount 65 | self:jProgressInfo["current"] := JsonObject():new() 66 | for nx := 1 to nCount 67 | jFunctionAnnotationInfo := Reflection.getFunctionAnnotation(cFileName,aFunctionToTest[nx],"test") 68 | self:jProgressInfo["current"]["count"] := nX 69 | self:jProgressInfo["current"]["function"] := aFunctionToTest[nx] 70 | self:jProgressInfo["current"]["AnnotationInfo"] := jFunctionAnnotationInfo 71 | self:executeTestFunction(aFunctionToTest[nx]) 72 | next nx 73 | aFunctionToTest := aSize(aFunctionToTest,0) 74 | lok := .t. 75 | self:oCoverageEventHandler:fire(self:aCoverage) 76 | endif 77 | return lok 78 | method runTestsFunction(cFileName as character, cFunction as character) class TestEngine 79 | local aFunctionToTest 80 | local nx 81 | local jFunctionAnnotationInfo 82 | local lok := .f. 83 | aFunctionToTest := Reflection.getProgramFunctionsByAnnotation(cFileName,"test") 84 | if !empty(aFunctionToTest) 85 | self:oProgressEventHandler:addEvent("json",JsonProgressEvent():new(cFileName)) 86 | self:jProgressInfo["source"] := cFileName 87 | self:jProgressInfo["tests"] := 1 88 | self:jProgressInfo["current"] := JsonObject():new() 89 | 90 | jFunctionAnnotationInfo := Reflection.getFunctionAnnotation(cFileName,cFunction,"test") 91 | if (jFunctionAnnotationInfo != Nil) 92 | self:jProgressInfo["current"]["count"] := nX 93 | self:jProgressInfo["current"]["function"] := aFunctionToTest[nx] 94 | self:jProgressInfo["current"]["AnnotationInfo"] := jFunctionAnnotationInfo 95 | self:executeTestFunction(aFunctionToTest[nx]) 96 | lok := .t. 97 | endif 98 | aFunctionToTest := aSize(aFunctionToTest,0) 99 | endif 100 | return lok 101 | 102 | method executeTestFunction(cFunctionName as Character) class TestEngine 103 | local lErrorCaught := .F. 104 | local lErrorExpected := self:jProgressInfo["current"]["AnnotationInfo"]["throwException"] 105 | local oErrorBlock := ErrorBlock({|oError| self:catchError(oError,lErrorExpected), lErrorCaught := .T., Break(oError) }) 106 | self:startCoverageIfEnable() 107 | 108 | self:jProgressInfo["current"]["start"] := seconds() 109 | Begin Sequence 110 | testFunctionCall(cFunctionName) 111 | Recover 112 | //Implementar o recover aqui 113 | End Sequence 114 | self:stopCoverageIfEnable() 115 | ErrorBlock( oErrorBlock ) 116 | //Esperava dar exception mais não deu 117 | if (lErrorExpected .and. !lErrorCaught ) 118 | self:oAssert:putResult(.f., "Expected exception was not thrown.", upper(self:jProgressInfo["source"]), self:jProgressInfo["current"]["function"] ) 119 | endif 120 | self:fireProgress() 121 | 122 | 123 | return 124 | 125 | /*method fireProgressStart() class TestEngine 126 | self:jProgressInfo["current"]["start"] := seconds() 127 | self:oProgressEventHandler:fire(self:jProgressInfo) 128 | return*/ 129 | method fireProgress() class TestEngine 130 | local jResult 131 | self:jProgressInfo["current"]["stop"] := seconds() 132 | jResult := self:oAssert:getResult(Upper(self:jProgressInfo["source"]),Upper(self:jProgressInfo["current"]["function"])) 133 | self:jProgressInfo["current"]["result"] := jResult 134 | self:oProgressEventHandler:fire(self:jProgressInfo) 135 | return 136 | 137 | method startCoverageIfEnable() class TestEngine 138 | if (self:lCoverage) 139 | PtInternal( 12 , "ON" ) 140 | endif 141 | return 142 | 143 | method stopCoverageIfEnable() class TestEngine 144 | local aTmp 145 | if Self:lCoverage 146 | aTmp := PtInternal( 12 , "COVERAGE" ) 147 | PtInternal( 12 , "OFF") 148 | //conout("Coverga Dump") 149 | printArray(aTmp) 150 | If (empty(self:aCoverage)) 151 | self:aCoverage := aTmp 152 | Else 153 | Merge(@self:aCoverage,aTmp) 154 | Endif 155 | //aTmp := aSize(aTmp,0) 156 | endif 157 | 158 | return 159 | method catchError(oError as object, lExpected as logical ) class TestEngine 160 | 161 | Local cMsg := "Error Log:" + Iif(oError != Nil, oError:ErrorStack,"") 162 | 163 | self:oAssert:putResult(lExpected, cMsg, upper(self:jProgressInfo["source"]), self:jProgressInfo["current"]["function"] ) 164 | return 165 | 166 | 167 | Return 168 | static function testFunctionCall(cFunctionName as Character) 169 | &cFunctionName.() 170 | return 171 | 172 | static function Merge(aOrigem,aNovo) 173 | local nSource 174 | local nLine 175 | local nPosNovo 176 | local aOriLines 177 | local aNovoLines 178 | local nPosOri 179 | local nMaxLines 180 | for nSource := 1 to Len(aOrigem) 181 | nPosNovo := aScan(aNovo, {|x| x[1] == aOrigem[nSource][1]}) 182 | if nPosNovo > 0 //Caso seja 0 é pq no novo não tem esse fonte 183 | aOriLines := aOrigem[nSource][2] 184 | aNovoLines := aNovo[nPosNovo][2] 185 | nMaxLines := Len(aNovoLines) 186 | for nLine := 1 to Len(aOriLines) 187 | if(nLine <= nMaxLines .and. aOriLines[nLine] != aNovoLines[nLine]) 188 | aOriLines[nLine] := Max(aOriLines[nLine], aNovoLines[nLine]) 189 | endif 190 | next nLine 191 | endif 192 | next nSource 193 | for nSource := 1 to Len(aNovo) 194 | nPosOri := aScan(aOrigem, {|x| x[1] == aNovo[nSource][1]}) 195 | if nPosOri == 0 196 | aAdd(aOrigem,aClone(aNovo[nSource])) 197 | endif 198 | next nSource 199 | return 200 | 201 | static function printArray(aEntry,cPai) 202 | local nX 203 | local clocalPai 204 | default cPai := "Array->" 205 | for nx := 1 to len(aEntry) 206 | clocalPai := cPai +"[" + cValTochar(nx) + "]" 207 | if valtype(aEntry[nx]) =="A" 208 | printarray(aEntry[nx],clocalPai) 209 | else 210 | conout( clocalPai + "=" + cValTochar(aEntry[nx])) 211 | endif 212 | next 213 | return -------------------------------------------------------------------------------- /src/main/debugTest.tlpp: -------------------------------------------------------------------------------- 1 | #include "tlpp-core.th" 2 | namespace tunittest.main 3 | //tunittest.main.u_testDebug 4 | user function testDebug(cFileName as character,cFunctionName as character) 5 | local oEngine 6 | local oProgress 7 | local oJson 8 | local cResult 9 | oEngine := tunittest.core.TestEngine():new() 10 | oEngine:runTestsByFile(cFileName) 11 | 12 | return 13 | -------------------------------------------------------------------------------- /src/main/executeByFile.tlpp: -------------------------------------------------------------------------------- 1 | #include "tlpp-core.th" 2 | namespace tunittest.main 3 | using namespace tunittest.progress 4 | user function executeTestByFile(cFileName as character,cCoverageType as character) 5 | local oEngine 6 | local oProgress 7 | local oJson 8 | local cResult 9 | local oCoverage 10 | local jCoverage 11 | default cCoverageType := "lcov" 12 | oEngine := tunittest.core.TestEngine():new() 13 | oEngine:enableCoverage() 14 | oEngine:addCoverage("lcov",LconWithJsonProgressEvent():new()) 15 | oEngine:addProgress("json",JsonProgressEvent():new(cFileName)) 16 | if oEngine:runTestsByFile(cFileName) 17 | oProgress := oEngine:getProgress("json") 18 | oJson := oProgress:getResult() 19 | 20 | oCoverage := oEngine:getCoverage(cCoverageType) 21 | jCoverage := oCoverage:getResult() 22 | oJson['lcov'] := jCoverage 23 | cResult := oJson:toJSON() 24 | endif 25 | 26 | return cResult 27 | -------------------------------------------------------------------------------- /src/progress/consoleProgressEvent.tlpp: -------------------------------------------------------------------------------- 1 | #include "tlpp-core.th" 2 | namespace tunittest.progress 3 | 4 | class ConsoleProgressEvent from ProgressEvent 5 | 6 | public method new() 7 | public method fire(jInfo) 8 | private method writeLog() 9 | endclass 10 | 11 | method new() class ConsoleProgressEvent 12 | 13 | 14 | return 15 | 16 | method writeLog(clog) class ConsoleProgressEvent 17 | conout ("[T-UNIT-TEST]" + clog ) 18 | return 19 | method fire(jProgress) class ConsoleProgressEvent 20 | local cLog 21 | local lSuccess 22 | local nExecTime 23 | nExecTime := jProgress["current"]["stop"] - jProgress["current"]["start"] 24 | 25 | cLog := "[" + jProgress["source"] + "][" + jProgress["current"]["function"]+ "][" 26 | cLog += jProgress["current"]["AnnotationInfo"]["description"] 27 | cLog += "][Exec time:" + cValToChar(nExecTime)+ "]" 28 | cLog += "[" + jProgress["source"] + "][" + jProgress["current"]["function"]+"] " 29 | lSuccess := jProgress["current"]["result"]["success"] 30 | cLog += iif(lSuccess, "test successfully completed.", "test finished with FAILURE.") 31 | if (!lSuccess) 32 | cLog += "[" + jProgress["current"]["result"]["message"] + "]" 33 | endif 34 | 35 | self:writeLog(cLog) 36 | return 37 | 38 | -------------------------------------------------------------------------------- /src/progress/jsonProgressEvent.tlpp: -------------------------------------------------------------------------------- 1 | #include "tlpp-core.th" 2 | namespace tunittest.progress 3 | 4 | class JsonProgressEvent from ProgressEvent 5 | private data jresult 6 | public method new(cFileName as character) 7 | public method fire(jInfo) 8 | public method getResult() 9 | 10 | endclass 11 | 12 | method new(cFileName as character) class JsonProgressEvent 13 | self:jresult := JsonObject():new() 14 | self:jresult["tests"] := JsonObject():new() 15 | self:jresult["tests"]["className"] := cFileName 16 | self:jresult["tests"]["methods"] := {} 17 | self:jresult["tests"]["runned"] := .t. 18 | return 19 | method getResult() class JsonProgressEvent 20 | return self:jresult 21 | 22 | method fire(jProgress) class JsonProgressEvent 23 | local item := JsonObject():new() 24 | item["success"] := jProgress["current"]["result"]["success"] 25 | item["methodname"] := jProgress["current"]["function"] 26 | item["message"] := jProgress["current"]["result"]["message"] 27 | item["line"] := -1 28 | item["skiped"] := .f. 29 | item["elapsedTime"] := jProgress["current"]["stop"] - jProgress["current"]["start"] 30 | aAdd(self:jresult["tests"]["methods"],item) 31 | return -------------------------------------------------------------------------------- /src/progress/lconWithJsonProgressEvent.tlpp: -------------------------------------------------------------------------------- 1 | #include "tlpp-core.th" 2 | namespace tunittest.progress 3 | static __ohIgnoredSources := __initIgnored() 4 | class LconWithJsonProgressEvent from ProgressEvent 5 | private data jresult 6 | public method new() 7 | public method fire(aCoverage) 8 | public method getResult() 9 | 10 | endclass 11 | static function __initIgnored() 12 | __ohIgnoredSources := JsonObject():new() 13 | //Adicionar aqui todos os fontes que nao sera gerado coverage 14 | __ohIgnoredSources["TUNITTEST.PROGRESS.LCONWITHJSONPROGRESSEVENT"] := .T. 15 | return 16 | method new() class LconWithJsonProgressEvent 17 | self:jresult := JsonObject():new() 18 | 19 | return 20 | method getResult() class LconWithJsonProgressEvent 21 | return self:jresult 22 | 23 | method fire(aCoverage) class LconWithJsonProgressEvent 24 | local nLenght as Numeric 25 | local nPos as Numeric 26 | local jLcovp := JsonObject():new() 27 | local jSF 28 | local nInstrumentedLines := 0 29 | local nNonZeroLines := 0 30 | 31 | 32 | jLcovp['TNs'] := {} 33 | nLenght := len(aCoverage) 34 | for nPos := 1 to nLenght 35 | /*if (__ohIgnoredSources[aCoverage[nPos][1]]) 36 | loop 37 | endif */ 38 | nInstrumentedLines := 0 39 | nNonZeroLines := 0 40 | jSF := JsonObject():new() 41 | jSF["SF"] := aCoverage[nPos][1] 42 | jSF["lines"] := lineToCover(aCoverage[nPos][2],@nInstrumentedLines,@nNonZeroLines) 43 | jSF["LH"] := cValToChar(nNonZeroLines) 44 | jSF["LF"] := cValToChar(nInstrumentedLines) 45 | aAdd(jLcovp['TNs'] ,jSF) 46 | next nPos 47 | self:jresult := jLcovp 48 | conout(jLcovp:toJson()) 49 | return 50 | 51 | static function lineToCover(aLines,nInstrumentedLines,nNonZeroLines) 52 | local aJsonLines := {} 53 | local nLenght as numeric 54 | local nX 55 | local nExecCount 56 | local jItem 57 | nLenght := Len(aLines) 58 | 59 | 60 | For nX := 1 to nLenght 61 | nExecCount := aLines[nX] 62 | If nExecCount >= 0 63 | nInstrumentedLines++ 64 | nNonZeroLines++ 65 | jItem := JsonObject():new() 66 | jItem["DA"] := cValToChar(nX) 67 | jItem["hits"] := cValToChar(aLines[nX]) 68 | aAdd(aJsonLines,jItem) 69 | ElseIf nExecCount == 0 70 | nInstrumentedLines++ 71 | EndIf 72 | Next nX 73 | 74 | 75 | return aJsonLines 76 | -------------------------------------------------------------------------------- /src/progress/progressEvent.tlpp: -------------------------------------------------------------------------------- 1 | #include "tlpp-core.th" 2 | namespace tunittest.progress 3 | 4 | class ProgressEvent 5 | public method new() 6 | public method fire(xValue) 7 | endclass -------------------------------------------------------------------------------- /src/progress/progressEventHandler.tlpp: -------------------------------------------------------------------------------- 1 | #include "tlpp-core.th" 2 | namespace tunittest.progress 3 | 4 | class ProgressEventHandler 5 | data jEvents 6 | 7 | public method new() 8 | public method addEvent(cId as character, oEvent as Object) 9 | public method fire(jProgress) 10 | public method getEvent(cid as character) 11 | endclass 12 | 13 | method new() class ProgressEventHandler 14 | self:jEvents := JsonObject():new() 15 | return 16 | method getEvent(cid as character) class ProgressEventHandler 17 | return self:jEvents[cid] 18 | 19 | method addEvent(cId as character, oEvent as Object) class ProgressEventHandler 20 | self:jEvents[cId] := oEvent 21 | return 22 | 23 | method fire(jProgress) class ProgressEventHandler 24 | local nx 25 | local aEvents := self:jEvents:GetNames() 26 | for nx := 1 to len (aEvents) 27 | self:jEvents[aEvents[nX]]:Fire(jProgress) 28 | next nx 29 | aEvents := aSize(aEvents,0) 30 | return -------------------------------------------------------------------------------- /test/runlib.tlpp: -------------------------------------------------------------------------------- 1 | #include 'tlpp-core.th' 2 | namespace tlpp.test 3 | //tlpp.test.u_runlib 4 | function u_runlib() 5 | 6 | tunittest.main.u_executeTestByFile("test-simple.spec.tlpp") 7 | 8 | return 9 | --------------------------------------------------------------------------------