<commit_before>#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <TimerOne.h>
#include <LiquidCrystal_I2C.h>
#include <ClickEncoder.h>

#include "ad5541.h"
#include "adc.h"
#include "button.h"
#include "fan.h"
#include "setter.h"
#include "lm35.h"

// Hardware Configuration
#define LCD_IIC_ADDRESS      0x20
#define LCD_IIC_COLS         16
#define LCD_IIC_ROWS         2

#define ENCODER_PIN_1        A0
#define ENCODER_PIN_2        A1
#define ENCODER_SW_PIN       2
#define ENCODER_UPDATE_RATE  4

#define ADC_CS_PIN           8
#define DAC_CS_PIN           9

#define BUTTON_1_PIN         3
#define BUTTON_2_PIN         4
#define BUTTON_3_PIN         6
#define BUTTON_4_PIN         5

#define FAN_SW_PIN           7
#define LM35_PIN             A3

#define MAX_BUTTON           4

#define ADC_CURRENT_CHN      AD7190_CH_AIN2P_AINCOM
#define ADC_VOLTAGE_CHN      AD7190_CH_AIN1P_AINCOM

// Constants
const double VREF_VOLTAGE = 5000.0;  // mV

const double MAX_WATTAGE = 200.0;

const double MAX_CURRENT = 15.0;

const double MAX_TEMPERATURE = 95.0;

const int MAX_PAGE = 3;

const double PID_K_COEFF = 0.0;
const double PID_I_COEFF = 0.0;
const double PID_D_COEFF = 0.0;

///////////////////////
// Devices
///////////////////////

// DAC
AD5541 ad5541(DAC_CS_PIN);

// ADC
ADConverter adc(ADC_CS_PIN,
                ADC_VOLTAGE_CHN,
                ADC_CURRENT_CHN,
                VREF_VOLTAGE);

// LCD
LiquidCrystal_I2C lcd(LCD_IIC_ADDRESS,
                      LCD_IIC_COLS,
                      LCD_IIC_ROWS);

// encoder
ClickEncoder encoder(ENCODER_PIN_1,
                     ENCODER_PIN_2,
                     ENCODER_SW_PIN,
                     ENCODER_UPDATE_RATE);

// Buttons
Button buttons[MAX_BUTTON] {
    BUTTON_1_PIN,
    BUTTON_2_PIN,
    BUTTON_3_PIN,
    BUTTON_4_PIN,
};

// FAN
FanController fan(FAN_SW_PIN);

// temperature sensor
LM35 lm35(LM35_PIN, VREF_VOLTAGE);

// Setter (max 15000mA)
Setter<(int32_t)(MAX_CURRENT * 1000.0)> current_set_point;
// Cut off voltage set
Setter<99999l> voltage_set_point;

char buffer[200];
// 0 - 4 current 5 - 9 cut off voltage
int8_t setter_position = 4;
const int MAX_SET_POSITION = 10;

//////////////////////////////
// Operations
//////////////////////////////

enum OPTERATION_STATE
{
    STATE_IDLE = 1,
    STATE_RUNNING = 2,
    STATE_CALIBRATION = 10,

    STATE_UNDEF = 99,
};

// Global Data
struct {

    // status
    OPTERATION_STATE state;
    uint32_t state_time;

    double mah;
    uint32_t mah_time;

    // page
    int page;

} g_cb { STATE_IDLE, 0, 0, 0, 0 };

double p_term = 0.0, i_term = 0.0, d_term = 0.0;

// timer service
void timer_one_isr()
{
    encoder.service();
}

void UpdateButtons()
{
    for (int i = MAX_BUTTON; i > 0; i--) {
        buttons[i - 1].update();
    }
}

void UpdateCurrentVoltage()
{
    // update current data, no need for idle
    if (g_cb.state != STATE_IDLE) {
        adc.updateCurrent();
    } else {
        adc.resetCurrent();
    }
    // update voltage
    adc.updateVoltage();
}

void UpdateTemperature()
{
    lm35.update();
}

void UpdateSensors()
{
    // update inputs
    UpdateButtons();

    // sensors
    UpdateCurrentVoltage();
    UpdateTemperature();
}

/// Display a double with Fixed length
void DisplayFixedDouble(double value, int width, int prec)
{
    char line[20];
    dtostrf(value, width, prec, line);
    int len = strlen(line);
    if (len > width) {
        // if we have longger value, truncate it
        line[width] = '\0';
    } else {
        // if the first one is space then we have leading spaces
        if (line[0] == ' ') {
            for (char* p = strchr(line, ' '); p; p = strchr(line, ' ')) {
                *p = '0';
            }
        }
    }
    lcd.print(line);
}

void UpdateDisplay()
{
    lcd.noCursor();

    // Display
    // Line 1 - Current Set Point, temperature:
    //   aa.aaaA ttt.ttC X
    lcd.setCursor(0, 0);
    DisplayFixedDouble(current_set_point.as_double(), 6, 3);
    lcd.print("A ");
    DisplayFixedDouble(voltage_set_point.as_double(), 6, 3);
    lcd.print("V");

    // FIXME: print out status
    switch (g_cb.state) {
        case STATE_IDLE:
            lcd.print(" ");
            break;
        case STATE_RUNNING:
            lcd.print("*");
            break;
        default:
            lcd.print("?");
    }

    // Line 2 - Current Sensing, Voltage Sensing:
    //   ss.ssssA vvv.vvvV
    lcd.setCursor(0, 1);

    if (g_cb.page == 0) {
        DisplayFixedDouble(adc.readCurrent(), 6, 3);
        lcd.print("A ");
        DisplayFixedDouble(adc.readVoltage(), 6, 3);
        lcd.print("V ");
    } else if (g_cb.page == 1) {
        double wattage = adc.readVoltage() * adc.readCurrent();
        DisplayFixedDouble(wattage, 8, 4);
        lcd.print("W ");
        DisplayFixedDouble(lm35.getTemperature(), 5, 2);
        lcd.print("C            ");
    } else if (g_cb.page == 2) {
        lcd.print(g_cb.mah);
        lcd.print("mAh          ");
    }

    // positiont the cursor for showing
    // current 01.345A 89.123V
    uint8_t bit = setter_position;
    if (setter_position >= 2) {
        bit++;
    }
    if (setter_position > 4) {
        bit += 2;
    }
    if (setter_position >= 7) {
        bit++;
    }
    lcd.setCursor(bit, 0);
    lcd.cursor();

}

static uint32_t last;
static double last_input;
static double e_sum;
static double pid_sum;
static double e;

void StopDischarge()
{
    g_cb.state = STATE_IDLE;
    ad5541.setValue(0);
}

void StartDischarge()
{
    uint32_t now = millis();
    g_cb.state = STATE_RUNNING;
    g_cb.state_time = now;
    ad5541.setValue(0);
    e_sum = 0.0;
    last_input = 0.0;
    g_cb.mah = 0;
    g_cb.mah_time = now;
}

void ProcessControl()
{
    uint32_t now = millis();

    // abort contitions
    if (adc.readCurrent() > (MAX_CURRENT * 1.1) ||
        adc.readVoltage() < voltage_set_point.as_double() ||
        lm35.getTemperature() > MAX_TEMPERATURE)
    {
        StopDischarge();
    }

    // temperature control
    if (lm35.getTemperature() > 40.0 && !fan.isOn()) {
        fan.turn_on();
    } else if (lm35.getTemperature() < 35.0 && fan.isOn()) {
        fan.turn_off();
    }

    // configuration setter control
    if (buttons[1].isRaisingEdge()) {
        setter_position = (setter_position - 1) % MAX_SET_POSITION;
        if (setter_position < 0) {
            setter_position += MAX_SET_POSITION;
        }
    } else if (buttons[2].isRaisingEdge()) {
        setter_position = (setter_position + 1) % MAX_SET_POSITION;
    }
    // find which to set
    if (setter_position < 5) {
        current_set_point.set_position(setter_position);
        current_set_point.change(encoder.getValue());
    } else {
        voltage_set_point.set_position(setter_position - 5);
        voltage_set_point.change(encoder.getValue());
    }

    // display control
    if (buttons[3].isRaisingEdge()) {
        g_cb.page = (g_cb.page + 1) % MAX_PAGE;
    }

    // FIXME: We should not run PID if not running
    pid_sum = 0.0;
    e = 0.0;
    p_term = 0.0;
    i_term = 0.0;
    d_term = 0.0;
    if (now - last >= 10) {
        // accumulate mah
        g_cb.mah += adc.readCurrent() * (now - last) / 3600;

        double current_set_p = current_set_point.as_double();
        // We must limit the max wattage to IRFP250 MAX
        if (current_set_p * adc.readVoltage() > MAX_WATTAGE) {
            current_set_p = MAX_WATTAGE / adc.readVoltage();
        }
        // calc PIDd
        e = current_set_p - adc.readCurrent();
        if (e > -0.001 && e < 0.001) {
            e = 0.0; // dead band
        }
        p_term = e * 2289.0; // _kP
        e_sum += 0.00036 * e * (now - last);
        // e_sum = constrain(e_sum, -15, 15);
        i_term = e_sum;
        d_term = (adc.readCurrent() - last_input) / (now - last) * 366.0;
        pid_sum = p_term + i_term - d_term;
        // double pid_sum = p_term;
        // pid_sum *= 3.5;
        last = now;
        last_input = adc.readCurrent();
    }

    int32_t set_point = (int32_t)ad5541.getValue();
    set_point += (int32_t)pid_sum;
    set_point = constrain(set_point, AD5541_CODE_LOW, AD5541_CODE_HIGH);

    if (buttons[0].isActive()) {
        lcd.clear();
        lcd.home();
        // lcd.print(e);
        // lcd.print(" ");
        // lcd.print(pid_sum);
        // lcd.print(" ");
        // lcd.print(set_point, HEX);
        // lcd.print(ad5541.getValue(), HEX);
        // lcd.setCursor(0, 1);
        // lcd.print(p_term);
        // lcd.print(" ");
        // lcd.print(i_term);
        // lcd.print(" ");
        // lcd.print(d_term);
        lcd.print(setter_position);
        delay(800);
    }

    // State change event
    ClickEncoder::Button encoder_btn = encoder.getButton();
    if (g_cb.state == STATE_IDLE &&
        encoder_btn == ClickEncoder::Held &&
        g_cb.state_time + 3000.0 < now)
    {
        // IDLE -> RUNNING
        StartDischarge();
    }
    else if (g_cb.state == STATE_RUNNING)
    {
        if (encoder_btn == ClickEncoder::Clicked)
        {
            StopDischarge();
        }
        else
        {
            ad5541.setValue((uint16_t)set_point);
        }
    }
}

void setup()
{
    // initialize state to idle
    g_cb.state = STATE_IDLE;

    // LCD
    lcd.init();
    lcd.home();
    lcd.print("@DC Active Load@");
    lcd.setCursor(0, 1);
    lcd.print("       20171002");
    lcd.home();

    //
    delay(400);

    lcd.clear();
    lcd.print(1);

    // SPI
    SPI.begin();
    lcd.print(2);

    // DAC
    ad5541.begin();
    ad5541.setValue(0);
    lcd.print(3);

    // Timer
    Timer1.initialize(1000);
    Timer1.attachInterrupt(timer_one_isr);
    lcd.print(4);

    // temperature
    lm35.init();
    lcd.print(5);

    // ADC
    adc.begin();
    while (!adc.detectDevice()) {
        lcd.clear();
        lcd.print("ADC ERROR");
        delay(300);
    }
    lcd.print("z");
    delay(10);
    adc.init();
    delay(10);
    lcd.print("a");
    // FIXME: Calibration data should be gotten from EEPROM
    adc.setCalibData(AD7190_CONF_GAIN_1, 1.00080, 4.0);
    lcd.print("b");
    adc.setCalibData(AD7190_CONF_GAIN_8, 1.00243, -0.60);
    lcd.print(6);

    // Buttons
    buttons[0].init();
    buttons[1].init();
    buttons[2].init();
    buttons[3].init();
    lcd.print(7);

    // FAN
    fan.init();
    lcd.print(8);

    // get lcd ready for using information
    delay(400);
    lcd.clear();
}

