Project Test manager is the source text of a compiled 32-bit Windows executable program
testman.exe
used to run EuroAssembler tests.
This utility is an alternative to the script version of the Test Manager.
prowin32subdirectory with command
euroasm testman.htm
...\eatests\testman.exe
..\eatests\subdirectory with command
testman t1234, t13*
, testman *
etc.
The header defines program format, imported libraries, used temporary files.
As this program only uses core WinAPI functions fromkernel32.dll, no import library is linked.
EUROASM Unicode=off testman PROGRAM Format=PE, Width=32, Entry=Start:, OutFile="..\eatests\testman.exe" INCLUDEHEAD1 wins.htm, winscon.htm, winssec.htm, winsfile.htm, winf32.htm, winapi.htm, \ status32.htm, cpuext.htm, cpuext32.htm, stdcal32.htm, string32.htm ; Specification of files which might be created during the test. %TemporaryFilesExtensions %SET .asm, .i.asm, .j.asm, .k.asm, \ explicit sources, .exp.lst, .htm.lst, .asm.lst, \ expected and obtained listing, .exp.msg, .msg, \ expected and obtained messages, .exp.hex, .hex, \ expected and obtained hexadecimal dump, .ext ; object file expected extension specification.
[.data]
, uninitialized memory variables in the segment [.bss]
.
[.data] StartupInfo DS STARTUP_INFO ; Windows API structures for running the test. ProcessInformation DS PROCESS_INFORMATION SecurityAttributes DS SECURITY_ATTRIBUTES Errorlevel: DD 0 ; 0=all tests passed, 2=some test failed, 4=file access error, 8=syntax error. ArgCnt: DD 0 ; Number of remaining testman.exe command-line arguments. ArgNr: DD 0 ; Ordinal number of testman.exe argument. PassedCnt: DD 0 ; Number of passed tests. FailedCnt: DD 0 ; Number of failed tests. StartTime: DD 0 ; Milliseconds since Windows boot. FirstFILE: test.htm: DS FILE ; FILE structures for files created during testing. mask.htm: DS FILE tempfile: DS FILE euroasm.ini DS FILE ext %FOR %TemporaryFilesExtensions test%ext: DS FILE %ENDFOR ext LastFILE: HelpText: DB 13,10 DB 'Program "testman.exe" will check EuroAssembler functionality using test files.',13,10 DB 'It should be run in EuroAssembler subdirectory "eatests".',13,10 DB '"testman.exe" erases configuration files "..\easource\euroasm.ini"',13,10 DB 'and "..\eatests\euroasm.ini".',13,10 DB 'The checked version of EuroAssembler is "..\easource\euroasm.exe".',13,10 DB 13,10 DB '"testman.exe" will extract temporary files from the test file',13,10 DB 'and then it will compile and link the extracted source.',13,10 DB 'Finally it compares obtained listing, messages and object file',13,10 DB 'with expected templates stored in the test file',13,10 DB 'and claim the test as "passed" if they match.',13,10 DB 'Temporary files are erased only if the test has succesfully passed.',13,10 DB 13,10 DB 'Tests may be specified as file mask(s), for instance',13,10 DB ' testman.exe t1234.htm t1235.htm t42??.htm"',13,10 DB 'File extension ".htm" as well as prefix "t" may be omitted, for instance',13,10 DB ' testman.exe 7??? or testman * (launch all tests).',13,10 DB 0 test: DB "t????",0 mask: DB "t????.htm",0 command: DB "..\easource\euroasm.exe ",0 ; The tested version of EuroAssembler. params: DB ", TIMESTAMP=0, NOWARN=0010..0170, NOWARN=0980, NOWARN=1160",0 Error: DB "Internal error 0x" ErrCode: DB "???????? accessing file ",0 AllPassed: DB 'All ' AllTests: DB '???? tests passed',0 PassedTests: DB '???? tests passed,' FailedTests: DB '???? tests failed',0 Duration: DB ' in' Seconds: DB '???? seconds.',13,10,0 ;; [.bss] ; Reserved, not initialized memory. DumpAddr: D DWORD DumpLine: D 64 * BYTE CmdLine: D 128 * BYTE Ext: D 12 * BYTE ; Extension of object file, e.g. ".lib". Status: D DWORD ; Status flags in following encoding: stFailed = 1 ; Test failed. stListing = 2 ; Listing are different. stMessages = 4 ; Messages are different. stObject = 8 ; Object dumps are different. stA = 16 ; Assembler source <!--A--> is present in test file. stB = 32 ; Object dump <!--B--> is present in test file.
[.text] Start:: WinAPI GetTickCount MOV [StartTime],EAX GetArgCount ; A macro from the library winapi.htm. JNC ArgCountOK: Help: ; When testman.exe was provided with none or wrong test number. StdOutput HelpText ORB [Errorlevel],8 JMP End: ArgCountOK: MOV [ArgCnt],ECX JECXZ Help: ; If run without arguments. FileAssign euroasm.ini,=B"..\easource\",=B"euroasm.ini" FileDelete euroasm.ini ; Make sure that no global or localeuroasm.iniwill interfere. FileAssign euroasm.ini,=B"..\eatests\",=B"euroasm.ini" FileDelete euroasm.ini NextArg: ; Parse command-line arguments. MOV EAX,[ArgNr] INC EAX MOV [ArgNr],EAX GetArg EAX JC Help: ; ESI,ECX is now one command-line argument, e.g. "t1234" or "/?". LEA EDX,[ESI+ECX] ; EDX points to the end of input string. CMPB [ESI],'/' JE Help: CMPB [ESI],'-' JE Help: MOV EDI,FirstFILE NextFILE: MOV [EDI+FILE.Handle],INVALID_HANDLE_VALUE ADD EDI,SIZE# FILE CMP EDI,LastFILE JB NextFILE: MOV EDI,mask: MOVD [EDI+1],'????' ; Reinitialize the test name mask with wildcards. MOV AL,'t' NextChar: CMP EDI,mask: + 5 JAE Mask3: STOSB SkipChar: CMP ESI,EDX JNB Mask3: ; If no more characters to parse. LODSB CMP AL,'?' JE NextChar: CMP AL,'*' JE Mask3: CMP AL,'0' JB SkipChar: CMP AL,'9' JA SkipChar: ; Skip nondigit and nonwild characters. JMP NextChar: Mask3: FileAssign mask.htm:, mask: FileEach mask.htm:, RunTest ; Perform RunTest with all wildcard-resolved files. DEC [ArgCnt] JNZ NextArg: ; If provided with more than one argument. WinAPI GetTickCount SUB EAX,[StartTime] ; EAX is now the duration af all tests in miliseconds. JC Report1: MOV ECX,1000 SUB EDX,EDX DIV ECX StoD Seconds, Size=4, Align=right Report1: MOV EAX,[PassedCnt] StoD PassedTests, Size=4, Align=right StoD AllTests, Size=4, Align=right MOV EAX,[FailedCnt] StoD FailedTests, Size=4, Align=right MOV ESI,PassedTests: TEST EAX ; Did any test fail? JNZ Report2: MOV ESI,AllPassed: Report2: ADD EAX,[PassedCnt] CMP EAX,1 JNA End: ; Skip the report if only one test was performed. StdOutput ESI,Duration End:TerminateProgram [Errorlevel]
mask.htmand then compares the test results.
t1234.htm.
RunTest PROC MOV EDI,test: MOV ECX,5 REP MOVSB StdOutput test:, =B" ... " ext %FOR %TemporaryFilesExtensions FileAssign test%ext:, test:, =B"%ext" %ENDFOR ext CALL EraseTemporaryFiles XOR EAX,EAX MOV [Status],EAX FileAssign test.htm, test:, =B".htm" FileStreamOpen test.htm JC .Error: .NextLine: FileStreamReadLn test.htm ; Parse test file and write its divisions to temporary files. JC .Error: JZ .CloseWrittenFiles: ; If no more lines. MOV ECX,EAX StripSpaces ESI,ECX CMPB [ESI],'<' ; > JE .Marker?: MOV EBX,test.exp.lst CMP [EBX+FILE.Handle],INVALID_HANDLE_VALUE ; Is the file already open? JNZ .StoreLstLine: FileStreamCreate EBX JC .Error: .StoreLstLine: FileStreamWriteLn EBX,ESI,ECX ; JC .Error: JMP .NextLine: .Marker?: CMPD [ESI],' ; Is it the marker beginning with <!-- ? JNE .NextLine: MOV EAX,[ESI+4] MOV EDX,EAX SHR EDX,8 CMP EDX,'-->' ; Is it the marker ending with --> ? JNE .NextLine: ADD ESI,8 ; Size of the marker. SUB ECX,8 JB .Error: Dispatch AL, 'M','A','I','J','K','E','B' JMP .NextLine: ; Ignore other markers. .StoreDivisionLine: CMP [EBX+FILE.Handle],INVALID_HANDLE_VALUE ; It the file already open? JNE .StoreLine: FileStreamCreate EBX JC .Error: .StoreLine: FileStreamWriteLn EBX,ESI,ECX JC .Error: JMP .NextLine: .M: MOV EBX,test.exp.msg JMP .StoreDivisionLine: .A: SetSt [Status],stA MOV EBX,test.asm JMP .StoreDivisionLine: .I: MOV EBX,test.i.asm JMP .StoreDivisionLine: .J: MOV EBX,test.j.asm JMP .StoreDivisionLine: .K: MOV EBX,test.k.asm JMP .StoreDivisionLine: .E: SetSt [Status],stB MOV EBX,test.ext JMP .StoreDivisionLine: .B: SetSt [Status],stB MOV EBX,test.exp.hex CMP ECX,53 JBE .B5: MOV ECX,53 ; Trim off the character column of the dump. .B5:StripSpaces ESI,ECX JMP .StoreDivisionLine: .CloseWrittenFiles: FileClose test.htm, test.asm, test.i.asm, test.j.asm, test.k.asm, test.ext, test.exp.lst, test.exp.msg, test.exp.hex JNSt [Status],stB,.ExecTest: ; If output object file won't be checked in this test. FileLoad test.ext ; File exists if the marker specified output extension. JNC .ObjExt: SetSt [Status],stFailed+stObject JMP .ExecTest: .ObjExt: MOV ECX,EAX ; File size. StripSpaces ESI,ECX MOV AL,'.' MOV EDI,Ext: CMP [ESI],AL JE .StoreExt: STOSB .StoreExt: REP MOVSB FileDelete test.ext FileAssign test.ext, test:, Ext: ; Reassign with the extension depending on program format. .ExecTest: ; Execute the test. MOV ESI,=B".htm" MOV EBX,test.htm.lst JNSt [Status],stA,.CmdLine: MOV ESI,=B".asm" MOV EBX,test.asm.lst .CmdLine: Concat$ CmdLine:, command:, test:, ESI, params: MOV ECX,SIZE# SecurityAttributes XOR EAX,EAX MOV [SecurityAttributes.nLength],ECX MOV [SecurityAttributes.lpSecurityDescriptor],EAX INC EAX MOV [SecurityAttributes.bInheritHandle],EAX MOV ESI,test.msg.Name ; Filename to capture standard output messages. WinAPI CreateFileA,ESI,FILE_APPEND_DATA,FILE_SHARE_WRITE|FILE_SHARE_READ, \ SecurityAttributes,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0 CMP EAX,INVALID_HANDLE_VALUE JE .Error: MOV [test.msg.Handle],EAX MOV ECX,SIZE# StartupInfo MOV EDX,STARTF_USESTDHANDLES MOV [StartupInfo.cb],ECX MOV [StartupInfo.hStdOutput],EAX MOV [StartupInfo.dwFlags],EDX WinAPI CreateProcess,0,CmdLine:,0,0,1,0,0,0,StartupInfo,ProcessInformation TEST EAX JZ .Error: WinAPI WaitForSingleObject,[ProcessInformation.hProcess],10k ; Until euroasm.exe finishes the test. WinAPI CloseHandle,[test.msg.Handle] ; Compare listing. MOV EBX,test.htm.lst JNSt [Status],stA,.LstLoad MOV EBX,test.asm.lst .LstLoad: FileLoad EBX ; Obtained listing. JC .LstFail: FileLoad test.exp.lst ; Expected listing. JC .LstFail: MOV ESI,[EBX+FILE.BufPtr] MOV ECX,[EBX+FILE.BufSize] MOV EDI,[test.exp.lst.BufPtr] CMP ECX,[test.exp.lst.BufSize] JNE .LstFail: REPE CMPSB JE .CmpMsg: .LstFail: SetSt [Status],stFailed + stListing .CmpMsg:; Compare messages. FileLoad test.msg ; Obtained messages. JC .MsgFail: FileLoad test.exp.msg ; Expected messages. JC .MsgFail: MOV ESI,[test.msg.BufPtr] MOV ECX,[test.msg.BufSize] MOV EDI,[test.exp.msg.BufPtr] CMP ECX,[test.exp.msg.BufSize] JNE .MsgFail: REPE CMPSB JE .MsgOK: .MsgFail: SetSt [Status],stFailed + stMessages .MsgOK: JNSt [Status],stB,.ObjOK: ; Compare target object executable file. ; Convert output file test.ext to hexadecimal dump test.hex. FileStreamCreate test.hex JC .ObjFail: FileLoad test.ext ; Obtained target binary output file. JC .ObjFail: MOV ESI,[test.ext.BufPtr] MOV EDX,[test.ext.BufSize] ADD EDX,ESI ; End of the dumped data. MOV [DumpAddr],-16 .NextDumpLine: ; Prepare one dump row into DumpLine. MOV EDI,DumpLine MOV EAX,[DumpAddr] ADD EAX,16 MOV [DumpAddr],EAX AND EAX,0x0000FFFF StoH EDI,Size=4 MOV AL,':' STOSB MOV ECX,16 ; Prepare max. 16 hex bytes. .NextDumpByte: CMP ESI,EDX JNB .WriteDumpLine: XOR EAX,EAX MOV AL,' ' ; Space separation. STOSB LODSB StoH EDI,Size=2 ; Dump one byte. LOOP .NextDumpByte: .WriteDumpLine: SUB EDI,DumpLine ; Written line size. FileStreamWriteLn test.hex:, DumpLine,EDI CMP ESI,EDX JB .NextDumpLine: FileClose test.hex: ; Compare hexadecimal dumps. FileLoad test.hex ; Obtained dump. JC .ObjFail: FileLoad test.exp.hex ; Expected dump. JC .ObjFail: MOV ESI,[test.hex.BufPtr] MOV ECX,[test.hex.BufSize] MOV EDI,[test.exp.hex.BufPtr] CMP ECX,[test.exp.hex.BufSize] JNE .ObjFail: REPE CMPSB JE .ObjOK: .ObjFail: SetSt [Status],stFailed + stObject .ObjOK: MOV EBX,test.htm.lst JNSt [Status],stA,.CloseExpFiles: MOV EBX,test.asm.lst .CloseExpFiles: FileClose EBX, test.exp.lst, test.msg, test.exp.msg JNSt [Status],stB,.Evaluate: FileClose test.ext, test.hex, test.exp.hex .Evaluate: JSt [Status],stFailed,.Failed: StdOutput ="passed.", Eol=yes INCD [PassedCnt] CALL EraseTemporaryFiles JMP .ObjectOK: .Error: ; EBX=^FILE ORB [Errorlevel],4 WinAPI GetLastError StoH ErrCode,Size=8 StdOutput Error: LEA ESI,[EBX+FILE.Name] StdOutput ESI, Eol=yes STC ; Break further FileEach wildcard resolving. JMP .EndRun: .Failed: StdOutput ="failed:", Eol=yes INCD [FailedCnt] ORB [Errorlevel],2 JNSt [Status],stListing,.ListingOK: LEA ESI,[EBX+FILE.Name] StdOutput ='Obtained listing "', ESI, ='" differs from expected "', \ test.exp.lst.Name, ='".', Eol=yes .ListingOK: JNSt [Status],stMessages,.MessagesOK: StdOutput ='Obtained message "', test.msg.Name, ='" differs from expected "', \ test.exp.msg.Name, ='".', Eol=yes .MessagesOK: JNSt [Status],stObject,.ObjectOK: StdOutput ='Obtained output "',test.hex.Name,='" differs from expected "', \ test.exp.hex.Name, ='".', Eol=yes .ObjectOK: CLC ; CF=0 to continue FileEach with the next test. .EndRun: RET ENDP RunTest
.htm(test source) survives.
EraseTemporaryFiles PROC ; Delete alltest*.*files except fortest.htm. FileAssign tempfile, test:, =B"*.*" FileEach tempfile, EraseTempfile RET EraseTempfile PROC ; Callback from FileEach to erase one FILE EBX whose name is at ESI. CMPB [ESI+9],0 JNE .Erase: MOV EAX,[ESI+5] OR EAX,0x20202000 ; Convert the resolved file extension to lower case. CMP EAX,".htm" JE .Skip: ; Do not delete the test file itself. .Erase:FileDelete EBX .Skip: RET ; CF=0 to continue with FileEach. ENDPROC EraseTempfile ENDPROC EraseTemporaryFiles
ENDPROGRAM testman