TEST_F(ParserTests_Types, TupleOfTwoInts) {
    ASTNode* node = this->parseNode("(Int, Int) value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ(DataType::Tuple, node->dataType().kind());
    ASSERT_EQ(2, node->dataType().subtypeCount());
    ASSERT_EQ(DataType::Integer, node->dataType().subtypeAtIndex(0).kind());
    ASSERT_EQ(DataType::Integer, node->dataType().subtypeAtIndex(1).kind());
}
TEST_F(ParserTests_Types, GlobalIntWithWidthSpecifier) {
    ASTNode* node = this->parseNode("Int:32 value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ(DataType::Integer, node->dataType().kind());
    ASSERT_EQ(32, node->dataType().widthSpecifier());
    ASSERT_EQ(0, node->dataType().alignmentSpecifier());
    ASSERT_EQ(0, node->dataType().vectorSizeSpecifier());
}
TEST_F(ParserTests_Types, GlobalReal) {
    ASTNode* node = this->parseNode("Real value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ(DataType::Real, node->dataType().kind());
    ASSERT_EQ(0, node->dataType().widthSpecifier());
    ASSERT_EQ(0, node->dataType().alignmentSpecifier());
    ASSERT_EQ(0, node->dataType().vectorSizeSpecifier());
}
TEST_F(ParserTests_Types, GlobalClosureWithReturn) {
    ASTNode* node = this->parseNode("{} -> Int value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ(DataType::Closure, node->dataType().kind());
    ASSERT_EQ(0, node->dataType().subtypeCount());
    ASSERT_EQ(1, node->dataType().parameterCount());
    ASSERT_EQ(1, node->dataType().returnCount());
    ASSERT_EQ(DataType::Integer, node->dataType().returnType().kind());
}
TEST_F(ParserTests_Types, GlobalClosureTakingAPointerParam) {
    ASTNode* node = this->parseNode("{*Int} -> Void value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ(DataType::Closure, node->dataType().kind());
    ASSERT_EQ(0, node->dataType().subtypeCount());
    ASSERT_EQ(2, node->dataType().parameterCount());
    ASSERT_EQ(DataType::Pointer, node->dataType().parameterAtIndex(1).kind());
    ASSERT_EQ(DataType::Void, node->dataType().returnType().kind());
}
TEST_F(ParserTests_Types, GlobalFunctionTakingAPointerParam) {
    ASTNode* node = this->parseNode("(*Int) -> Void value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ(DataType::Function, node->dataType().kind());
    ASSERT_EQ(0, node->dataType().subtypeCount());
    ASSERT_EQ(1, node->dataType().parameterCount());
    ASSERT_EQ(DataType::Pointer, node->dataType().parameterAtIndex(0).kind());
    ASSERT_EQ(DataType::Void, node->dataType().returnType().kind());
}
TEST_F(ParserTests_Types, GlobalFunction) {
    ASTNode* node = this->parseNode("() -> Void value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ("value", node->name());
    ASSERT_EQ(DataType::Function, node->dataType().kind());
    ASSERT_EQ(0, node->dataType().subtypeCount());
    ASSERT_EQ(0, node->dataType().parameterCount());
    ASSERT_EQ(DataType::Void, node->dataType().returnType().kind());
}
TEST_F(ParserTests_Types, GlobalArrayOfPointersToInt) {
    ASTNode* node = this->parseNode("[3]*Int value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ(DataType::Array, node->dataType().kind());
    ASSERT_EQ(3, node->dataType().arrayCount());
    ASSERT_EQ(DataType::Pointer, node->dataType().subtypeAtIndex(0).kind());
    ASSERT_EQ(1, node->dataType().subtypeAtIndex(0).subtypeCount());
    ASSERT_EQ(DataType::Integer, node->dataType().subtypeAtIndex(0).subtypeAtIndex(0).kind());
}
TEST_F(ParserTests_Types, GlobalMutableBooleanMutablePointer) {
    ASTNode* node = this->parseNode("*!Bool! value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ("Variable Declaration", node->nodeName());
    ASSERT_EQ("value", node->name());
    EXPECT_EQ(DataType::Pointer, node->dataType().kind());
    EXPECT_EQ(DataType::Access::ReadWrite, node->dataType().access());
    ASSERT_EQ(1, node->dataType().subtypeCount());
    EXPECT_EQ(DataType::Boolean, node->dataType().subtypeAtIndex(0).kind());
    EXPECT_EQ(DataType::Access::ReadWrite, node->dataType().subtypeAtIndex(0).access());
}
TEST_F(ParserTests_Types, GlobalUntyped) {
    ASTNode* node = this->parseNode("value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ("Variable Declaration", node->nodeName());
    ASSERT_EQ("value", node->name());
    ASSERT_EQ(DataType::Undefined, node->dataType().kind());
}
TEST_F(ParserTests_Types, GlobalClosure) {
    ASTNode* node = this->parseNode("{} -> Void value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ("value", node->name());
    ASSERT_EQ(DataType::Closure, node->dataType().kind());
    ASSERT_EQ(0, node->dataType().subtypeCount());
    ASSERT_EQ(1, node->dataType().parameterCount());
    ASSERT_EQ(DataType::Kind::Pointer, node->dataType().parameterAtIndex(0).kind());
    ASSERT_EQ(1, node->dataType().parameterAtIndex(0).subtypeCount());
    ASSERT_EQ(DataType::Kind::Void, node->dataType().parameterAtIndex(0).subtypeAtIndex(0).kind());
    ASSERT_EQ(DataType::Void, node->dataType().returnType().kind());
}
TEST_F(ParserTests_Types, GlobalClosureTakingTwoParams) {
    ASTNode* node = this->parseNode("{Int, Float} -> Void value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ(DataType::Closure, node->dataType().kind());
    ASSERT_EQ(0, node->dataType().subtypeCount());
    ASSERT_EQ(3, node->dataType().parameterCount());
    ASSERT_EQ(DataType::Integer, node->dataType().parameterAtIndex(1).kind());
    ASSERT_EQ(DataType::Float, node->dataType().parameterAtIndex(2).kind());
    ASSERT_EQ(DataType::Void, node->dataType().returnType().kind());
}
TEST_F(ParserTests_Types, GlobalFunctionWithTwoReturns) {
    ASTNode* node = this->parseNode("() -> (Int, Int) value\n");

    node = node->childAtIndex(0);

    ASSERT_EQ(DataType::Function, node->dataType().kind());
    ASSERT_EQ(0, node->dataType().subtypeCount());
    ASSERT_EQ(0, node->dataType().parameterCount());

    ASSERT_EQ(DataType::Tuple, node->dataType().returnType().kind());
    ASSERT_EQ(2, node->dataType().returnType().subtypeCount());
    ASSERT_EQ(DataType::Integer, node->dataType().returnType().subtypeAtIndex(0).kind());
    ASSERT_EQ(DataType::Integer, node->dataType().returnType().subtypeAtIndex(1).kind());
}