void loop()
{
    // Read Information
    UpdateSensors();
    // TODO: Controller logic
    ProcessControl();
    // Output:
    UpdateDisplay();
}

<commit_msg>Add couner for wattage hour<commit_after>#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <TimerOne.h>
#include <LiquidCrystal_I2C.h>
#include <ClickEncoder.h>

#include "ad5541.h"
#include "adc.h"
#include "button.h"
#include "fan.h"
#include "setter.h"
#include "lm35.h"

// Hardware Configuration
#define LCD_IIC_ADDRESS      0x20
#define LCD_IIC_COLS         16
#define LCD_IIC_ROWS         2

#define ENCODER_PIN_1        A0
#define ENCODER_PIN_2        A1
#define ENCODER_SW_PIN       2
#define ENCODER_UPDATE_RATE  4

#define ADC_CS_PIN           8
#define DAC_CS_PIN           9

#define BUTTON_1_PIN         3
#define BUTTON_2_PIN         4
#define BUTTON_3_PIN         6
#define BUTTON_4_PIN         5

#define FAN_SW_PIN           7
#define LM35_PIN             A3

#define MAX_BUTTON           4

#define ADC_CURRENT_CHN      AD7190_CH_AIN2P_AINCOM
#define ADC_VOLTAGE_CHN      AD7190_CH_AIN1P_AINCOM

// Constants
const double VREF_VOLTAGE = 5000.0;  // mV

const double MAX_WATTAGE = 200.0;

const double MAX_CURRENT = 15.0;

const double MAX_TEMPERATURE = 95.0;

const int MAX_PAGE = 4;

const double PID_K_COEFF = 0.0;
const double PID_I_COEFF = 0.0;
const double PID_D_COEFF = 0.0;

///////////////////////
// Devices
///////////////////////

// DAC
AD5541 ad5541(DAC_CS_PIN);

// ADC
ADConverter adc(ADC_CS_PIN,
                ADC_VOLTAGE_CHN,
                ADC_CURRENT_CHN,
                VREF_VOLTAGE);

// LCD
LiquidCrystal_I2C lcd(LCD_IIC_ADDRESS,
                      LCD_IIC_COLS,
                      LCD_IIC_ROWS);

// encoder
ClickEncoder encoder(ENCODER_PIN_1,
                     ENCODER_PIN_2,
                     ENCODER_SW_PIN,
                     ENCODER_UPDATE_RATE);

// Buttons
Button buttons[MAX_BUTTON] {
    BUTTON_1_PIN,
    BUTTON_2_PIN,
    BUTTON_3_PIN,
    BUTTON_4_PIN,
};

// FAN
FanController fan(FAN_SW_PIN);

// temperature sensor
LM35 lm35(LM35_PIN, VREF_VOLTAGE);

// Setter (max 15000mA)
Setter<(int32_t)(MAX_CURRENT * 1000.0)> current_set_point;
// Cut off voltage set
Setter<99999l> voltage_set_point;

char buffer[200];
// 0 - 4 current 5 - 9 cut off voltage
int8_t setter_position = 4;
const int MAX_SET_POSITION = 10;

//////////////////////////////
// Operations
//////////////////////////////

enum OPTERATION_STATE
{
    STATE_IDLE = 1,
    STATE_RUNNING = 2,
    STATE_CALIBRATION = 10,

    STATE_UNDEF = 99,
};

// Global Data
struct {

    // status
    OPTERATION_STATE state;
    uint32_t state_time;

    double mah;
    double watt_h;
    uint32_t update_last;

    // page
    int page;

} g_cb { STATE_IDLE, 0, 0, 0, 0 };

double p_term = 0.0, i_term = 0.0, d_term = 0.0;

// timer service
void timer_one_isr()
{
    encoder.service();
}

void UpdateButtons()
{
    for (int i = MAX_BUTTON; i > 0; i--) {
        buttons[i - 1].update();
    }
}

void UpdateCurrentVoltage()
{
    // update current data, no need for idle
    if (g_cb.state != STATE_IDLE) {
        adc.updateCurrent();
    } else {
        adc.resetCurrent();
    }
    // update voltage
    adc.updateVoltage();
}

void UpdateTemperature()
{
    lm35.update();
}

void UpdateSensors()
{
    // update inputs
    UpdateButtons();

    // sensors
    UpdateCurrentVoltage();
    UpdateTemperature();
}

/// Display a double with Fixed length
void DisplayFixedDouble(double value, int width, int prec)
{
    char line[20];
    dtostrf(value, width, prec, line);
    int len = strlen(line);
    if (len > width) {
        // if we have longger value, truncate it
        line[width] = '\0';
    } else {
        // if the first one is space then we have leading spaces
        if (line[0] == ' ') {
            for (char* p = strchr(line, ' '); p; p = strchr(line, ' ')) {
                *p = '0';
            }
        }
    }
    lcd.print(line);
}

void UpdateDisplay()
{
    lcd.noCursor();

    // Display
    // Line 1 - Current Set Point, temperature:
    //   aa.aaaA ttt.ttC X
    lcd.setCursor(0, 0);
    DisplayFixedDouble(current_set_point.as_double(), 6, 3);
    lcd.print("A ");
    DisplayFixedDouble(voltage_set_point.as_double(), 6, 3);
    lcd.print("V");

    // FIXME: print out status
    switch (g_cb.state) {
        case STATE_IDLE:
            lcd.print(" ");
            break;
        case STATE_RUNNING:
            lcd.print("*");
            break;
        default:
            lcd.print("?");
    }

    // Line 2 - Current Sensing, Voltage Sensing:
    //   ss.ssssA vvv.vvvV
    lcd.setCursor(0, 1);

    if (g_cb.page == 0) {
        DisplayFixedDouble(adc.readCurrent(), 6, 3);
        lcd.print("A ");
        DisplayFixedDouble(adc.readVoltage(), 6, 3);
        lcd.print("V ");
    } else if (g_cb.page == 1) {
        double wattage = adc.readVoltage() * adc.readCurrent();
        DisplayFixedDouble(wattage, 8, 4);
        lcd.print("W ");
        DisplayFixedDouble(lm35.getTemperature(), 5, 2);
        lcd.print("C ");
    } else if (g_cb.page == 2) {
        DisplayFixedDouble(g_cb.mah, 8, 2);
        lcd.print("mAh      ");
    } else if (g_cb.page == 3) {
        DisplayFixedDouble(g_cb.watt_h, 8, 2);
        lcd.print("Wh      ");
    }

    // positiont the cursor for showing
    // current 01.345A 89.123V
    uint8_t bit = setter_position;
    if (setter_position >= 2) {
        bit++;
    }
    if (setter_position > 4) {
        bit += 2;
    }
    if (setter_position >= 7) {
        bit++;
    }
    lcd.setCursor(bit, 0);
    lcd.cursor();

}

static uint32_t last;
static double last_input;
static double e_sum;
static double pid_sum;
static double e;

void StopDischarge()
{
    g_cb.state = STATE_IDLE;
    ad5541.setValue(0);
}

void StartDischarge()
{
    uint32_t now = millis();
    g_cb.state = STATE_RUNNING;
    g_cb.state_time = now;
    ad5541.setValue(0);
    e_sum = 0.0;
    last_input = 0.0;
    g_cb.mah = 0;
    g_cb.update_last = now;
}

void ProcessControl()
{
    uint32_t now = millis();

    // abort contitions
    if (adc.readCurrent() > (MAX_CURRENT * 1.1) ||
        adc.readVoltage() < voltage_set_point.as_double() ||
        lm35.getTemperature() > MAX_TEMPERATURE)
    {
        StopDischarge();
    }

    // temperature control
    if (lm35.getTemperature() > 40.0 && !fan.isOn()) {
        fan.turn_on();
    } else if (lm35.getTemperature() < 35.0 && fan.isOn()) {
        fan.turn_off();
    }

    // configuration setter control
    if (buttons[1].isRaisingEdge()) {
        setter_position = (setter_position - 1) % MAX_SET_POSITION;
        if (setter_position < 0) {
            setter_position += MAX_SET_POSITION;
        }
    } else if (buttons[2].isRaisingEdge()) {
        setter_position = (setter_position + 1) % MAX_SET_POSITION;
    }
    // find which to set
    if (setter_position < 5) {
        current_set_point.set_position(setter_position);
        current_set_point.change(encoder.getValue());
    } else {
        voltage_set_point.set_position(setter_position - 5);
        voltage_set_point.change(encoder.getValue());
    }

    // display control
    if (buttons[3].isRaisingEdge()) {
        g_cb.page = (g_cb.page + 1) % MAX_PAGE;
    }
    if (buttons[0].isRaisingEdge()) {
        g_cb.page = (g_cb.page - 1) % MAX_PAGE;
        if (g_cb.page < 0) {
            g_cb.page += MAX_PAGE;
        }
    }

    // accumulate mah
    g_cb.mah += adc.readCurrent() * (now - g_cb.update_last) / 3600.0;
    g_cb.watt_h += adc.readCurrent() * adc.readVoltage() * (now - g_cb.update_last) / 3600000.0;
    g_cb.update_last = now;

    // FIXME: We should not run PID if not running
    pid_sum = 0.0;
    e = 0.0;
    p_term = 0.0;
    i_term = 0.0;
    d_term = 0.0;
    if (now - last >= 10) {
        double current_set_p = current_set_point.as_double();
        // We must limit the max wattage to IRFP250 MAX
        if (current_set_p * adc.readVoltage() > MAX_WATTAGE) {
            current_set_p = MAX_WATTAGE / adc.readVoltage();
        }
        // calc PIDd
        e = current_set_p - adc.readCurrent();
        if (e > -0.001 && e < 0.001) {
            e = 0.0; // dead band
        }
        p_term = e * 2289.0; // _kP
        e_sum += 0.00036 * e * (now - last);
        // e_sum = constrain(e_sum, -15, 15);
        i_term = e_sum;
        d_term = (adc.readCurrent() - last_input) / (now - last) * 366.0;
        pid_sum = p_term + i_term - d_term;
        // double pid_sum = p_term;
        // pid_sum *= 3.5;
        last = now;
        last_input = adc.readCurrent();
    }

    int32_t set_point = (int32_t)ad5541.getValue();
    set_point += (int32_t)pid_sum;
    set_point = constrain(set_point, AD5541_CODE_LOW, AD5541_CODE_HIGH);

    // State change event
    ClickEncoder::Button encoder_btn = encoder.getButton();
    if (g_cb.state == STATE_IDLE &&
        encoder_btn == ClickEncoder::Held &&
        g_cb.state_time + 3000.0 < now)
    {
        // IDLE -> RUNNING
        StartDischarge();
    }
    else if (g_cb.state == STATE_RUNNING)
    {
        if (encoder_btn == ClickEncoder::Clicked)
        {
            StopDischarge();
        }
        else
        {
            ad5541.setValue((uint16_t)set_point);
        }
    }
}

