On Wed, Jan 16, 2019 at 09:07:24PM +0000, Victor Porton via Digitalmars-d-learn wrote: > What is the rule for unittest which uses a file (containing example > data for testing) available only in the source distribution, not in > binary distribution? > > I am writing a library. > > The library has also a file main.d which is compiled only in DUB > "application" configuration (I use this configuration solely for > testing.) > > Maybe I should put unittest { } into main.d not in the module which I > test? > > Also, what is the correct way to locate the file in the filesystem?
There is no rule about this as far as I know, but generally speaking, my advice is to avoid touching the filesystem from inside a unittest. This is not always possible, but where possible, I highly recommend templatizing the File type so that you can substitute it with an in-memory-only proxy in your unittest. For example, instead of: auto myFunc(Args...)(File fp, Args args) { ... fp.rawWrite(...); fp.rawRead(...); ... // etc. } unittest { auto testfile = File("testfile", "r+"); // <-- ugh auto r = myFunc(testfile, ...); ... } do something like this instead: auto myFunc(File = std.stdio.File, Args...)(File fp, Args args) { ... fp.rawWrite(...); fp.rawRead(...); ... // etc. } unittest { struct FakeFile { string fakedata = "blah blah blah"; void[] rawRead(...) { // copy fakedata into output buffer, // etc. } ... // ditto for any other method you might use } FakeFile testfile; // N.B.: no actual filesystem access auto r = myFunc(testfile, ...); ... } This way, you can verify your code logic using only in-memory test data, and you don't have to worry about polluting the filesystem with temporary files, cleaning up after your unittest is done, setting up paths, and all that messy stuff. Better yet, separate your code logic so that accessing the filesystem only happens in one place (e.g., in a user-facing API that takes filenames, say), and encapsulate the file data as a generic data source, so that the main logic of your code operates on the generic data source (e.g., an input range of chars or bytes, or whatever other structure most convenient for your logic) without any specific binding to std.stdio.File. Then it will be easy to pass in test data to your core logic without needing to use File or the FakeFile hack above. (The FakeFile hack is really only for testing low-level functions that are actually intended to interact directly with the filesystem; generally, I try to structure my code so that the "business logic" is independent of the filesystem. It just operates on whatever abstract data source is most convenient, whether a range, or even just a string buffer, or whatever. This makes it easy to test with non-file data, and avoids importing std.stdio everywhere (which IMO is a code smell). It also makes it easier to extend to other data sources in the future, like network data.) T -- Those who don't understand Unix are condemned to reinvent it, poorly.