Thread overview
File-like option where the "file contents" comes from a string?
Nov 27
monkyyy
Nov 27
Dennis
November 27

Again and again for testing I run into how nice it would be to have an open "File" which has its contents set by the unit test code:

>

auto f = StringFile("my test data...", "r");

I've searched high and low without discovering something which would fit the bill.

Thanks in advance,
Andy

November 26
On 11/26/24 5:12 PM, Andy Valencia wrote:
> Again and again for testing I run into how nice it would be to have an open "File" which has its contents set by the unit test code:
> 
>> auto f = StringFile("my test data...", "r");
> 
> I've searched high and low without discovering something which would fit the bill.
> 
> Thanks in advance,
> Andy
> 

An earlier post by H. S. Teoh may be helpful:

 https://forum.dlang.org/post/mailman.10192.1685482943.31357.digitalmars-d@puremagic.com

Ali
November 27
On Wednesday, 27 November 2024 at 02:43:21 UTC, Ali Çehreli wrote:
> On 11/26/24 5:12 PM, Andy Valencia wrote:
>> Again and again for testing I run into how nice it would be to have an open "File" which has its contents set by the unit test code:
>> 
>>> auto f = StringFile("my test data...", "r");
> An earlier post by H. S. Teoh may be helpful:
> https://forum.dlang.org/post/mailman.10192.1685482943.31357.digitalmars-d@puremagic.com

Thank you.  It's somewhat bemusing to, in essence, wrap the entirety of an implementation around a #define just to slot in an alternative to File.  With my OO programming goggles on, I can't help but notice that if Phobos had made File a class--or an interface--then it would be possible through simple type compatibility to have a FileFile instance which would satisfy the File API using the filesystem, and as no special case have a StringFile which did the same from the body of a string.

But I used your suggested approach, and it does indeed work nicely.  Thank you again.

Andy

November 27

On Wednesday, 27 November 2024 at 01:12:23 UTC, Andy Valencia wrote:

>

Again and again for testing I run into how nice it would be to have an open "File" which has its contents set by the unit test code

I don't know what situation you're in so this may not be applicable, but I personally rarely use mocks, because I write my code as pure as possible and push dependencies on the file system / environment / user interface etc. to the top. For example, instead of:

void main(string[] args)
{
    writeln(lineCount(File(args[1], "r")));
}

int lineCount(File f) => f.byLine.walkLength;

unittest
{
    // Annoyingly need to create file with test input
    assert(lineCount(StringFile("Good\nday")) == 2);
}

You can also write it like:

void main(string[] args)
{
    writeln(lineCount(cast(string) read(args[1])));
}

int lineCount(string f) pure => f.splitter('\n').walkLength;

unittest
{
    assert(lineCount("Good\nday") == 2);
}

This is a toy example. Again, you may have constraints that don't allow structuring your code like that, but it's worth considering.

November 27
On Wednesday, 27 November 2024 at 14:37:03 UTC, Andy Valencia wrote:
> With my OO programming goggles on, I can't help but notice that if Phobos had made File a class--or an interface--

oo doesn't own polymorphism you could do 99% of the value with

```d
struct dummyfile{
  auto byLineCopy()=>//string.spiltter('\n')....
}

auto myfunc(F)(F file){
  foreach(s;file.byLineCopy){
    ...
  }
}
unittest{ assert(
  dummyfile(q{
    ...
  }).myfunc
  == ...);
}
```
November 27
On Wednesday, 27 November 2024 at 20:38:22 UTC, monkyyy wrote:
> On Wednesday, 27 November 2024 at 14:37:03 UTC, Andy Valencia wrote:
>> With my OO programming goggles on, I can't help but notice that if Phobos had made File a class--or an interface--
>
> oo doesn't own polymorphism you could do 99% of the value with
>
> ```d
> struct dummyfile{
>   auto byLineCopy()=>//string.spiltter('\n')....
> }
>
> auto myfunc(F)(F file){
>   foreach(s;file.byLineCopy){
>     ...
>   }
> }

Yes, the page pointed to by Ali Çehreli up above shows this, thus my comment about how OO techniques avoid the "big hammer" of macro expansion (well, template expansion...).

Andy

November 28

On Wednesday, 27 November 2024 at 01:12:23 UTC, Andy Valencia wrote:

>

Again and again for testing I run into how nice it would be to have an open "File" which has its contents set by the unit test code:

>

auto f = StringFile("my test data...", "r");

I've searched high and low without discovering something which would fit the bill.

On Linux, you could use fmemopen to get a FILE* pointing to an in-memory buffer, and File.wrapFile to convert that into a D File object. Keep in mind if you do this that you will have to manually fclose the FILE* when you're done with it.

Another possibility is to change your function so that it takes a range as its input instead of a File. Then, you can pass a string for testing, and something like File.byLine(Yes.keepTerminator).joiner when you want to read from an actual file. The downside of this approach is that you will either have to make your function a template, or use std.range.interfaces and wrap the inputs with inputRangeObject.