# Copyright:    2010 Paul Obermeier (obermeier@tcl3d.org)
#
#               See the file "Tcl3D_License.txt" for information on 
#               usage and redistribution of this file, and for a
#               DISCLAIMER OF ALL WARRANTIES.
#
# Description:  Tcl script to create a GoogleMock file as described in
#               Daniel Rákos blog entry "Unit testing OpenGL applications":
#               http://rastergrid.com/blog/2010/02/unit-testing-opengl-applications/
#
#               Note: This script needs at least Tcl3D version 0.4.1.
#               If using Tcl3D 0.4.1, only mockup methods for OpenGL functions
#               are created.
#               If using Tcl3D 0.4.2 or newer, additional mockup methods for
#               GLU functions are created.
#
#               The script reads in a mockup template file "glmock-template.txt".
#               This template file can be adapted to your specific needs.

package require tcl3d 0.4.1

# Name of the generated mock file.
set mockFile "glmock.h"

# Name of the mock template file. 
set mockTmplFile "glmock-template.txt"

puts "OpenGL GoogleMock Creator Version 1.0"

# Check Tcl3D version, as some procedures have a slightly changed signature.
if { [package vcompare [package versions tcl3d] "0.4.2"] < 0 } {
    puts "Using Tcl3D version < 0.4.2"
    proc GetFuncList {} {
        return [tcl3dOglGetFuncList]
    }
    proc GetFuncSignature { func index } {
        return [lindex [tcl3dOglGetFuncSignatureList] $index]
    }
} else {
    puts "Using Tcl3D version >= 0.4.2"
    proc GetFuncList {} {
        return [tcl3dOglGetFuncList "all"]
    }
    proc GetFuncSignature { func index } {
        return [tcl3dOglGetFuncSignature $func]
    }
}

# Generate a mock class method name out of OpenGL function func.
proc GenMethodName { func } {
    # Version 1: Use OpenGL name.
    # return $func

    # Version 2: Remove gl or glu prefix.
    if { [string match "glu*" $func] } {
        return [string range $func 3 end]
    } else {
        return [string range $func 2 end]
    }
}

# Read the template file into a Tcl string. This string will be searched
# for the keywords %CLASS% and %DEFINES%, which will be replaced with
# the actual mockup code.
puts "Reading template file $mockTmplFile ..."
set fp [open $mockTmplFile "r"]
set tmplStr [read $fp]
close $fp

# Build up the Mockup class definition.
set    classStr "class CGLMock \{\n"
append classStr "public:\n"

set index 0
foreach func [GetFuncList] {
    # Get signature of OpenGL function func.
    set sig [GetFuncSignature $func $index]
    set sigNoFuncName [string map [list $func ""] $sig]

    # Get number of arguments of OpenGL function func.
    set startInd [string first "(" $sigNoFuncName]
    set argsStr  [string trim [string range $sigNoFuncName $startInd end] "()"]
    if { $argsStr eq "void" || $argsStr eq "" } {
        set numArgs 0
    } else {
        set argsList [split $argsStr ","]
        set numArgs [llength $argsList]
    }

    # Generate method name for OpenGL function func.
    set methodName [GenMethodName $func]

    append classStr [format "    MOCK_METHOD%d( %s, %s );\n" \
                     $numArgs $methodName $sigNoFuncName]
    incr index
}

append classStr "\};\n"

# Build up the fake definitions.
set defineStr ""
foreach func [GetFuncList] {
    set methodName [GenMethodName $func]
    append defineStr "#undef $func\n"
    append defineStr "#define $func GLMock.$methodName\n"
}

# Substitute the 2 keywords in the mockup template.
regsub "%CLASS%"   $tmplStr $classStr  tmplStr
regsub "%DEFINES%" $tmplStr $defineStr tmplStr

puts "Writing mockup file $mockFile ..."
set fp [open $mockFile "w"]
puts $fp $tmplStr
close $fp

puts "Done."
exit 0
