Nothing really difficult to write but I find ASSERT in general an invaluable tool while developing a new program, and this one has some nice little touches.
First of all I'll give a brief introduction to the benefits of ASSERT in general for the people who never used it.
Skip to the specifics of this one if you already know what an ASSERT is.
The ASSERT macro is a simple way to program defensively.
You basically say: at this point in my code this expression must be true or what follow does not make sense, can't operate as envisioned.
It's a way to double check the assumptions you make while developing your program, to test for all the things that never should go wrong but actually can when the code you are writing is expecting something to be in a certain state, and for some reason (an error somewhere else maybe) that's not the case.
An ASSERT constantly check if your program's environment is the way it should, and it will save you countless of times, spotting a problem before it can invisibly creep in a bigger problem apparently unrelated, one you'll end up discovering a lot later.
For example, if you know a pointer shouldn't be null, you ASSERT this before use it.
You *know* that pointer will not be null, right ?
But if you made a mistake ? You'll catch it immediately while still developing your program.
A good use for ASSERT is to check all the parameters and dependencies a procedure needs to work as expected.
The parameters part is obvious. With dependencies I mean all the rest. For example some procedures inside a library could be usable only if the library has been initialized. You could enforce that inside each procedure with an ASSERT.
Or a particular procedure can successfully operate on a object only if the object has been set to a valid state by another procedure first. Another job for an ASSERT.
Another good use is to check values you are about to return to the caller before exiting a procedure.
If you know the proc, when working correctly, must return values within a certain range, or values which must satisfy some conditions, ASSERT it just before the ProcedureReturn.
All those checks are time consuming ? They could be, but when you are ready to release your program you can make them vanish by defining a single constant.
You had all the benefit of strict checking without a permanent penalty, and your software will be a lot more robust from the start.
When you take the habit to use ASSERT it become a second nature, and you'll ask yourself how you missed it until now.
Well... if you already find tedious EnableExplicit probably you will hate all this, and I cannot save you

Obviously not all must be exclusively checked with an ASSERT. For example input by the user can contain something unexpected, or if your program access external data who knows what you may end up reading. So run time checks (and error handling) in the release build still have their place.
But with ASSERT you can check all the rest, and only in the debugging/developing phase.
ASSERT role is essentially to protect you from yourself, from your errors and to validate your assumptions.
The other runtime checks are there to protect your program from the unexpected (a missing file, a gibberish data input, etc.)
All this must be calibrated depending on the type of software you are developing.
One big important note: since the ASSERT macros are not compiled in the final release of the program, it's important you take the habit of not calling procs inside an ASSERT, or alter a value of a var. You must not alter the state of your program or removing the ASSERTs will make it behave differently.
This is exactly like using the debug command in PB with a function as its parameter. Same problem.
OK, now the specifics of this version.
You enable the ASSERTs with #ASSERT_ENABLED = 1
and set the optional title of the ASSERT window with #ASSERT_TITLE$ = "Test program 1.0"
Then you include the ASSERT code with IncludeFile "Assert.pb"
And finally you write your program.
The usage is:
ASSERT(<expression>)
or
ASSERT(<expression>, "text message")
The ASSERTs are included in the program with #ASSERT_ENABLED = 1 and completely removed with #ASSERT_ENABLED = 0.
When the program is running with the debugger enabled, and an ASSERT fails, you will see a window like this one:

Continue will continue the execution.
Disable this ASSERT will disable *ONLY* this specific ASSERT for the entire execution of the program.
This is very useful if the failed ASSERT is inside a loop to avoid to click Continue forever to test another section without quitting.
Call Debugger will invoke the debugger on the line of the failed ASSERT.
When the program is running with the debugger disabled, the Call Debugger option is not available and is replaced by
End, which will close the program.
Simple test:
Code: Select all
; TEST
EnableExplicit
#ASSERT_ENABLED = 1
#ASSERT_TITLE$ = "Test program 1.0"
IncludeFile "Assert.pb"
Procedure Test1 (a,b,c)
ASSERT(a > 0)
ASSERT(b > 0)
ASSERT(c > a + b)
EndProcedure
Procedure Test2 (val, *ptr)
Protected a$
ASSERT(val > 0)
ASSERT(*ptr > 0, "Pointer to string is null, PeekS() will fail !")
a$ = PeekS(*ptr)
EndProcedure
Define s$ = "string"
Test1(5,0,10) ; fails one assert
Test1(5,0,1) ; fails two assert
Test1(1,2,5) ; ok
Test2(1, @s$) ; ok
Test2(5, #Null) ; fails one assert
For example, you could check if a pointer to structured data is not null with an ASSERT.
If it pass the test, you could inspect the first bytes of that buffer to see if the structured data start with a magic number you know must be present.
This would give you a greater reassurance the pointer not only is not null, but with a high level of probability is pointing to valid data.
So you could stack the ASSERTs to check something more when the previous ASSERT validated an assumption for the second ASSERT.
Hope this will give you some ideas.
A link to wikipedia
That's it, the include is in the next post.
EDIT: if you want to have this code in module's form, see the conversion made here by Little John -> http://www.purebasic.fr/english/viewtop ... 39#p424239