void setup()
{
    // initialize state to idle
    g_cb.state = STATE_IDLE;

    // LCD
    lcd.init();
    lcd.home();
    lcd.print("@DC Active Load@");
    lcd.setCursor(0, 1);
    lcd.print("       20171002");
    lcd.home();

    //
    delay(400);

    lcd.clear();
    lcd.print(1);

    // SPI
    SPI.begin();
    lcd.print(2);

    // DAC
    ad5541.begin();
    ad5541.setValue(0);
    lcd.print(3);

    // Timer
    Timer1.initialize(1000);
    Timer1.attachInterrupt(timer_one_isr);
    lcd.print(4);

    // temperature
    lm35.init();
    lcd.print(5);

    // ADC
    adc.begin();
    while (!adc.detectDevice()) {
        lcd.clear();
        lcd.print("ADC ERROR");
        delay(300);
    }
    lcd.print("z");
    delay(10);
    adc.init();
    delay(10);
    lcd.print("a");
    // FIXME: Calibration data should be gotten from EEPROM
    adc.setCalibData(AD7190_CONF_GAIN_1, 1.00080, 4.0);
    lcd.print("b");
    adc.setCalibData(AD7190_CONF_GAIN_8, 1.00243, -0.60);
    lcd.print(6);

    // Buttons
    buttons[0].init();
    buttons[1].init();
    buttons[2].init();
    buttons[3].init();
    lcd.print(7);

    // FAN
    fan.init();
    lcd.print(8);

    // get lcd ready for using information
    delay(400);
    lcd.clear();
}

void loop()
{
    // Read Information
    UpdateSensors();
    // TODO: Controller logic
    ProcessControl();
    // Output:
    UpdateDisplay();
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007-2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include <iostream>

#include "db/test/Test.h"
#include "db/test/Tester.h"
#include "db/test/TestRunner.h"
#include "db/util/Base64Codec.h"
#include "db/util/Crc16.h"
#include "db/util/StringTools.h"
#include "db/util/Convert.h"
#include "db/util/regex/Pattern.h"
#include "db/util/Date.h"
#include "db/util/StringTokenizer.h"
#include "db/util/UniqueList.h"

using namespace std;
using namespace db::test;
using namespace db::rt;
using namespace db::util;
using namespace db::util::regex;

void runBase64Test(TestRunner& tr)
{
   const char* expected = "YmNkZQ==";

   tr.test("Base64");

   char data[] = {'a', 'b', 'c', 'd', 'e'};
   string encoded = Base64Codec::encode(data + 1, 4);
   assert(encoded == expected);

   char* decoded;
   unsigned int length;
   Base64Codec::decode(encoded.c_str(), &decoded, length);
   assert(decoded != NULL);

   assert(length == 4);
   for(unsigned int i = 0; i < length; i++)
   {
      assert(decoded[i] == data[i + 1]);
   }

   string encoded2 = Base64Codec::encode(decoded, 4);
   assertStrCmp(encoded2.c_str(), expected);
   free(decoded);

   unsigned int size = 144;
   string large;
   large.append(size, 0x01);
   encoded = Base64Codec::encode(large.c_str(), size);
   Base64Codec::decode(encoded.c_str(), &decoded, length);
   assert(memcmp(decoded, large.c_str(), size) == 0);
   assert(length == size);
   free(decoded);

   size = 145;
   large.erase();
   large.append(size, 0x01);
   encoded = Base64Codec::encode(large.c_str(), size);
   Base64Codec::decode(encoded.c_str(), &decoded, length);
   assert(memcmp(decoded, large.c_str(), size) == 0);
   assert(length == size);
   free(decoded);

   tr.pass();
}

void runCrcTest(TestRunner& tr)
{
   tr.group("CRC");

   unsigned int correctValue = 6013;

   tr.test("single value update");
   Crc16 crc16s;
   crc16s.update(10);
   crc16s.update(20);
   crc16s.update(30);
   crc16s.update(40);
   crc16s.update(50);
   crc16s.update(60);
   crc16s.update(70);
   crc16s.update(80);
   assert(crc16s.getChecksum() == correctValue);
   tr.pass();

   tr.test("array update");
   Crc16 crc16a;
   char b[] = {10, 20, 30, 40, 50, 60, 70, 80};
   crc16a.update(b, 8);
   //cout << "CRC-16=" << crc16.getChecksum() << endl;
   assert(crc16a.getChecksum() == correctValue);
   tr.pass();

   tr.ungroup();
}

void runConvertTest(TestRunner& tr)
{
   tr.test("Convert");

   // convert to hex
   char data[] = "abcdefghiABCDEFGZXYW0123987{;}*%6,./.12`~";
   string original(data, strlen(data));

   //cout << "test data=" << original << endl;

   string lowerHex = Convert::bytesToHex(data, strlen(data));
   string upperHex = Convert::bytesToUpperHex(data, strlen(data));

   assertStrCmp(lowerHex.c_str(),"616263646566676869414243444546475a585957303132333938377b3b7d2a25362c2e2f2e3132607e");
   assert(lowerHex.length() == 82);
   assertStrCmp(upperHex.c_str(),"616263646566676869414243444546475A585957303132333938377B3B7D2A25362C2E2F2E3132607E");
   assert(upperHex.length() == 82);

   char decoded1[lowerHex.length() / 2];
   char decoded2[upperHex.length() / 2];

   unsigned int length1;
   unsigned int length2;
   Convert::hexToBytes(lowerHex.c_str(), lowerHex.length(), decoded1, length1);
   Convert::hexToBytes(upperHex.c_str(), upperHex.length(), decoded2, length2);

   string ascii1(decoded1, length1);
   string ascii2(decoded2, length2);

   assertStrCmp(ascii1.c_str(), data);
   assert(length1 == strlen(data));
   assertStrCmp(ascii2.c_str(), data);
   assert(length2 == strlen(data));

   assert(ascii1 == ascii2);
   assert(ascii1 == original);

   assertStrCmp(Convert::intToHex(10).c_str(), "0a");
   assertStrCmp(Convert::intToHex(33).c_str(), "21");
   assertStrCmp(Convert::intToHex(100).c_str(), "64");
   assertStrCmp(Convert::intToUpperHex(10).c_str(), "0A");
   assertStrCmp(Convert::intToUpperHex(33).c_str(), "21");
   assertStrCmp(Convert::intToUpperHex(100).c_str(), "64");
   assertStrCmp(Convert::intToHex(8975).c_str(), "230f");
   assertStrCmp(Convert::intToUpperHex(8975).c_str(), "230F");
   assertStrCmp(Convert::intToHex(65537).c_str(), "010001");
   assertStrCmp(Convert::intToUpperHex(65537).c_str(), "010001");

   {
      unsigned int ui;
      string hex;

      hex = "230f";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 8975);

      hex = "230F";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 8975);

      hex = "230FABCD";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 588229581);

      hex = "0";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 0x0);

      hex = "d";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 0xd);

      hex = "fab";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 0xfab);

      // bad hex
      hex = "x";
      assert(!Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assertException();
      Exception::clearLast();

      // too big
      hex = "876543210";
      assert(!Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assertException();
      Exception::clearLast();
   }

   {
      unsigned int length;
      string hex;
      char bytes[100];

      hex = "0";
      assert(Convert::hexToBytes(hex.c_str(), hex.length(), bytes, length));
      assert(length == 1);
      assert(bytes[0] == 0x0);

      hex = "d";
      assert(Convert::hexToBytes(hex.c_str(), hex.length(), bytes, length));
      assert(length == 1);
      assert(bytes[0] == 0xd);

      hex = "230f";
      assert(Convert::hexToBytes(hex.c_str(), hex.length(), bytes, length));
      assert(length == 2);
      assert(bytes[0] == 0x23);
      assert(bytes[1] == 0x0f);
   }

   tr.passIfNoException();
}

void runRegexTest(TestRunner& tr)
{
   tr.group("Regex");

   {
      tr.test("match");
      assert(Pattern::match("^[a-z]{3}$", "abc"));
      assert(Pattern::match("^[a-zA-Z0-9_]+$", "username"));
      tr.passIfNoException();
   }

   {
      tr.test("no match");
      assert(!Pattern::match("^[a-z]{3}$", "abcd"));
      assert(!Pattern::match("^[a-z]{3}$", "ABC"));
      assert(!Pattern::match("^[a-zA-Z0-9_]+$", "user name"));
      tr.passIfNoException();
   }

   {
      tr.test("sub-match");

      string submatches = "Look for green globs of green matter in green goo.";
      Pattern* p = Pattern::compile("green");

      unsigned int start, end;
      unsigned int index = 0;

      assert(p->match(submatches.c_str(), index, start, end));
      assert(start == 9);
      assert(end == 14);
      assertStrCmp(submatches.substr(start, end - start).c_str(), "green");
      index = end;

      assert(p->match(submatches.c_str(), index, start, end));
      assert(start == 24);
      assert(end == 29);
      assertStrCmp(submatches.substr(start, end - start).c_str(), "green");
      index = end;

      assert(p->match(submatches.c_str(), index, start, end));
      assert(start == 40);
      assert(end == 45);
      assertStrCmp(submatches.substr(start, end - start).c_str(), "green");
      index = end;

      assert(!p->match(submatches.c_str(), index, start, end));

      delete p;
      tr.passIfNoException();
   }

   {
      tr.test("replace all");

      string str = "Look for green globs of green matter in green goo.";
      string exp = "Look for blue globs of blue matter in blue goo.";
      StringTools::regexReplaceAll(str, "green", "blue");
      assertStrCmp(str.c_str(), exp.c_str());

      tr.passIfNoException();
   }

   tr.ungroup();
}

void runDateTest(TestRunner& tr)
{
   cout << "Starting Date test." << endl << endl;

   TimeZone gmt = TimeZone::getTimeZone("GMT");
   TimeZone local = TimeZone::getTimeZone();

   Date d;
   string str;
   //d.format(str);
   //d.format(str, "E EEEE d dd M MMMM MM yy w ww yyyy a", "java");
   //d.format(str, "EEEE, MMMM dd yyyy hh:mm:ss a", "java");
   //d.format(str, "EEE, MMMM dd yyyy hh:mm:ss a", "java", &local);
   //d.format(str, "EEE, d MMM yyyy HH:mm:ss", "java", &gmt);
   //d.format(str, "%a, %d %b %Y %H:%M:%S");
   d.format(str, "%a, %d %b %Y %H:%M:%S", "c", &gmt);
   //d.format(str, "%a, %d %b %Y %H:%M:%S", "c", &local);

   cout << "Current Date: " << str << endl;

   // parse date
   Date d2;
   d2.parse(str, "%a, %d %b %Y %H:%M:%S", "c", &gmt);
   //d2.parse(str, "%a, %d %b %Y %H:%M:%S", "c", &local);
   string str2;
   d2.format(str2, "%a, %d %b %Y %H:%M:%S", "c", &gmt);
   //d2.format(str2, "%a, %d %b %Y %H:%M:%S", "c", &local);

   cout << "Parsed Date 1: " << str2 << endl;

//   // FIXME: parser may have a problem with AM/PM
   // parse date again
   Date d3;
   str = "Thu, 02 Aug 2007 10:30:00";
   d3.parse(str, "%a, %d %b %Y %H:%M:%S", "c", &gmt);
   string str3;
   //d3.format(str3, "%a, %d %b %Y %H:%M:%S", "c", &gmt);
   d3.format(str3, "%a, %d %b %Y %H:%M:%S", "c", &local);

   cout << "Parsed Date 2: " << str3 << endl;

   cout << endl << "Date test complete." << endl;
}

