Peter N Lewis wrote:
I have a lot of assertions. If one of them fails, GPC only reports something like "assertion failed (error #306 at 40dd45)". How can I find out the exact assertion that failed?
Rather than use the built in assertions, we use our own assertions, that way it allows us to compile them out of the later beta/final builds (a requirement for over-asserting as recommended by Writing Solid Code which should be essential reading for any programmer).
The code we use is basically:
Prefix file:
{$definec do_debug true}
{$ifc do_debug} {$definec Assert(b) AssertCode((b), __FILE__, __LINE__)} {$definec AssertNoErr(err) AssertNoErrCode((err), __FILE__, __LINE__)} {$definec InitAssertions(name, version) InitAssertionsCode(name, version)} {$elsec} {$definec Assert(b)} {$definec AssertNoErr(err)} {$definec InitAssertions(name, version)} {$endc}
Assertions unit:
unit MyAssertions;
interface
{$ifc do_debug} procedure AssertCode( b: Boolean; const sourceFileName: String; sourceFileLine: Integer ); procedure AssertNoErrCode( err: OSStatus; const sourceFileName: String; sourceFileLine: Integer ); procedure InitAssertionsCode( const name: String; const version: String ); {$endc}
implementation
{$ifc do_debug}
var gAppName: String255; gAppVersion: String255; procedure InitAssertionsCode( const name: String; const version:
String ); begin gAppName := name; gAppVersion := version; end;
procedure AssertCode( b: Boolean; const sourceFileName: String;
sourceFileLine: Integer ); begin if not b then begin WriteLn( 'Assert: ' + gAppName + ' ' + gAppVersion + ' - '
sourceFileName + ':' + NumToStr( sourceFileLine ) ); end; end;
procedure AssertNoErrCode( err: OSStatus; const sourceFileName:
String; sourceFileLine: Integer ); begin if err <> noErr then begin WriteLn( 'Assert: Error=' + NumToStr(err) + ' ' + gAppName
- ' ' + gAppVersion + ' - ' + sourceFileName + ':' + NumToStr(
sourceFileLine ) ); end; end;
{$endc}
Obviously this can easily be extended to implement assertions any way you desire.
Please be aware that if you intend to compile out assertions (as you should for at least some assertions), then you must never include real code in your assert statement, eg:
Assert( (open( ... )) == 0 );
Rather you need to do
err = open( ... ); Assert( err == 0 );
Why do you have to compile out some assertions? Because you should be doing things like:
Assert( ValidDataStructure( complex_structure ) );
Where ValidDataStructure is walking through your complex structure ensuring it is all internally self consistent, which could be a significantly time consuming task. But that does not matter as it will be compiled out when you are performance tuning and in the shipping version.
The alternative is you would have to be very light weight with what you assert, or have two different classes of assertions (perhaps by using something like)
{$ifc do_heavy_debug} Assert( ValidDataStructure( complex_structure ) ); {$endc}
Enjoy, Peter.
Thank you for this detailed solution.
Bastiaan.