/*
 * Author: Jake G
 * Date: 2025
 * filename: test_ADC.c
 * description: Test groups for the ADC module. 
 */

//#include "CppUTest/CommandLineTestRunner.h"
#include "CppUTestExt/MockSupport.h"
#include <cstdint>

extern "C"
{
#include "ADC.h"
#include "ch32v003hw.h"
}

TEST_GROUP(tg_ADC)
{
    void   setup(){

    }
    void teardown()
    {
        mock().checkExpectations();
        mock().clear();
    }
};

TEST(tg_ADC, FirstTest)
{
    CHECK(true);
}

TEST(tg_ADC, ADC_PowerOnTest)
{
    // The ADCON bit should be high in the ADC_CTRL2 register.
    mock().expectOneCall("RegEdit_u32_SetBit").withPointerParameter("reg", (void *)&ADC1->CTLR2).withUnsignedIntParameter("bit_num", ADC_ADON);

    ADC_PowerOn();
}

TEST(tg_ADC, ADC_PowerOffTest)
{
    mock().expectOneCall("RegEdit_u32_ClearBit")
        .withPointerParameter("reg", (void *)&ADC1->CTLR2)
        .withUnsignedIntParameter("bit_num", ADC_ADON);

    ADC_PowerOff();
}

TEST(tg_ADC, ADC_SetupSetsRegisters)
{
    // R32_GPIOD_CFGLR --> 0x40011400
    // DESC: PD port configuration register low
    // RESET VALUE--> 0x44444444

    // R32_GPIOD_INDR --> 0x40011408
    // DESC: PD port input data register

    // R32_GPIOD_BSHR --> 0x40011410
    // DESC: PD port set/reset register

    // R32_GPIOD_BCR --> 0x40011414
    // DESC: PD port reset register

    // R32_GPIOD_LCKR --> 0x40011418
    // DESC: PD port configuration lock register

    // Setup the ADC clock and divider. The internal HSI-XC is 24MHz.

    // Setup PORTD pin(s) as analog input.

    /*
    //Clears control register A for ADC0
    mock().expectOneCall("RegEdit_SetNum")
        .withPointerParameter("reg", (void *) &ADC0.CTRLA)
        .withUnsignedIntParameter("num", 0x00);

    //Sets The sample accumulation number to 32.
    mock().expectOneCall("RegEdit_SetNum")
        .withPointerParameter("reg", (void *) &ADC0.CTRLB)
        .withUnsignedIntParameter("num", 0x5);

    //Sets the voltage reference to VDD or VCC.
    mock().expectOneCall("RegEdit_SetBit")
        .withPointerParameter("reg", (void *) &ADC0.CTRLC)
        .withUnsignedIntParameter("bit_num", 4);

    //Sets the pre-scalar for the adc sample rate.
    mock().expectOneCall("RegEdit_SetBit")
        .withPointerParameter("reg", (void *) &ADC0.CTRLC)
        .withUnsignedIntParameter("bit_num", 2);

    //Setup an Initalization delay.
    mock().expectOneCall("RegEdit_OR_Num")
        .withPointerParameter("reg", (void *) &ADC0.CTRLD)
        .withUnsignedIntParameter("num", (2<<5));

    //Set the bit for ADC variation during readings.
    mock().expectOneCall("RegEdit_SetBit")
        .withPointerParameter("reg", (void *) &ADC0.CTRLD)
        .withUnsignedIntParameter("bit_num", 4);

    */
    ADC_Setup();
}

TEST(tg_ADC, ADC_InitPortAPin7UsesCorrectRegisters)
{
    /*
    //Check for setting the direction to input.
    mock().expectOneCall("RegEdit_ClearBit")
        .withPointerParameter("reg", (void *) &PORTA.DIR)
        .withUnsignedIntParameter("bit_num", 7);

    //Check that the pullup is off
    mock().expectOneCall("RegEdit_ClearBit")
        .withPointerParameter("reg", (void *) &PORTA.OUT)
        .withUnsignedIntParameter("bit_num", 7);

    //Set the ISC(input sense config) to disable digital input
    //buffering and reduce the noise on ADC usage.
    mock().expectOneCall("RegEdit_SetBit")
        .withPointerParameter("reg", (void *) &PORTA.PIN7CTRL)
        .withUnsignedIntParameter("bit_num", PORT_ISC_INPUT_DISABLE_gc);

    */
    ADC_Init(7);
}

TEST(tg_ADC, ADC_InitPortAPin0UsesCorrectRegisters)
{
    /*
    //Check for setting the direction to input.
    mock().expectOneCall("RegEdit_ClearBit")
        .withPointerParameter("reg", (void *) &PORTA.DIR)
        .withUnsignedIntParameter("bit_num", 0);

    //Check that the pullup is off
    mock().expectOneCall("RegEdit_ClearBit")
        .withPointerParameter("reg", (void *) &PORTA.OUT)
        .withUnsignedIntParameter("bit_num", 0);

    //Set the ISC(input sense config) to disable digital input
    //buffering and reduce the noise on ADC usage.
    mock().expectOneCall("RegEdit_SetBit")
        .withPointerParameter("reg", (void *) &PORTA.PIN0CTRL)
        .withUnsignedIntParameter("bit_num", PORT_ISC_INPUT_DISABLE_gc);

    */

    ADC_Init(0);
}

TEST(tg_ADC, ADC_InitDoesNothingOnHighPinNumbers)
{
    // mock().expectNoCall("RegEdit_SetBit");
    ADC_Init(8);
}

TEST(tg_ADC, ADC_EnablePasses)
{
    /*
    mock().expectOneCall("RegEdit_SetBit")
        .withPointerParameter("reg", (void *) &ADC0.CTRLA)
        .withUnsignedIntParameter("bit_num", 0);

    */
    ADC_Enable();
}

TEST(tg_ADC, ADC_DisablePasses)
{
    /*
    mock().expectOneCall("RegEdit_ClearBit")
        .withPointerParameter("reg", (void *) &ADC0.CTRLA)
        .withUnsignedIntParameter("bit_num", 0);
    */
    ADC_Disable();
}

TEST(tg_ADC, ADC_SetPinSetsRightRegisters)
{
    /*
    //It clears existing MUXPOS register values.
    mock().expectOneCall("RegEdit_ClearRegister")
        .withPointerParameter("reg", (void *) &ADC0.MUXPOS);

    //It Correctly sets the pin number.
    mock().expectOneCall("RegEdit_SetNum")
        .withPointerParameter("reg", (void *) &ADC0.MUXPOS)
        .withUnsignedIntParameter("num", 4);

    */
    ADC_SetPin(4);
}

TEST(tg_ADC, ADC_SetPinFailsOnInvalidPin)
{
    ADC_SetPin(8);
}

static uint16_t ADC_ReadValueFake(uint8_t pin_num)
{
    return 512;
}

TEST_GROUP(tg_ADCRead){
    void setup(){
        UT_PTR_SET(ADC_ReadValue, ADC_ReadValueFake);
}

    void teardown()
    {
        mock().checkExpectations();
        mock().clear();
    }
};

TEST(tg_ADCRead, FunctionPointerSwapWorks)
{
    uint16_t value = ADC_ReadValue(0);

    LONGS_EQUAL(512, value);
}
