// Pruebas de expr con assert.
// Agreguen sus casos en cada función de prueba. Corran con: build/lab/expr_tests
#include <assert.h>
#include <stdio.h>
#include <string.h>

#include "expr.h"

// Escribe la expresión en un archivo temporal y la lee de vuelta en text.
static void print_to_text(const Expr *e, char *text, int size) {
    FILE *file = tmpfile();
    assert(file != NULL);
    expr_print(e, file);
    rewind(file);
    if (fgets(text, size, file) == NULL) {
        text[0] = '\0';
    }
    fclose(file);
}

static void test_constructors(void) {
    Expr *e = expr_binary(OP_ADD, expr_number(2.0), expr_variable("x"));
    assert(e != NULL);
    assert(e->kind == EXPR_BINARY);
    assert(e->as.binary.op == OP_ADD);
    assert(e->as.binary.left->kind == EXPR_NUMBER);
    assert(e->as.binary.left->as.number == 2.0);
    assert(e->as.binary.right->kind == EXPR_VARIABLE);
    assert(strcmp(e->as.binary.right->as.name, "x") == 0);
    expr_free(e);
}

static void test_print(void) {
    char text[100];
    // (2 + 3) * x
    Expr *e = expr_binary(OP_MUL, expr_binary(OP_ADD, expr_number(2.0), expr_number(3.0)),
                          expr_variable("x"));
    assert(e != NULL);
    print_to_text(e, text, sizeof text);
    assert(strcmp(text, "(2 + 3) * x") == 0);
    expr_free(e);
}

static void test_eval(void) {
    Env *env = env_new(NULL);
    assert(env != NULL);
    assert(env_set(env, "x", 4.0));
    // 2 + 3 * x
    Expr *e = expr_binary(OP_ADD, expr_number(2.0),
                          expr_binary(OP_MUL, expr_number(3.0), expr_variable("x")));
    assert(e != NULL);
    double value = 0.0;
    assert(expr_eval(e, env, &value) == 1);
    assert(value == 14.0);
    expr_free(e);
    env_free(env);
}

// Sesión 2: escriban una función de prueba por cada función nueva, y llámenlas desde main.

int main(void) {
    test_constructors();
    test_print();
    test_eval();

    printf("Todas las pruebas pasaron\n");
    return 0;
}
