This section offers a step-by-step explanation of how svnmock emulates the Subversion API.
This section offers a step-by-step explanation of how svnmock emulates the Subversion API.
When you import the root svnmock package or one of its submodules, the following series of operations is kicked off:
The imported subpackage (or all subpackages, in the case of import svnmock) imports its corresponding module in the svn. namespace, aka, the module to be emulated.
For example, the svnmock.repos subpackage would import svn.repos, and so on down the line.
We then iterate over all members of the svn.* modules; if the object is not callable, we make a reference to it in the appropriate svnmock.* module (this step passes through all constants, for example).
If the object is callable, the svnmock.* module instead receives a wrapper function that, when called, passes control back to svnmock.mock;
this is how we check to make sure that the right function was called with the right arguments.
These wrapper functions are not merely aliases for a single common function nor closures, but rather compiled from a template. This is done so that the generated function can pass itself as an argument, something that would make for ugly code otherwise.
Once all constants have been passed through and all the appropriate wrapper functions have been generated, the root svnmock module exercises some trickery.
In order to make the emulate transparent (i.e., that your code never knows it's not calling the real svn.fs.foo function), svnmock goes out and steals the svn.* namespace.
This is done by replacing svn's entry in sys.modules.
When you call a function in the svn.* namespace, that call eventually gets redirected back to a function in the svnmock.mock module.
This function first checks to make sure a MockSession instance exists, then forwards the function call to the MockSession for inspection.
The MockSession object will then re-re-re-forward the function call to the next State object in its queue, or if the queue is empty, it will raise an exception.
What the State object then does with the function call is up to it.