void runStringTokenizerTest(TestRunner& tr)
{
   tr.test("StringTokenizer");

   const char* str = "This is a test of the StringTokenizer class.";

   /*
   StringTokenizer st0(str, ' ');
   while(st0.hasNextToken())
   {
      cout << "token='" << st0.nextToken() << "'" << endl;
   }
   */
   StringTokenizer st(str, ' ');
   #define NT(str) \
      do { \
         assert(st.hasNextToken()); \
         assertStrCmp(st.nextToken(), str); \
      } while(0)
   NT("This");
   NT("is");
   NT("a");
   NT("test");
   NT("of");
   NT("the");
   NT("StringTokenizer");
   NT("class.");
   assert(!st.hasNextToken());
   #undef NT

   tr.passIfNoException();
}

void runUniqueListTest(TestRunner& tr)
{
   tr.test("UniqueList");

   UniqueList<int> list;

   list.add(5);
   list.add(6);
   list.add(7);
   list.add(5);

   Iterator<int>* i = list.getIterator();
   /*
   while(i->hasNext())
   {
      cout << "element=" << i->next() << endl;
   }
   */
   assert(i->hasNext());
   assert(i->next() == 5);
   assert(i->hasNext());
   assert(i->next() == 6);
   assert(i->hasNext());
   assert(i->next() == 7);
   assert(!i->hasNext());
   delete i;

   list.remove(5);

   i = list.getIterator();
   /*
   while(i->hasNext())
   {
      cout << "element=" << i->next() << endl;
   }
   */
   assert(i->hasNext());
   assert(i->next() == 6);
   assert(i->hasNext());
   assert(i->next() == 7);
   assert(!i->hasNext());
   delete i;

   list.clear();

   i = list.getIterator();
   assert(!i->hasNext());
   delete i;

   tr.passIfNoException();
}

class DbUtilTester : public db::test::Tester
{
public:
   DbUtilTester()
   {
      setName("util");
   }

   /**
    * Run automatic unit tests.
    */
   virtual int runAutomaticTests(TestRunner& tr)
   {
      runBase64Test(tr);
      runCrcTest(tr);
      runConvertTest(tr);
      runStringTokenizerTest(tr);
      runUniqueListTest(tr);
      runRegexTest(tr);
      return 0;
   }

   /**
    * Runs interactive unit tests.
    */
   virtual int runInteractiveTests(TestRunner& tr)
   {
//      runDateTest(tr);
      return 0;
   }
};

#ifndef DB_TEST_NO_MAIN
DB_TEST_MAIN(DbUtilTester)
#endif
<commit_msg>Add hexToInt test for hex starting with 0.<commit_after>/*
 * Copyright (c) 2007-2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include <iostream>

#include "db/test/Test.h"
#include "db/test/Tester.h"
#include "db/test/TestRunner.h"
#include "db/util/Base64Codec.h"
#include "db/util/Crc16.h"
#include "db/util/StringTools.h"
#include "db/util/Convert.h"
#include "db/util/regex/Pattern.h"
#include "db/util/Date.h"
#include "db/util/StringTokenizer.h"
#include "db/util/UniqueList.h"

using namespace std;
using namespace db::test;
using namespace db::rt;
using namespace db::util;
using namespace db::util::regex;

void runBase64Test(TestRunner& tr)
{
   const char* expected = "YmNkZQ==";

   tr.test("Base64");

   char data[] = {'a', 'b', 'c', 'd', 'e'};
   string encoded = Base64Codec::encode(data + 1, 4);
   assert(encoded == expected);

   char* decoded;
   unsigned int length;
   Base64Codec::decode(encoded.c_str(), &decoded, length);
   assert(decoded != NULL);

   assert(length == 4);
   for(unsigned int i = 0; i < length; i++)
   {
      assert(decoded[i] == data[i + 1]);
   }

   string encoded2 = Base64Codec::encode(decoded, 4);
   assertStrCmp(encoded2.c_str(), expected);
   free(decoded);

   unsigned int size = 144;
   string large;
   large.append(size, 0x01);
   encoded = Base64Codec::encode(large.c_str(), size);
   Base64Codec::decode(encoded.c_str(), &decoded, length);
   assert(memcmp(decoded, large.c_str(), size) == 0);
   assert(length == size);
   free(decoded);

   size = 145;
   large.erase();
   large.append(size, 0x01);
   encoded = Base64Codec::encode(large.c_str(), size);
   Base64Codec::decode(encoded.c_str(), &decoded, length);
   assert(memcmp(decoded, large.c_str(), size) == 0);
   assert(length == size);
   free(decoded);

   tr.pass();
}

void runCrcTest(TestRunner& tr)
{
   tr.group("CRC");

   unsigned int correctValue = 6013;

   tr.test("single value update");
   Crc16 crc16s;
   crc16s.update(10);
   crc16s.update(20);
   crc16s.update(30);
   crc16s.update(40);
   crc16s.update(50);
   crc16s.update(60);
   crc16s.update(70);
   crc16s.update(80);
   assert(crc16s.getChecksum() == correctValue);
   tr.pass();

   tr.test("array update");
   Crc16 crc16a;
   char b[] = {10, 20, 30, 40, 50, 60, 70, 80};
   crc16a.update(b, 8);
   //cout << "CRC-16=" << crc16.getChecksum() << endl;
   assert(crc16a.getChecksum() == correctValue);
   tr.pass();

   tr.ungroup();
}

void runConvertTest(TestRunner& tr)
{
   tr.test("Convert");

   // convert to hex
   char data[] = "abcdefghiABCDEFGZXYW0123987{;}*%6,./.12`~";
   string original(data, strlen(data));

   //cout << "test data=" << original << endl;

   string lowerHex = Convert::bytesToHex(data, strlen(data));
   string upperHex = Convert::bytesToUpperHex(data, strlen(data));

   assertStrCmp(lowerHex.c_str(),"616263646566676869414243444546475a585957303132333938377b3b7d2a25362c2e2f2e3132607e");
   assert(lowerHex.length() == 82);
   assertStrCmp(upperHex.c_str(),"616263646566676869414243444546475A585957303132333938377B3B7D2A25362C2E2F2E3132607E");
   assert(upperHex.length() == 82);

   char decoded1[lowerHex.length() / 2];
   char decoded2[upperHex.length() / 2];

   unsigned int length1;
   unsigned int length2;
   Convert::hexToBytes(lowerHex.c_str(), lowerHex.length(), decoded1, length1);
   Convert::hexToBytes(upperHex.c_str(), upperHex.length(), decoded2, length2);

   string ascii1(decoded1, length1);
   string ascii2(decoded2, length2);

   assertStrCmp(ascii1.c_str(), data);
   assert(length1 == strlen(data));
   assertStrCmp(ascii2.c_str(), data);
   assert(length2 == strlen(data));

   assert(ascii1 == ascii2);
   assert(ascii1 == original);

   assertStrCmp(Convert::intToHex(10).c_str(), "0a");
   assertStrCmp(Convert::intToHex(33).c_str(), "21");
   assertStrCmp(Convert::intToHex(100).c_str(), "64");
   assertStrCmp(Convert::intToUpperHex(10).c_str(), "0A");
   assertStrCmp(Convert::intToUpperHex(33).c_str(), "21");
   assertStrCmp(Convert::intToUpperHex(100).c_str(), "64");
   assertStrCmp(Convert::intToHex(8975).c_str(), "230f");
   assertStrCmp(Convert::intToUpperHex(8975).c_str(), "230F");
   assertStrCmp(Convert::intToHex(65537).c_str(), "010001");
   assertStrCmp(Convert::intToUpperHex(65537).c_str(), "010001");

   {
      unsigned int ui;
      string hex;

      hex = "230f";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 8975);

      hex = "230F";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 8975);

      hex = "230FABCD";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 588229581);

      hex = "0";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 0x0);

      hex = "d";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 0xd);

      hex = "fab";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 0xfab);

      hex = "0141";
      assert(Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assert(ui == 0x141);

      // bad hex
      hex = "x";
      assert(!Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assertException();
      Exception::clearLast();

      // too big
      hex = "876543210";
      assert(!Convert::hexToInt(hex.c_str(), hex.length(), ui));
      assertException();
      Exception::clearLast();
   }

   {
      unsigned int length;
      string hex;
      char bytes[100];

      hex = "0";
      assert(Convert::hexToBytes(hex.c_str(), hex.length(), bytes, length));
      assert(length == 1);
      assert(bytes[0] == 0x0);

      hex = "d";
      assert(Convert::hexToBytes(hex.c_str(), hex.length(), bytes, length));
      assert(length == 1);
      assert(bytes[0] == 0xd);

      hex = "230f";
      assert(Convert::hexToBytes(hex.c_str(), hex.length(), bytes, length));
      assert(length == 2);
      assert(bytes[0] == 0x23);
      assert(bytes[1] == 0x0f);
   }

   tr.passIfNoException();
}

void runRegexTest(TestRunner& tr)
{
   tr.group("Regex");

   {
      tr.test("match");
      assert(Pattern::match("^[a-z]{3}$", "abc"));
      assert(Pattern::match("^[a-zA-Z0-9_]+$", "username"));
      tr.passIfNoException();
   }

   {
      tr.test("no match");
      assert(!Pattern::match("^[a-z]{3}$", "abcd"));
      assert(!Pattern::match("^[a-z]{3}$", "ABC"));
      assert(!Pattern::match("^[a-zA-Z0-9_]+$", "user name"));
      tr.passIfNoException();
   }

   {
      tr.test("sub-match");

      string submatches = "Look for green globs of green matter in green goo.";
      Pattern* p = Pattern::compile("green");

      unsigned int start, end;
      unsigned int index = 0;

      assert(p->match(submatches.c_str(), index, start, end));
      assert(start == 9);
      assert(end == 14);
      assertStrCmp(submatches.substr(start, end - start).c_str(), "green");
      index = end;

      assert(p->match(submatches.c_str(), index, start, end));
      assert(start == 24);
      assert(end == 29);
      assertStrCmp(submatches.substr(start, end - start).c_str(), "green");
      index = end;

      assert(p->match(submatches.c_str(), index, start, end));
      assert(start == 40);
      assert(end == 45);
      assertStrCmp(submatches.substr(start, end - start).c_str(), "green");
      index = end;

      assert(!p->match(submatches.c_str(), index, start, end));

      delete p;
      tr.passIfNoException();
   }

   {
      tr.test("replace all");

      string str = "Look for green globs of green matter in green goo.";
      string exp = "Look for blue globs of blue matter in blue goo.";
      StringTools::regexReplaceAll(str, "green", "blue");
      assertStrCmp(str.c_str(), exp.c_str());

      tr.passIfNoException();
   }

   tr.ungroup();
}

void runDateTest(TestRunner& tr)
{
   cout << "Starting Date test." << endl << endl;

   TimeZone gmt = TimeZone::getTimeZone("GMT");
   TimeZone local = TimeZone::getTimeZone();

   Date d;
   string str;
   //d.format(str);
   //d.format(str, "E EEEE d dd M MMMM MM yy w ww yyyy a", "java");
   //d.format(str, "EEEE, MMMM dd yyyy hh:mm:ss a", "java");
   //d.format(str, "EEE, MMMM dd yyyy hh:mm:ss a", "java", &local);
   //d.format(str, "EEE, d MMM yyyy HH:mm:ss", "java", &gmt);
   //d.format(str, "%a, %d %b %Y %H:%M:%S");
   d.format(str, "%a, %d %b %Y %H:%M:%S", "c", &gmt);
   //d.format(str, "%a, %d %b %Y %H:%M:%S", "c", &local);

   cout << "Current Date: " << str << endl;

   // parse date
   Date d2;
   d2.parse(str, "%a, %d %b %Y %H:%M:%S", "c", &gmt);
   //d2.parse(str, "%a, %d %b %Y %H:%M:%S", "c", &local);
   string str2;
   d2.format(str2, "%a, %d %b %Y %H:%M:%S", "c", &gmt);
   //d2.format(str2, "%a, %d %b %Y %H:%M:%S", "c", &local);

   cout << "Parsed Date 1: " << str2 << endl;

//   // FIXME: parser may have a problem with AM/PM
   // parse date again
   Date d3;
   str = "Thu, 02 Aug 2007 10:30:00";
   d3.parse(str, "%a, %d %b %Y %H:%M:%S", "c", &gmt);
   string str3;
   //d3.format(str3, "%a, %d %b %Y %H:%M:%S", "c", &gmt);
   d3.format(str3, "%a, %d %b %Y %H:%M:%S", "c", &local);

   cout << "Parsed Date 2: " << str3 << endl;

   cout << endl << "Date test complete." << endl;
}

void runStringTokenizerTest(TestRunner& tr)
{
   tr.test("StringTokenizer");

   const char* str = "This is a test of the StringTokenizer class.";

   /*
   StringTokenizer st0(str, ' ');
   while(st0.hasNextToken())
   {
      cout << "token='" << st0.nextToken() << "'" << endl;
   }
   */
   StringTokenizer st(str, ' ');
   #define NT(str) \
      do { \
         assert(st.hasNextToken()); \
         assertStrCmp(st.nextToken(), str); \
      } while(0)
   NT("This");
   NT("is");
   NT("a");
   NT("test");
   NT("of");
   NT("the");
   NT("StringTokenizer");
   NT("class.");
   assert(!st.hasNextToken());
   #undef NT

   tr.passIfNoException();
}

