Search code examples
unit-testingtemplatesd

template alias causes unit test failure


I'm a freshfaced D newbie and I'm very interested in exploiting all that it has to offer. I'm currently in the process of turning a large codebase I have in C++ into D for education. I've barely started though and I'm reaching some weird inconsistency. I have a template struct with a constructor and a unittest for that constructor, (hope i'm using it right). It seems to verify correctly. However, if I make a type alias at the bottom of the file to a specific templated struct, I get an exception within the unittest.

main.d

import math;

int main() {

    return 0;
}

math.d

import std.math;
import std.stdio;

struct Vector2(T) {
    T[2] vec = [0, 0];

    @property const T x() {return vec[0];}
    @property inout(T) x(inout(T) val) {return vec[0] = val;}
    @property const T y() {return vec[1];}
    @property inout(T) y(inout(T) val) {return vec[1] = val;}

    this(T x, T y) {
        this.x = x;
        this.y = y;
    }
    unittest {
        Vector2!int a = Vector2!int(2, 2);
        assert(a.x == 2 && a.y == 2);

        Vector2!float b = Vector2!float(2.2, 2.2);
        assert(b.x == 2.2 && b.y == 2.2);  // <-- this line excepts given alias
    }
}

// if this is not here, no problem.
// if it is here "[email protected](21): unittest failure"
alias Vector2f = Vector2!float;

why does the presence of an alias cause a unit test to fail? I am using this command to build:

dmd -unittest main.d math.d

I use Windows 10, DMD version 2.070.2, and msys2 shell


Solution

    1. A template itself is not (and in general, cannot be) unittested. Only its instantiated instances are.

    2. Since 2.2 cannot be exactly represented in a floating-point variable, the double closest to 2.2 is not the same as the float closest to 2.2. If you change the lines to the following (2.2f is a float constant, 2.2 is a double constant), the test succeeds just fine:

          Vector2!float b = Vector2!float(2.2f, 2.2f);
          assert(b.x == 2.2f && b.y == 2.2f);  // <-- no exception
      

    Generally, one should avoid comparing floating-point variables directly unless they really know what they are doing. In D, one may want to use std.math.approxEqual to compare them.