Is there a File-like object for unit tests?

Paul Backus snarwin at gmail.com
Tue Jan 4 17:48:24 UTC 2022


On Tuesday, 4 January 2022 at 17:01:41 UTC, Amit wrote:
> Hi!
>
> I wrote a text parser that takes a File argument and parses 
> that file's contents. Now I would like to write a unit-test for 
> that parser. I need a File (or a general IO interface) that 
> reads from an in-memory buffer, similar to python's `StringIO` 
> or go's `strings.Reader`.
>
> How can I achieve that?

Probably the easiest way to do it is to have your parser take a 
generic [range][1] as its argument instead of a `File`. Then you 
can pass in whatever source of data you like--a file, an 
in-memory buffer, a class that generates data on-the-fly--and it 
will all Just Work.

For example, here's a function that parses an integer from an 
input range:

```d
import std.range;

int parseInteger(Input)(Input input)
     if (isInputRange!Input && is(typeof(input.front - '0') : int))
{
     import std.ascii: isDigit;
     import std.exception: enforce;

     int result = 0;
     bool success = false;

     while (!input.empty && input.front.isDigit)
     {
         success = true;
         result *= 10;
         result += input.front - '0';
         input.popFront;
     }

     enforce(success, "input did not contain an integer");
     return result;
}

unittest
{
     import std.ascii: isDigit;
     import std.algorithm: filter;
     import std.exception: assertThrown;

     // can use strings
     assert(parseInteger("123") == 123);
     assert(parseInteger("123 hello") == 123);

     // can use arbitrary range types
     assert(parseInteger("321".retro) == 123);
     assert(parseInteger("a1b2c3".filter!isDigit) == 123);

     // failure cases
     assertThrown!Exception(parseInteger("hello"));
     assertThrown!Exception(parseInteger(""));
}
```

[1]: https://dlang.org/phobos/std_range.html



More information about the Digitalmars-d-learn mailing list