void runUniqueListTest(TestRunner& tr)
{
   tr.test("UniqueList");

   UniqueList<int> list;

   list.add(5);
   list.add(6);
   list.add(7);
   list.add(5);

   Iterator<int>* i = list.getIterator();
   /*
   while(i->hasNext())
   {
      cout << "element=" << i->next() << endl;
   }
   */
   assert(i->hasNext());
   assert(i->next() == 5);
   assert(i->hasNext());
   assert(i->next() == 6);
   assert(i->hasNext());
   assert(i->next() == 7);
   assert(!i->hasNext());
   delete i;

   list.remove(5);

   i = list.getIterator();
   /*
   while(i->hasNext())
   {
      cout << "element=" << i->next() << endl;
   }
   */
   assert(i->hasNext());
   assert(i->next() == 6);
   assert(i->hasNext());
   assert(i->next() == 7);
   assert(!i->hasNext());
   delete i;

   list.clear();

   i = list.getIterator();
   assert(!i->hasNext());
   delete i;

   tr.passIfNoException();
}

class DbUtilTester : public db::test::Tester
{
public:
   DbUtilTester()
   {
      setName("util");
   }

   /**
    * Run automatic unit tests.
    */
   virtual int runAutomaticTests(TestRunner& tr)
   {
      runBase64Test(tr);
      runCrcTest(tr);
      runConvertTest(tr);
      runStringTokenizerTest(tr);
      runUniqueListTest(tr);
      runRegexTest(tr);
      return 0;
   }

   /**
    * Runs interactive unit tests.
    */
   virtual int runInteractiveTests(TestRunner& tr)
   {
//      runDateTest(tr);
      return 0;
   }
};

#ifndef DB_TEST_NO_MAIN
DB_TEST_MAIN(DbUtilTester)
#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Dump.hxx"
#include "Widget.hxx"
#include "istream/istream_notify.hxx"

#include <daemon/log.h>

static void dump_widget_tree(unsigned indent, const Widget *widget)
{
    daemon_log(4, "%*swidget id='%s' class='%s'\n", indent, "",
               widget->id, widget->class_name);

    for (auto &child : widget->children)
        dump_widget_tree(indent + 2, &child);
}

static void
widget_dump_callback(void *ctx)
{
    const auto *widget = (const Widget *)ctx;

    dump_widget_tree(0, widget);
}

static constexpr struct istream_notify_handler widget_dump_handler = {
    .eof = widget_dump_callback,
    .abort = widget_dump_callback,
    .close = widget_dump_callback,
};

Istream *
widget_dump_tree_after_istream(struct pool &pool, Istream &istream,
                               Widget &widget)
{
    return istream_notify_new(pool, istream,
                              widget_dump_handler, &widget);
}
<commit_msg>widget/Dump: use the fprintf(stderr) instead of libdaemon<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Dump.hxx"
#include "Widget.hxx"
#include "istream/istream_notify.hxx"

#include <stdio.h>

static void dump_widget_tree(unsigned indent, const Widget *widget)
{
    fprintf(stderr, "%*swidget id='%s' class='%s'\n", indent, "",
            widget->id, widget->class_name);

    for (auto &child : widget->children)
        dump_widget_tree(indent + 2, &child);
}

static void
widget_dump_callback(void *ctx)
{
    const auto *widget = (const Widget *)ctx;

    dump_widget_tree(0, widget);
}

static constexpr struct istream_notify_handler widget_dump_handler = {
    .eof = widget_dump_callback,
    .abort = widget_dump_callback,
    .close = widget_dump_callback,
};

Istream *
widget_dump_tree_after_istream(struct pool &pool, Istream &istream,
                               Widget &widget)
{
    return istream_notify_new(pool, istream,
                              widget_dump_handler, &widget);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) Andrey Pikas
 */

#include <pruv/worker_loop.hpp>

#include <algorithm>
#include <cassert>
#include <cinttypes>
#include <cstring>

#include <signal.h>
#include <unistd.h>

#include <pruv/log.hpp>
#include <pruv/shmem_buffer.hpp>
#include <pruv/shmem_cache.hpp>
#include <pruv/termination.hpp>

namespace pruv {

int process_input(const char *s, request_handler handler)
{
    static thread_local char buf_in_name[256];
    static thread_local size_t buf_in_pos;
    static thread_local size_t buf_in_len;
    static thread_local char buf_out_name[256];
    static thread_local size_t buf_out_file_size;

    int parsed = sscanf(s, "HTTP IN SHM %255s %" SCNuPTR ", %" SCNuPTR
            " OUT SHM %255s %" SCNuPTR, buf_in_name,
            &buf_in_pos, &buf_in_len, buf_out_name, &buf_out_file_size);
    if (parsed != 5) {
        log(LOG_ERR, "Error parsing \"%s\"", s);
        return EXIT_FAILURE;
    }

    static shmem_cache buf_in_cache;
    static shmem_cache buf_out_cache;
    static const size_t PAGESIZE_MASK = sysconf(_SC_PAGE_SIZE) - 1;

    shmem_buffer *buf_in = buf_in_cache.get(buf_in_name);
    if (!buf_in)
        return EXIT_FAILURE;
    size_t buf_in_base_pos = buf_in_pos & ~PAGESIZE_MASK;
    size_t in_len = buf_in_pos + buf_in_len - buf_in_base_pos;
    size_t buf_in_end_pos = buf_in->map_offset() +
        (buf_in->map_end() - buf_in->map_begin());
    if (!(buf_in->map_offset() <= buf_in_base_pos &&
          buf_in_base_pos + in_len <= buf_in_end_pos)) {
        if (!buf_in->map(buf_in_base_pos, in_len))
            return EXIT_FAILURE;
    }
    buf_in->move_ptr((ptrdiff_t)buf_in_pos - (ptrdiff_t)buf_in->cur_pos());

    shmem_buffer *buf_out = buf_out_cache.get(buf_out_name);
    if (!buf_out)
        return EXIT_FAILURE;
    buf_out->update_file_size(buf_out_file_size);

    int r = EXIT_FAILURE;
    try {
        r = handler(buf_in->map_ptr(), buf_in_len, buf_out);
    }
    catch (...) {}

    bool ok = true;
    if (buf_in_pos + buf_in_len > REQUEST_CHUNK)
        ok &= buf_in->unmap();
    if (buf_out->map_end() - buf_out->map_begin() > (ptrdiff_t)RESPONSE_CHUNK)
        ok &= buf_out->unmap();
    if (!ok)
        return EXIT_FAILURE;

    printf("RESP %" PRIuPTR " of %" PRIuPTR " END\n",
            buf_out->data_size(), buf_out->file_size());
    fflush(stdout);
    return r;
}

namespace {

void termhdlr(int sig)
{
    set_interruption(sig == SIGINT ? IRQ_INT : IRQ_TERM);
}

} // namespace

int worker_loop(request_handler handler)
{
    static thread_local char ln[256];

    struct sigaction sigact;
    memset(&sigact, 0, sizeof(sigact));
    sigact.sa_handler = termhdlr;
    sigemptyset(&sigact.sa_mask);
    int r = sigaction(SIGTERM, &sigact, nullptr);
    if (r == -1)
        log_syserr(LOG_ERR, "main sigaction(SIGTERM)");
    r = sigaction(SIGINT, &sigact, nullptr);
    if (r == -1)
        log_syserr(LOG_ERR, "main sigaction(SIGINT)");
    r = sigaction(SIGHUP, &sigact, nullptr);
    if (r == -1)
        log_syserr(LOG_ERR, "main sigaction(SIGHUP)");

    for (;;) {
        char *dst = ln;
        while (interruption_requested() != IRQ_TERM) {
            ssize_t r = read(STDIN_FILENO, dst, std::end(ln) - dst);
            if (r == -1) {
                if (errno == EINTR)
                    continue;
                else {
                    log_syserr(LOG_ERR, "main read(STDIN_FILENO)");
                    return EXIT_FAILURE;
                }
            }
            dst += r;
            char *eol = std::find(dst - r, dst, '\n');
            if (eol != dst) {
                *eol = 0;
                break;
            }
            if (dst >= std::end(ln)) {
                log(LOG_ERR, "Too large input line");
                return EXIT_FAILURE;
            }
        }
        if (interruption_requested() == IRQ_TERM)
            break;

        r = process_input(ln, handler);
        if (r != EXIT_SUCCESS)
            return r;
        if (interruption_requested() == IRQ_INT) {
            log(LOG_DEBUG, "Interrupted.");
            set_interruption(IRQ_NONE);
        }
    }
    log(LOG_NOTICE, "Terminated.");
    return EXIT_SUCCESS;
}

} // namespace pruv
<commit_msg>Handle parent's exit in worker process.<commit_after>/*
 * Copyright (C) Andrey Pikas
 */

#include <pruv/worker_loop.hpp>

#include <algorithm>
#include <cassert>
#include <cinttypes>
#include <cstring>

#include <signal.h>
#include <sys/prctl.h>
#include <unistd.h>

#include <pruv/log.hpp>
#include <pruv/shmem_buffer.hpp>
#include <pruv/shmem_cache.hpp>
#include <pruv/termination.hpp>

