Intercepting system calls via LD_PRELOAD is a hugely useful approach for many situations. Got a binary-only piece of code that's creating ghost temp files you want to poke at? Intercept unlink(). Need to quickly (and dirtily) hack an executable that isn't designed for concurrency into sharing a file with other instances of itself? Intercept open().
On the flipside, when trying to do things as securely as possible, never blindly trust dynamic linkage into library functions: attackers can and will use such techniques against you. Reflections on Trusting Trust[1] becomes scarier when you start thinking about all the venues you open with dynamic library linkage.
I wish we had something like this on my last project. On my last project, there were two separate systems for determining the local Timestamp. One of them was based on the time from the local machine's clock. The other took time from a central mainframe/transaction processing system. (Call these system-A and system-B) We really could've used something like the article proposes for both systems.
Here's the thing: The application would calculate the timezone based on system-A, then use the time from system-B to do a lookup into a GMT-based table using system-B's time. All well and good, until the testers tried to test calling outside allowed hours by changing their local system clocks. This mess resulted in trying to look up entries in the table for timezones the middle of the Pacific. Boom!
The worst part? Trying to explain to the testers how this was an inherent flaw in the legacy system and not a result of the upgrade. (Yes, I would've changed it if I were allowed to.)
I've done this many times in both unit specs and Cucumber (what it looks like he's targetting), and I manage to get away with defining the Given step as stubbing Time.now. No need to get hairy with C at the low level.
That feels even more wrong for Haskell. I think that the Haskell way really is that you have pass the function in. Probably the worst thing about Haskell is that it aggressively has no concept of a global environment.
That said this may well be the most practical approach; "the Haskell way" and "practical" are not always exactly buddy-buddy. I'm just responding to the question of "the Haskell way".
I can see your point here, but since time is fundamentally an external datum provided by the system, in my view there's no reason to screw with Haskell's internals when you can just produce the necessary simulated environment in which your runtime lives. Moreover, by doing it this way you can use exactly the same code in testing as in production, reducing the risk of something going wrong when you change from the former to the latter codebase.
I totally agree. The OP came with a great way of simulating certain states of the external environment for the purpose of tests and completely independently of the implementation. This decoupling seems uber cool.
On the flipside, when trying to do things as securely as possible, never blindly trust dynamic linkage into library functions: attackers can and will use such techniques against you. Reflections on Trusting Trust[1] becomes scarier when you start thinking about all the venues you open with dynamic library linkage.
[1] http://cm.bell-labs.com/who/ken/trust.html