www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - unittest which uses a disk file

reply Victor Porton <porton narod.ru> writes:
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?
Jan 16
next sibling parent Victor Porton <porton narod.ru> writes:
On Wednesday, 16 January 2019 at 21:07:24 UTC, Victor Porton 
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?
Also if I choose to put any tests in main.d, should these tests be within unittest { }? main.d is anyway meant to be compiled only in unittest mode, so I'm unsure.
Jan 16
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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.
Jan 16
parent reply Victor Porton <porton narod.ru> writes:
This way I would make data duplication (data files distributed 
with the source and the same data embedding as strings into my D 
sources).

Note that the source is multilingual (I am currently working on a 
multi-language bindings of a C library).
Jan 16
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Jan 17, 2019 at 12:58:20AM +0000, Victor Porton via Digitalmars-d-learn
wrote:
 This way I would make data duplication (data files distributed with
 the source and the same data embedding as strings into my D sources).
[...] You could use -J and string imports, perhaps? In any case, if you only ever need to run unittests from within a main() that never gets run by user code, then you could just version your unittests like somebody else has suggested. Then you could just make assumptions about the current working directory and so on in your tests.
 Note that the source is multilingual (I am currently working on a
 multi-language bindings of a C library).
Not sure what this has to do with your question. T -- The two rules of success: 1. Don't tell everything you know. -- YHL
Jan 16
prev sibling parent Neia Neutuladh <neia ikeran.org> writes:
On Wed, 16 Jan 2019 21:07:24 +0000, Victor Porton 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 easy way of doing things is to define a version for your library's unittests. Like I might write: version (EpubTest) unittest { writeEbookFile("test.epub"); } And then in dub.sdl, I'd have the test configuration add -version=EpubTest. Dub has support for this sort of thing, but I don't know the details offhand. If you have extra dependencies or need extra environment setup, you might want to make a second dub package inside the same repository and give it a path-based dependency on your library. Normal people won't touch that second package, so you can do whatever you want there, and it's a good place to add another README.
Jan 16