namespace pruv {

int process_input(const char *s, request_handler handler)
{
    static thread_local char buf_in_name[256];
    static thread_local size_t buf_in_pos;
    static thread_local size_t buf_in_len;
    static thread_local char buf_out_name[256];
    static thread_local size_t buf_out_file_size;

    int parsed = sscanf(s, "HTTP IN SHM %255s %" SCNuPTR ", %" SCNuPTR
            " OUT SHM %255s %" SCNuPTR, buf_in_name,
            &buf_in_pos, &buf_in_len, buf_out_name, &buf_out_file_size);
    if (parsed != 5) {
        log(LOG_ERR, "Error parsing \"%s\"", s);
        return EXIT_FAILURE;
    }

    static shmem_cache buf_in_cache;
    static shmem_cache buf_out_cache;
    static const size_t PAGESIZE_MASK = sysconf(_SC_PAGE_SIZE) - 1;

    shmem_buffer *buf_in = buf_in_cache.get(buf_in_name);
    if (!buf_in)
        return EXIT_FAILURE;
    size_t buf_in_base_pos = buf_in_pos & ~PAGESIZE_MASK;
    size_t in_len = buf_in_pos + buf_in_len - buf_in_base_pos;
    size_t buf_in_end_pos = buf_in->map_offset() +
        (buf_in->map_end() - buf_in->map_begin());
    if (!(buf_in->map_offset() <= buf_in_base_pos &&
          buf_in_base_pos + in_len <= buf_in_end_pos)) {
        if (!buf_in->map(buf_in_base_pos, in_len))
            return EXIT_FAILURE;
    }
    buf_in->move_ptr((ptrdiff_t)buf_in_pos - (ptrdiff_t)buf_in->cur_pos());

    shmem_buffer *buf_out = buf_out_cache.get(buf_out_name);
    if (!buf_out)
        return EXIT_FAILURE;
    buf_out->update_file_size(buf_out_file_size);

    int r = EXIT_FAILURE;
    try {
        r = handler(buf_in->map_ptr(), buf_in_len, buf_out);
    }
    catch (...) {}

    bool ok = true;
    if (buf_in_pos + buf_in_len > REQUEST_CHUNK)
        ok &= buf_in->unmap();
    if (buf_out->map_end() - buf_out->map_begin() > (ptrdiff_t)RESPONSE_CHUNK)
        ok &= buf_out->unmap();
    if (!ok)
        return EXIT_FAILURE;

    printf("RESP %" PRIuPTR " of %" PRIuPTR " END\n",
            buf_out->data_size(), buf_out->file_size());
    fflush(stdout);
    return r;
}

namespace {

void termhdlr(int sig)
{
    set_interruption(sig == SIGINT ? IRQ_INT : IRQ_TERM);
}

} // namespace

int worker_loop(request_handler handler)
{
    static thread_local char ln[256];

    struct sigaction sigact;
    memset(&sigact, 0, sizeof(sigact));
    sigact.sa_handler = termhdlr;
    sigemptyset(&sigact.sa_mask);
    int r = sigaction(SIGTERM, &sigact, nullptr);
    if (r == -1)
        log_syserr(LOG_ERR, "worker_loop sigaction(SIGTERM)");
    r = sigaction(SIGINT, &sigact, nullptr);
    if (r == -1)
        log_syserr(LOG_ERR, "worker_loop sigaction(SIGINT)");
    r = sigaction(SIGHUP, &sigact, nullptr);
    if (r == -1)
        log_syserr(LOG_ERR, "worker_loop sigaction(SIGHUP)");
    r = prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
    if (r == -1)
        log_syserr(LOG_ERR, "worker_loop prctl");
    if (getppid() == 1) {
        log(LOG_ERR, "Orphaned at start. Exit.");
        return EXIT_FAILURE;
    }

    for (;;) {
        char *dst = ln;
        while (interruption_requested() != IRQ_TERM) {
            ssize_t r = read(STDIN_FILENO, dst, std::end(ln) - dst);
            if (r == -1) {
                if (errno == EINTR)
                    continue;
                else {
                    log_syserr(LOG_ERR, "main read(STDIN_FILENO)");
                    return EXIT_FAILURE;
                }
            }
            dst += r;
            char *eol = std::find(dst - r, dst, '\n');
            if (eol != dst) {
                *eol = 0;
                break;
            }
            if (dst >= std::end(ln)) {
                log(LOG_ERR, "Too large input line");
                return EXIT_FAILURE;
            }
        }
        if (interruption_requested() == IRQ_TERM)
            break;

        r = process_input(ln, handler);
        if (r != EXIT_SUCCESS)
            return r;
        if (interruption_requested() == IRQ_INT) {
            log(LOG_DEBUG, "Interrupted.");
            set_interruption(IRQ_NONE);
        }
    }
    log(LOG_NOTICE, "Terminated.");
    return EXIT_SUCCESS;
}

} // namespace pruv
<|endoftext|>


<commit_before>#include "fast_float/fast_float.h"

#include <cassert>
#include <cmath>

#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__)
// Anything at all that is related to cygwin, msys and so forth will
// always use this fallback because we cannot rely on it behaving as normal
// gcc.
#include <locale>
#include <sstream>
// workaround for CYGWIN
double cygwin_strtod_l(const char* start, char** end) {
    double d;
    std::stringstream ss;
    ss.imbue(std::locale::classic());
    ss << start;
    ss >> d;
    size_t nread = ss.tellg();
    *end = const_cast<char*>(start) + nread;
    return d;
}
#endif

template <typename T> char *to_string(T d, char *buffer) {
  auto written = std::snprintf(buffer, 64, "%.*e",
                               std::numeric_limits<T>::max_digits10 - 1, d);
  return buffer + written;
}

void strtod_from_string(const char * st, float& d) {
    char *pr = (char *)st;
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__)
    d = cygwin_strtod_l(st, &pr);
#elif defined(_WIN32)
    static _locale_t c_locale = _create_locale(LC_ALL, "C");
    d = _strtof_l(st, &pr,  c_locale);
#else
    static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
    d = strtof_l(st, &pr,  c_locale);
#endif
    if (pr == st) {
      throw std::runtime_error("bug in strtod_from_string");
    }
}

void allvalues() {
  char buffer[64];
  for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) {
    float v;
    if ((w % 1048576) == 0) {
      std::cout << ".";
      std::cout.flush();
    }
    uint32_t word = w;
    memcpy(&v, &word, sizeof(v));
    if(std::isfinite(v)) {
      float nextf = std::nextafterf(v, INFINITY);
      if(!std::isfinite(nextf)) { continue; }
      double v1{v};
      assert(float(v1) == v);
      double v2{nextf};
      assert(float(v2) == nextf);
      double midv{v1 + (v2 - v1) / 2};
      float expected_midv(midv);

      const char *string_end = to_string(midv, buffer);
      float str_answer;
      strtod_from_string(buffer, str_answer);

      float result_value;
      auto result = fast_float::from_chars(buffer, string_end, result_value);
      if (result.ec != std::errc()) {
        std::cerr << "parsing error ? " << buffer << std::endl;
        abort();
      }
      if(copysign(1,result_value) != copysign(1,v)) {
        std::cerr << buffer << std::endl;
        std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << v
              << std::endl;
        abort();
      } else if (std::isnan(v)) {
        if (!std::isnan(result_value)) {
          std::cerr << "not nan" << buffer << std::endl;
          abort();
        }
      } else if (result_value != str_answer) {
        std::cerr << "no match ? " << buffer << std::endl;
        std::cout << "started with " << std::hexfloat << midv << std::endl;
        std::cout << "round down to " << std::hexfloat << str_answer << std::endl;
        std::cout << "got back " << std::hexfloat << result_value << std::endl;
        std::cout << std::dec;
        abort();
      }
    }
  }
  std::cout << std::endl;
}

int main() {
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__)
  std::cout << "Warning: msys/cygwin detected. This particular test is likely to generate false failures due to our reliance on the underlying runtime library." << std::endl;
#endif
  allvalues();
  std::cout << std::endl;
  std::cout << "all ok" << std::endl;
  return EXIT_SUCCESS;
}<commit_msg>More elaborate.<commit_after>#include "fast_float/fast_float.h"

#include <cassert>
#include <cmath>

#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__)
// Anything at all that is related to cygwin, msys and so forth will
// always use this fallback because we cannot rely on it behaving as normal
// gcc.
#include <locale>
#include <sstream>
// workaround for CYGWIN
double cygwin_strtod_l(const char* start, char** end) {
    double d;
    std::stringstream ss;
    ss.imbue(std::locale::classic());
    ss << start;
    ss >> d;
    size_t nread = ss.tellg();
    *end = const_cast<char*>(start) + nread;
    return d;
}
#endif

template <typename T> char *to_string(T d, char *buffer) {
  auto written = std::snprintf(buffer, 64, "%.*e",
                               std::numeric_limits<T>::max_digits10 - 1, d);
  return buffer + written;
}

void strtod_from_string(const char * st, float& d) {
    char *pr = (char *)st;
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__)
    d = cygwin_strtod_l(st, &pr);
#elif defined(_WIN32)
    static _locale_t c_locale = _create_locale(LC_ALL, "C");
    d = _strtof_l(st, &pr,  c_locale);
#else
    static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
    d = strtof_l(st, &pr,  c_locale);
#endif
    if (pr == st) {
      throw std::runtime_error("bug in strtod_from_string");
    }
}

void allvalues() {
  char buffer[64];
  for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) {
    float v;
    if ((w % 1048576) == 0) {
      std::cout << ".";
      std::cout.flush();
    }
    uint32_t word = w;
    memcpy(&v, &word, sizeof(v));
    if(std::isfinite(v)) {
      float nextf = std::nextafterf(v, INFINITY);
      if(copysign(1,v) != copysign(1,nextf)) { continue; }
      if(!std::isfinite(nextf)) { continue; }
      double v1{v};
      assert(float(v1) == v);
      double v2{nextf};
      assert(float(v2) == nextf);
      double midv{v1 + (v2 - v1) / 2};
      float expected_midv(midv);

      const char *string_end = to_string(midv, buffer);
      float str_answer;
      strtod_from_string(buffer, str_answer);

      float result_value;
      auto result = fast_float::from_chars(buffer, string_end, result_value);
      if (result.ec != std::errc()) {
        std::cerr << "parsing error ? " << buffer << std::endl;
        abort();
      }
      if(copysign(1,result_value) != copysign(1,v)) {
        std::cerr << buffer << std::endl;
        std::cerr << "v " << std::hexfloat << v << std::endl;
        std::cerr << "v2 " << std::hexfloat << v2 << std::endl;
        std::cerr << "midv " << std::hexfloat << midv << std::endl;
        std::cerr << "expected_midv " << std::hexfloat << expected_midv << std::endl;
        std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << v
              << std::endl;
        abort();
      } else if (std::isnan(v)) {
        if (!std::isnan(result_value)) {
          std::cerr << "not nan" << buffer << std::endl;
          std::cerr << "v " << std::hexfloat << v << std::endl;
          std::cerr << "v2 " << std::hexfloat << v2 << std::endl;
          std::cerr << "midv " << std::hexfloat << midv << std::endl;
          std::cerr << "expected_midv " << std::hexfloat << expected_midv << std::endl;
          abort();
        }
      } else if (result_value != str_answer) {
        std::cerr << "no match ? " << buffer << std::endl;
        std::cerr << "v " << std::hexfloat << v << std::endl;
        std::cerr << "v2 " << std::hexfloat << v2 << std::endl;
        std::cerr << "midv " << std::hexfloat << midv << std::endl;
        std::cerr << "expected_midv " << std::hexfloat << expected_midv << std::endl;
        std::cout << "started with " << std::hexfloat << midv << std::endl;
        std::cout << "round down to " << std::hexfloat << str_answer << std::endl;
        std::cout << "got back " << std::hexfloat << result_value << std::endl;
        std::cout << std::dec;
        abort();
      }
    }
  }
  std::cout << std::endl;
}

