Unittests, templates
bearophile
bearophileHUGS at lycos.com
Thu Oct 30 19:57:53 PDT 2008
I like to test all my functions, are there ways to unit test nested functions?
void foo() {
int add(int x, int y) {
return x + y;
}
unittest { // found 'unittest' instead of statement
assert(add(10, 20) == 30);
}
}
unittest {
assert(foo.add(10, 20) == 30); // Error: no property 'add' for type 'void'
}
void main() {}
If currently there's no way, I think it can be good to add to the language some way to test them.
----------------------
This is a question regarding templates. Let's say I have a simple struct template that is specified by an integer:
struct S(int N) {
int[N] a;
}
Now I'd like to write a function that takes a S, and for example prints the integers of S.a
separated by a space (I don't care of the extra space at the end).
This is easy to to in Haskell because it has type classes, but it's less easy to do in D (I don't know if type classes can be introduced into the D type system):
http://en.wikipedia.org/wiki/Type_class
This is a simple solution, but it compiles only if N == 2, so I'd like something more general:
void printS1(S!(2) s) {
foreach (el; s.a)
put(el, " ");
putr();
}
This is general, a function template, but it requires you to specify N:
void printS2(int N)(S!(N) s) {
foreach (el; s.a)
put(el, " ");
putr();
}
You have to call it for example like this:
printS2!(s.a.length)(s);
The following way ignores S, and just looks if the given type T has the requires qualities:
void printS3(T)(T s) {
static assert(is(T == struct) && (T.tupleof.length == 1) &&
is(typeof(T.a)) && is(ArrayType1!(typeof(T.a)) == int)
);
foreach (el; s.a)
put(el, " ");
putr();
}
(Where ArrayType1 gives the type of the items of T.a). printS3 isn't strict enough, because it accepts all typedef-ined types as long as they have that qualities. And if you change S a little, you have to change lot of code.
The following doesn't work, I don't know why:
void printSX(T)(T s) {
static assert ( is(T == S) );
...
So this is more strict, but requires more RAM during compilation, and it doesn't accept N > 13:
void printS4(T)(T s) {
//static assert (is(T == S), "printS4: err"); // doesn't work
static assert (IsType!(T, S!(0), S!(1), S!(2), S!(3), S!(4), S!(5), S!(6),
S!(7), S!(8), S!(9), S!(10), S!(11), S!(12), S!(13)
), "printS4: err");
foreach (el; s.a)
put(el, " ");
putr();
}
Of course that can be generalized, up to N =~ 2930 but it requires lot of RAM and some compilation time, so this can't be the way to go:
template IsTN(alias TN, T, int N=0) {
static if (N >= 2900 || N < 0) // 2900 is an arbitrary high value
const bool IsTN = false;
else static if ( is(T == TN!(N)) )
const bool IsTN = true;
else
const bool IsTN = IsTN!(TN, T, N+1);
}
void printS5(T)(T s) {
static assert (IsTN!(S, T), "printS5: err");
foreach (el; s.a)
put(el, " ");
putr();
}
To reduce the RAM used I have tried to use a CT function, but it doesn't work:
bool isTN(alias TN, T)() { // doesn't work
int i = 0;
while ( is(T == TN!(i)) ) {}
return true;
}
void printS6(T)(T s) {
static assert (isTN!(S, T)(), "printS6: err");
foreach (el; s.a)
put(el, " ");
putr();
}
I have tried with a recursive CT function, but it doesn't work still (maybe there are ways to make it run):
bool isTN2(alias TN, T)(int n=0) {
if (n >= 2900 || n < 0)
return false;
else if ( is(T == TN!(n)) )
return true;
else
return IsTN2!(TN, T)(n+1);
}
void printS8(T)(T s) {
static assert (isTN2!(S, T)(), "printS6: err");
foreach (el; s.a)
put(el, " ");
putr();
}
In the end changing totally approch it works and uses little RAM, but is this a good solution?
void printS7(T)(T s) {
static assert (S.stringof == "S(int N)", "printS7: err");
foreach (el; s.a)
put(el, " ");
putr();
}
Bye,
bearophile
More information about the Digitalmars-d-learn
mailing list