int main() {
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__)
  std::cout << "Warning: msys/cygwin detected. This particular test is likely to generate false failures due to our reliance on the underlying runtime library." << std::endl;
#endif
  allvalues();
  std::cout << std::endl;
  std::cout << "all ok" << std::endl;
  return EXIT_SUCCESS;
}<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright(C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation(directui@nokia.com)
**
** This file is part of systemui.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QX11Info>
#include <MApplication>
#include <MWindow>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include "ft_mwindow.h"

void Ft_MWindow::initTestCase()
{
    int argc = 1;
    char *argv[] = {(char *) "./ft_mwindow", NULL };
    app = new MApplication(argc, argv);
}

void Ft_MWindow::cleanupTestCase()
{
    delete app;
}

void Ft_MWindow::init()
{
    window = new MWindow;
}

void Ft_MWindow::cleanup()
{
    delete window;
}

void Ft_MWindow::testShowDoesNotResetSkipTaskbar()
{
    // Show the window
    qDebug() << "show()ing the window";
    window->show();

    // Wait for 1 second
    QTest::qWait(1000);

    // Tell the window to not to be shown in the task bar
    qDebug() << "Setting _NET_WM_STATE_SKIP_TASKBAR";
    Display *display = QX11Info::display();
    XEvent e;
    memset(&e, 0, sizeof(XEvent));
    e.xclient.type = ClientMessage;
    e.xclient.display = display;
    e.xclient.window = window->winId();
    e.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", False);
    e.xclient.format = 32;
    e.xclient.data.l[0] = 1;
    e.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False);
    XSendEvent(display, RootWindow(display, window->x11Info().screen()), False, (SubstructureNotifyMask | SubstructureRedirectMask), &e);
    XSync(display, False);

    // Wait for 1 second
    QTest::qWait(1000);

    // Verify that the window has the property
    testWindowHasSkipTaskbarProperty();

    // Show the window again
    qDebug() << "show()ing the window again";
    window->show();

    // Wait for 1 second
    QTest::qWait(1000);

    // Verify that the window has the property
    testWindowHasSkipTaskbarProperty();
}

void Ft_MWindow::testWindowHasSkipTaskbarProperty()
{
    QList<Atom> properties;
    Atom actualType;
    int actualFormat;
    unsigned long numTypeItems, bytesLeft;
    unsigned char *typeData = NULL;

    bool found = false;
    Display *display = QX11Info::display();
    Status result = XGetWindowProperty(display, window->winId(), XInternAtom(display, "_NET_WM_STATE", False), 0L, 16L, False, XA_ATOM, &actualType, &actualFormat, &numTypeItems, &bytesLeft, &typeData);
    if (result == Success) {
        Atom *type = (Atom *) typeData;
        for (unsigned int n = 0; n < numTypeItems; n++) {
            found |= (type[n] == XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False));
        }
        XFree(typeData);
    }

    qDebug() << "Checking whether _NET_WM_STATE_SKIP_TASKBAR is set:" << found;

    QVERIFY2(found, "_NET_WM_STATE_SKIP_TASKBAR not set");
}

QTEST_APPLESS_MAIN(Ft_MWindow)
<commit_msg>Fixes: Ft_MWindow functional test<commit_after>/****************************************************************************
**
** Copyright(C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation(directui@nokia.com)
**
** This file is part of systemui.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QX11Info>
#include <MApplication>
#include <MWindow>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include "ft_mwindow.h"

void Ft_MWindow::initTestCase()
{
    static int argc = 1;
    static char *argv[] = {(char *) "./ft_mwindow", NULL };
    app = new MApplication(argc, argv);
}

void Ft_MWindow::cleanupTestCase()
{
    delete app;
}

void Ft_MWindow::init()
{
    window = new MWindow;
}

void Ft_MWindow::cleanup()
{
    delete window;
}

void Ft_MWindow::testShowDoesNotResetSkipTaskbar()
{
    // Show the window
    qDebug() << "show()ing the window";
    window->show();

    // Wait for 1 second
    QTest::qWait(1000);

    // Tell the window to not to be shown in the task bar
    qDebug() << "Setting _NET_WM_STATE_SKIP_TASKBAR";
    Display *display = QX11Info::display();
    XEvent e;
    memset(&e, 0, sizeof(XEvent));
    e.xclient.type = ClientMessage;
    e.xclient.display = display;
    e.xclient.window = window->winId();
    e.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", False);
    e.xclient.format = 32;
    e.xclient.data.l[0] = 1;
    e.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False);
    XSendEvent(display, RootWindow(display, window->x11Info().screen()), False, (SubstructureNotifyMask | SubstructureRedirectMask), &e);
    XSync(display, False);

    // Wait for 1 second
    QTest::qWait(1000);

    // Verify that the window has the property
    testWindowHasSkipTaskbarProperty();

    // Show the window again
    qDebug() << "show()ing the window again";
    window->show();

    // Wait for 1 second
    QTest::qWait(1000);

    // Verify that the window has the property
    testWindowHasSkipTaskbarProperty();
}

void Ft_MWindow::testWindowHasSkipTaskbarProperty()
{
    QList<Atom> properties;
    Atom actualType;
    int actualFormat;
    unsigned long numTypeItems, bytesLeft;
    unsigned char *typeData = NULL;

    bool found = false;
    Display *display = QX11Info::display();
    Status result = XGetWindowProperty(display, window->winId(), XInternAtom(display, "_NET_WM_STATE", False), 0L, 16L, False, XA_ATOM, &actualType, &actualFormat, &numTypeItems, &bytesLeft, &typeData);
    if (result == Success) {
        Atom *type = (Atom *) typeData;
        for (unsigned int n = 0; n < numTypeItems; n++) {
            found |= (type[n] == XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False));
        }
        XFree(typeData);
    }

    qDebug() << "Checking whether _NET_WM_STATE_SKIP_TASKBAR is set:" << found;

    QVERIFY2(found, "_NET_WM_STATE_SKIP_TASKBAR not set");
}

QTEST_APPLESS_MAIN(Ft_MWindow)
<|endoftext|>


<commit_before>#include <atomic>
#include <thread>
#include <iostream>

#include <silicon/middlewares/sqlite_connection.hh>
#include <silicon/middlewares/hashmap_session.hh>
#include <silicon/api.hh>
#include <silicon/clients/libcurl_client.hh>
#include <silicon/backends/rabbitmq.hh>
#include <silicon/clients/rmq_client.hh>

#include "symbols.hh"

using namespace s;

using namespace sl;

struct session
{
  int id;
};

auto hl_api = http_api(

  // get
  GET / _test = [] () { return D(_message = "get"); },

  // get params
  GET / _test2 * get_parameters(_id = int(0)) = [] (auto p) { return D(_id = p.id); },

  // post params
  POST / _test2 * post_parameters(_id = int(0), _name = std::string()) = [] (auto p) { return D(_id = p.id, _name = p.name ); },

  // post object params
  POST / _test4 * post_parameters(_id = D(_name = std::string())) = [] (auto p) { return D(_name = p.id.name ); },

  // post array params
  POST / _test5 * post_parameters(_id = std::vector<int>()) = [] (auto p) { return D(_name = p.id ); },

  // url params
  GET / _test3 / _id[int(0)] = [] (auto p) { return D(_id = p.id); },

  // cookie
  GET / _set_id / _id[int(0)] = [] (auto p, session& s) {
    s.id = p.id;
    return D(_id = s.id);
  },

  GET / _get_id = [] (session& s) {
    return D(_id = s.id);
  }

);

std::atomic_int cpt0;
std::atomic_int cpt1;
std::atomic_int cpt2;
std::atomic_int cpt3;
std::atomic_int cpt4;
std::atomic_int cpt5;

auto rmq_api = sl::rmq::api(
  s::_test = [](sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt0, 1);
  },
  s::_test1 & sl::rmq::parameters(s::_str = std::string()) = [](auto,
                                                                sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt1, 1);
  },
  s::_test2 * s::_rk1 = [](sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt2, 1);
  },
  s::_test3 * s::_rk2 & sl::rmq::parameters(s::_str = std::string()) = [](auto,
                                                                          sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt3, 1);
  },
  s::_test4 * s::_rk1 / s::_qn1 = [](sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt4, 1);
  },
  s::_test5 * s::_rk2 / s::_qn2 & sl::rmq::parameters(s::_str = std::string()) = [](auto,
                                                                                sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt5, 1);
  }
);

template <typename T>
void backend_testsuite(T port)
{
  auto c1 = libcurl_json_client(hl_api, "127.0.0.1", port, _post_encoding = _x_www_form_urlencoded);
  auto c2 = libcurl_json_client(hl_api, "127.0.0.1", port);

  auto r1 = c1.http_get.test();
  assert(r1.status == 200);
  assert(r1.response.message == "get");

  auto r3 = c1.http_get.test2(_id = 12);
  assert(r3.status == 200);
  assert(r3.response.id == 12);

  auto r4 = c1.http_post.test2(_id = 12, _name = "s pa ces");
  assert(r4.status == 200);
  assert(r4.response.id == 12);
  assert(r4.response.name == "s pa ces");

  auto r41 = c2.http_post.test4(_id = D(_name = "John"));
  assert(r41.status == 200);
  assert(r41.response.name == "John");

  auto r5 = c1.http_get.test3(_id = 12);
  assert(r5.status == 200);
  assert(r5.response.id == 12);

  auto r6 = c1.http_get.set_id(_id = 42);
  auto r7 = c2.http_get.set_id(_id = 51);
  auto r8 = c1.http_get.get_id();
  auto r9 = c2.http_get.get_id();

  assert(r8.response.id == 42);
  assert(r9.response.id == 51);

}
<commit_msg>Fix compilation.<commit_after>#include <atomic>
#include <thread>
#include <iostream>

#include <silicon/middlewares/hashmap_session.hh>
#include <silicon/api.hh>
#include <silicon/clients/libcurl_client.hh>

#include "symbols.hh"

using namespace s;

using namespace sl;

struct session
{
  int id;
};

auto hl_api = http_api(

  // get
  GET / _test = [] () { return D(_message = "get"); },

  // get params
  GET / _test2 * get_parameters(_id = int(0)) = [] (auto p) { return D(_id = p.id); },

  // post params
  POST / _test2 * post_parameters(_id = int(0), _name = std::string()) = [] (auto p) { return D(_id = p.id, _name = p.name ); },

  // post object params
  POST / _test4 * post_parameters(_id = D(_name = std::string())) = [] (auto p) { return D(_name = p.id.name ); },

  // post array params
  POST / _test5 * post_parameters(_id = std::vector<int>()) = [] (auto p) { return D(_name = p.id ); },

  // url params
  GET / _test3 / _id[int(0)] = [] (auto p) { return D(_id = p.id); },

  // cookie
  GET / _set_id / _id[int(0)] = [] (auto p, session& s) {
    s.id = p.id;
    return D(_id = s.id);
  },

  GET / _get_id = [] (session& s) {
    return D(_id = s.id);
  }

);

std::atomic_int cpt0;
std::atomic_int cpt1;
std::atomic_int cpt2;
std::atomic_int cpt3;
std::atomic_int cpt4;
std::atomic_int cpt5;

auto rmq_api = sl::rmq::api(
  s::_test = [](sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt0, 1);
  },
  s::_test1 & sl::rmq::parameters(s::_str = std::string()) = [](auto,
                                                                sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt1, 1);
  },
  s::_test2 * s::_rk1 = [](sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt2, 1);
  },
  s::_test3 * s::_rk2 & sl::rmq::parameters(s::_str = std::string()) = [](auto,
                                                                          sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt3, 1);
  },
  s::_test4 * s::_rk1 / s::_qn1 = [](sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt4, 1);
  },
  s::_test5 * s::_rk2 / s::_qn2 & sl::rmq::parameters(s::_str = std::string()) = [](auto,
                                                                                sl::sqlite_connection &)
  {
    std::atomic_fetch_add(&cpt5, 1);
  }
);

template <typename T>
void backend_testsuite(T port)
{
  auto c1 = libcurl_json_client(hl_api, "127.0.0.1", port, _post_encoding = _x_www_form_urlencoded);
  auto c2 = libcurl_json_client(hl_api, "127.0.0.1", port);

  auto r1 = c1.http_get.test();
  assert(r1.status == 200);
  assert(r1.response.message == "get");

  auto r3 = c1.http_get.test2(_id = 12);
  assert(r3.status == 200);
  assert(r3.response.id == 12);

  auto r4 = c1.http_post.test2(_id = 12, _name = "s pa ces");
  assert(r4.status == 200);
  assert(r4.response.id == 12);
  assert(r4.response.name == "s pa ces");

  auto r41 = c2.http_post.test4(_id = D(_name = "John"));
  assert(r41.status == 200);
  assert(r41.response.name == "John");

  auto r5 = c1.http_get.test3(_id = 12);
  assert(r5.status == 200);
  assert(r5.response.id == 12);

  auto r6 = c1.http_get.set_id(_id = 42);
  auto r7 = c2.http_get.set_id(_id = 51);
  auto r8 = c1.http_get.get_id();
  auto r9 = c2.http_get.get_id();

  assert(r8.response.id == 42);
  assert(r9.response.id == 51);

}
<|endoftext|>


<commit_before>#include <common-ee.h>
#include <kernel.h>
#include <string.h>

#define INIT_PRIO 0x40
#define STACK_SIZE 0x8000

char nullThreadStack[STACK_SIZE] __attribute__ ((aligned(16)));
void nullThreadProc(u32) {
	//Do nothing
}

char sleepingThreadStack[STACK_SIZE] __attribute__ ((aligned(16)));
void sleepingThreadProc(u32) {
	SleepThread();
}

char waitingThreadStack[STACK_SIZE] __attribute__ ((aligned(16)));
void waitingThreadProc(u32) {
	ee_sema_t dummySemaInfo;
	dummySemaInfo.init_count = 0;
	dummySemaInfo.max_count = 1;
	dummySemaInfo.option = 0;
	u32 dummySema = CreateSema(&dummySemaInfo);
	WaitSema(dummySema);
}

int createTestThread(void *entry, int prio, void *stack, u32 stackSize) {
	ee_thread_t threadParam;
	memset(&threadParam, 0, sizeof(ee_thread_t));
	threadParam.func = entry;
	threadParam.initial_priority = prio;
	threadParam.stack = stack;
	threadParam.stack_size = stackSize;
	return CreateThread(&threadParam);
}

void printThreadStatus(int threadId) {
	ee_thread_status_t threadStat;
	memset(&threadStat, 0, sizeof(ee_thread_status_t));
	int result = ReferThreadStatus(threadId, &threadStat);
	if(result >= 0) {
		schedf("succeeded -> result: %02x, init prio: %02x current prio: %02x, status: %02x\n",
			result, threadStat.initial_priority, threadStat.current_priority, threadStat.status);
	} else {
		schedf("failed -> result: %d\n", result);
	}
}

int main(int argc, char **argv) {
	printf("-- TEST BEGIN\n");

	{
		schedf("self thread:\n");

		schedf("  stat (with tid 0): ");
		printThreadStatus(0);

		schedf("  stat (with current tid): ");
		printThreadStatus(GetThreadId());

		flushschedf();
	}

	{
		schedf("low prio thread:\n");

		int threadId = createTestThread((void*)&nullThreadProc, INIT_PRIO + 0x10, nullThreadStack, STACK_SIZE);
		schedf("  stat before start: ");
		printThreadStatus(threadId);

		StartThread(threadId, 0);
		schedf("  stat after start: ");
		printThreadStatus(threadId);

		SuspendThread(threadId);
		schedf("  stat after suspend: ");
		printThreadStatus(threadId);

		ResumeThread(threadId);
		schedf("  stat after resume: ");
		printThreadStatus(threadId);

		TerminateThread(threadId);
		schedf("  stat after terminate: ");
		printThreadStatus(threadId);

		DeleteThread(threadId);

		flushschedf();
	}

	{
		schedf("sleeping thread:\n");

		int threadId = createTestThread((void*)&sleepingThreadProc, INIT_PRIO - 0x10, sleepingThreadStack, STACK_SIZE);

		StartThread(threadId, 0);
		schedf("  stat after start: ");
		printThreadStatus(threadId);

		SuspendThread(threadId);
		schedf("  stat after suspend: ");
		printThreadStatus(threadId);

		ResumeThread(threadId);
		schedf("  stat after resume: ");
		printThreadStatus(threadId);

		TerminateThread(threadId);
		DeleteThread(threadId);

		flushschedf();
	}

	//Waiting thread
	{
		schedf("waiting thread:\n");

		int threadId = createTestThread((void*)&waitingThreadProc, INIT_PRIO - 0x10, waitingThreadStack, STACK_SIZE);

		StartThread(threadId, 0);
		schedf("  stat after start: ");
		printThreadStatus(threadId);

		SuspendThread(threadId);
		schedf("  stat after suspend: ");
		printThreadStatus(threadId);

		ResumeThread(threadId);
		schedf("  stat after resume: ");
		printThreadStatus(threadId);

		TerminateThread(threadId);
		DeleteThread(threadId);

		flushschedf();
	}

	//Various corner cases
	{
		//Add thread stat from spr_ram

		schedf("thread stat with invalid tid: ");
		printThreadStatus(~0);

		int result = ReferThreadStatus(0, NULL);
		schedf("self thread stat with null struct: %02x\n", result);

		flushschedf();
	}

	printf("-- TEST END\n");

	return 0;
}
<commit_msg>Added stat test with struct located in SPR.<commit_after>#include <common-ee.h>
#include <kernel.h>
#include <string.h>

#define INIT_PRIO 0x40
#define STACK_SIZE 0x8000
#define SPR_BEGIN 0x70000000

char nullThreadStack[STACK_SIZE] __attribute__ ((aligned(16)));
void nullThreadProc(u32) {
	//Do nothing
}

char sleepingThreadStack[STACK_SIZE] __attribute__ ((aligned(16)));
void sleepingThreadProc(u32) {
	SleepThread();
}

char waitingThreadStack[STACK_SIZE] __attribute__ ((aligned(16)));
void waitingThreadProc(u32) {
	ee_sema_t dummySemaInfo;
	dummySemaInfo.init_count = 0;
	dummySemaInfo.max_count = 1;
	dummySemaInfo.option = 0;
	u32 dummySema = CreateSema(&dummySemaInfo);
	WaitSema(dummySema);
}

int createTestThread(void *entry, int prio, void *stack, u32 stackSize) {
	ee_thread_t threadParam;
	memset(&threadParam, 0, sizeof(ee_thread_t));
	threadParam.func = entry;
	threadParam.initial_priority = prio;
	threadParam.stack = stack;
	threadParam.stack_size = stackSize;
	return CreateThread(&threadParam);
}

void printThreadStatus(int threadId) {
	ee_thread_status_t threadStat;
	memset(&threadStat, 0, sizeof(ee_thread_status_t));
	int result = ReferThreadStatus(threadId, &threadStat);
	if(result >= 0) {
		schedf("succeeded -> result: %02x, init prio: %02x current prio: %02x, status: %02x\n",
			result, threadStat.initial_priority, threadStat.current_priority, threadStat.status);
	} else {
		schedf("failed -> result: %d\n", result);
	}
}

int main(int argc, char **argv) {
	printf("-- TEST BEGIN\n");

	{
		schedf("self thread:\n");

		schedf("  stat (with tid 0): ");
		printThreadStatus(0);

		schedf("  stat (with current tid): ");
		printThreadStatus(GetThreadId());

		flushschedf();
	}

	{
		schedf("low prio thread:\n");

		int threadId = createTestThread((void*)&nullThreadProc, INIT_PRIO + 0x10, nullThreadStack, STACK_SIZE);
		schedf("  stat before start: ");
		printThreadStatus(threadId);

		StartThread(threadId, 0);
		schedf("  stat after start: ");
		printThreadStatus(threadId);

		SuspendThread(threadId);
		schedf("  stat after suspend: ");
		printThreadStatus(threadId);

		ResumeThread(threadId);
		schedf("  stat after resume: ");
		printThreadStatus(threadId);

		TerminateThread(threadId);
		schedf("  stat after terminate: ");
		printThreadStatus(threadId);

		DeleteThread(threadId);

		flushschedf();
	}

	{
		schedf("sleeping thread:\n");

		int threadId = createTestThread((void*)&sleepingThreadProc, INIT_PRIO - 0x10, sleepingThreadStack, STACK_SIZE);

		StartThread(threadId, 0);
		schedf("  stat after start: ");
		printThreadStatus(threadId);

		SuspendThread(threadId);
		schedf("  stat after suspend: ");
		printThreadStatus(threadId);

		ResumeThread(threadId);
		schedf("  stat after resume: ");
		printThreadStatus(threadId);

		TerminateThread(threadId);
		DeleteThread(threadId);

		flushschedf();
	}

	//Waiting thread
	{
		schedf("waiting thread:\n");

		int threadId = createTestThread((void*)&waitingThreadProc, INIT_PRIO - 0x10, waitingThreadStack, STACK_SIZE);

		StartThread(threadId, 0);
		schedf("  stat after start: ");
		printThreadStatus(threadId);

		SuspendThread(threadId);
		schedf("  stat after suspend: ");
		printThreadStatus(threadId);

		ResumeThread(threadId);
		schedf("  stat after resume: ");
		printThreadStatus(threadId);

		TerminateThread(threadId);
		DeleteThread(threadId);

		flushschedf();
	}

	//Various corner cases
	{
		schedf("thread stat with invalid tid: ");
		printThreadStatus(~0);

		{
			int result = ReferThreadStatus(0, NULL);
			schedf("self thread stat with null struct: %02x\n", result);
		}

		{
			ee_thread_status_t* threadStat = (ee_thread_status_t*)SPR_BEGIN;
			memset(threadStat, 0, sizeof(ee_thread_status_t));
			int result = ReferThreadStatus(0, threadStat);
			schedf("self thread stat with struct in spr -> result: %02x, status: %02x\n",
				result, threadStat->status);
		}

		flushschedf();
	}

	printf("-- TEST END\n");

	return 0;
}
<|endoftext|>