<commit_before>#include <stdlib.h>
#include <stdint.h>

#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <U8g2lib.h>
#include <avr/pgmspace.h>

#include "tetrominoes.h"
#include "tune.h"

U8G2_ST7920_128X64_F_HW_SPI scr(
    U8G2_R1/*Rotate the screen 90 degree clockwise*/,
    A5/*CS, pin 41*/,
    A4/*RESET, pin 40*/
);

constexpr int16_t kSpeakerPin = 9;

constexpr int16_t kFieldCols = 10;
constexpr int16_t kFieldRows = 22;
constexpr int16_t kFieldOffsetX = 5;
constexpr int16_t kFieldOffsetY = 1;
constexpr int16_t kBoxSize = 5;
constexpr int16_t kStartRow = -2;
constexpr int16_t kStartCol = 3;

constexpr uint32_t kDebounceMs = 50;
constexpr uint32_t kGameStepMs = 1000;
uint32_t nextStepMs = 0;

int16_t tetrRot = 0;
int16_t tetrRow = 0;
int16_t tetrCol = kStartCol;
int16_t tetrType = 0;

int16_t score = 0;
const int16_t kMaxScore = 999;

int16_t level = 0;
const int16_t kMaxLevel = 9;
const uint32_t kStepMs[kMaxLevel+1] = {1000, 800, 650, 500, 400, 300, 200, 100, 50, 10};
const int16_t kLinesPerLevel = 10;

bool field[kFieldRows][kFieldCols] = {0};

enum {
  BUTTON_LEFT,
  BUTTON_RIGHT,
  BUTTON_ROT,
  BUTTON_DROP,
  BUTTON_COUNT = BUTTON_DROP + 1,
};

enum {
  STATE_RUNNING,
  STATE_GAMEOVER,
  STATE_PAUSE,
};

int16_t state = STATE_RUNNING;

bool buttons[BUTTON_COUNT] = {false};
bool buttonsBefore[BUTTON_COUNT] = {false};
uint32_t lastPressedMs[BUTTON_COUNT] = {0};
const int16_t kButtonPins[BUTTON_COUNT] = {4, 5, 6, 7};

int16_t nextToneIndex = -1;
int16_t nextTone = 0;
uint16_t nextToneDurationMs = 0;
uint32_t nextToneTimeMs = 0;

bool currentTetromino[kTetrominoRows][kTetrominoCols] = {0};

void loadTetramino() {
  int16_t data = pgm_read_word_near(&kTetrominoes[tetrType][tetrRot]);
  for (int16_t row = 0; row < kTetrominoRows; ++row) {
    for (int16_t col = 0; col < kTetrominoCols; ++col) {
      currentTetromino[row][col] = (data & 1) == 1;
      data >>= 1;
    }
  }
}

inline bool wasPressed(int16_t btn) {
  return buttons[btn] && !buttonsBefore[btn];
}

inline void drawBox(int16_t row, int16_t col) {
  scr.drawBox(kFieldOffsetX + 2 + col * kBoxSize,
              kFieldOffsetY + 2 + row * kBoxSize,
              kBoxSize - 1,
              kBoxSize - 1);
}

void drawField() {
  scr.clearBuffer();
  scr.drawFrame(kFieldOffsetX,
                kFieldOffsetY,
                kFieldCols * kBoxSize + 3,
                kFieldRows * kBoxSize + 3);
  for (int16_t row = 0; row < kFieldRows; ++row) {
    for (int16_t col = 0; col < kFieldCols; ++col) {
      if (field[row][col]) {
        drawBox(row, col);
      }
    }
  }

  for (int16_t row = 0; row < kTetrominoRows; ++row) {
    for (int16_t col = 0; col < kTetrominoCols; ++col) {
      if (currentTetromino[row][col]) {
        drawBox(tetrRow + row, tetrCol + col);
      }
    }
  }

  scr.setCursor(3, 125);
  scr.print("S");
  scr.print(score);
  scr.setCursor(32, 125);
  scr.print("L");
  scr.print(level + 1);

  scr.sendBuffer();
}

void drawFinalScreen() {
  scr.setDrawColor(0);
  scr.drawBox(0, 47, 64, 18);
  scr.setDrawColor(1);
  scr.setCursor(5, 60);
  scr.print(F("GAME OVER"));
  scr.sendBuffer();
}

bool collides(int16_t trow, int16_t tcol) {
  for (int16_t row = 0; row < kTetrominoRows; ++row) {
    for (int16_t col = 0; col < kTetrominoCols; ++col) {
      if (currentTetromino[row][col]) {
        if (trow + row >= kFieldRows || tcol + col < 0 || tcol + col >= kFieldCols) {
          return true;
        }
        if (field[trow + row][tcol + col]) {
          return true;
        }
      }
    }
  }
  return false;
}

bool isCompleteRow(int16_t row) {
  for (int16_t col = 0; col < kFieldCols; ++col) {
    if (!field[row][col]) {
      return false;
    }
  }
  return true;
}

void deleteRow(int16_t row) {
  for (int16_t i = row; i > 0; --i) {
    for (int16_t col = 0; col < kFieldCols; ++col) {
      field[i][col] = field[i-1][col];
    }
  }
  for (int16_t col = 0; col < kFieldCols; ++col) {
    field[0][col] = false;
  }
  score++;
  if (score > kMaxScore) {
    score = kMaxScore;
  }
  level = score / kLinesPerLevel;
  if (level > kMaxLevel) {
    level = kMaxLevel;
  }
}

void placeTetromino() {
  for (int16_t row = 0; row < kTetrominoRows; ++row) {
    for (int16_t col = 0; col < kTetrominoCols; ++col) {
      if (currentTetromino[row][col]) {
        field[tetrRow + row][tetrCol + col] = true;
      }
    }
  }

  bool deleted;
  do {
    deleted = false;
    for (int16_t row = kFieldRows-1; row >= 0; --row) {
      if (isCompleteRow(row)) {
        deleteRow(row);
        deleted = true;
        break;
      }
    }
  } while (deleted);
}

void step() {
  if (collides(tetrRow + 1, tetrCol)) {
    placeTetromino();

    tetrRow = 0;
    tetrCol = kStartCol;
    tetrRot = 0;
    tetrType = random(kTetrominoCount);
    loadTetramino();

    if (collides(tetrRow, tetrCol)) {
      state = STATE_GAMEOVER;
    }
  } else {
    tetrRow++;
  }
}

// Returns whether there were changes.
bool updateGameState(uint32_t now) {
  bool changesMade = false;
  // Test rotation.
  if (wasPressed(BUTTON_ROT)) {
    // FIXME: load all rotations into RAM, pass rotation to collides().
    tetrRot = (tetrRot + 1) % kRotationCount;
    loadTetramino();
    changesMade = true;
    if (collides(tetrRow, tetrCol)) {
      // Undo.
      tetrRot = (tetrRot - 1) % kRotationCount;
      loadTetramino();
    }
  }

  if (wasPressed(BUTTON_LEFT)) {
    if (!collides(tetrRow, tetrCol - 1)) {
      --tetrCol;
    }
  }

  if (wasPressed(BUTTON_RIGHT)) {
    if (!collides(tetrRow, tetrCol + 1)) {
      ++tetrCol;
    }
  }

  if (now >= nextStepMs) {
    step();
    nextStepMs = now + kStepMs[level];
    changesMade = true;
  }

  return changesMade;
}

void initGame() {
  tetrType = random(kTetrominoCount);
  tetrRot = 0;
  tetrRow = 0;
  tetrCol = kStartCol;
  score = 0;
  for (int16_t row = 0; row < kFieldRows; ++row) {
    for (int16_t col = 0; col < kFieldCols; ++col) {
      field[row][col] = false;
    }
  }
  loadTetramino();
}

void setup() {
  randomSeed(analogRead(0));
  pinMode(kSpeakerPin, OUTPUT);
  for (uint16_t pin : kButtonPins) {
    pinMode(pin, INPUT_PULLUP);
  }
  scr.begin();
  scr.setFont(u8g2_font_profont12_tr);
  initGame();
}

void loop() {
  uint32_t now = millis();
  if (now >= nextToneTimeMs) {
    if (nextTone != 0) {
      tone(kSpeakerPin, nextTone, (uint32_t)nextToneDurationMs);
    }
    nextToneTimeMs = now + nextToneDurationMs;
    nextToneIndex = (nextToneIndex + 1) % kToneCount;
    nextTone = pgm_read_word_near(&kTones[nextToneIndex]);
    nextToneDurationMs = pgm_read_word_near(&kToneDurations[nextToneIndex]);
  }
  for (uint16_t i = 0; i < BUTTON_COUNT; ++i) {
    buttonsBefore[i] = buttons[i];
    if (now - lastPressedMs[i] > kDebounceMs) {
      if (digitalRead(kButtonPins[i]) == LOW) {
        buttons[i] = true;
        lastPressedMs[i] = now;
      } else {
        buttons[i] = false;
      }
    }
  }
  if (state == STATE_RUNNING) {
    if (updateGameState(now)) {
      drawField();
    }
  } else if (state == STATE_GAMEOVER) {
    drawFinalScreen();
  }
}
<commit_msg>adjust tetris speed<commit_after>#include <stdlib.h>
#include <stdint.h>

#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <U8g2lib.h>
#include <avr/pgmspace.h>

#include "tetrominoes.h"
#include "tune.h"

U8G2_ST7920_128X64_F_HW_SPI scr(
    U8G2_R1/*Rotate the screen 90 degree clockwise*/,
    A5/*CS, pin 41*/,
    A4/*RESET, pin 40*/
);

constexpr int16_t kSpeakerPin = 9;

constexpr int16_t kFieldCols = 10;
constexpr int16_t kFieldRows = 22;
constexpr int16_t kFieldOffsetX = 5;
constexpr int16_t kFieldOffsetY = 1;
constexpr int16_t kBoxSize = 5;
constexpr int16_t kStartRow = -2;
constexpr int16_t kStartCol = 3;

constexpr uint32_t kDebounceMs = 50;
constexpr uint32_t kGameStepMs = 1000;
uint32_t nextStepMs = 0;

int16_t tetrRot = 0;
int16_t tetrRow = 0;
int16_t tetrCol = kStartCol;
int16_t tetrType = 0;

int16_t score = 0;
const int16_t kMaxScore = 999;

int16_t level = 0;
const int16_t kMaxLevel = 9;
const uint32_t kStepMs[kMaxLevel+1] = {800, 700, 600, 500, 400, 300, 200, 100, 50, 10};
const int16_t kLinesPerLevel = 10;

bool field[kFieldRows][kFieldCols] = {0};

enum {
  BUTTON_LEFT,
  BUTTON_RIGHT,
  BUTTON_ROT,
  BUTTON_DROP,
  BUTTON_COUNT = BUTTON_DROP + 1,
};

enum {
  STATE_RUNNING,
  STATE_GAMEOVER,
  STATE_PAUSE,
};

int16_t state = STATE_RUNNING;

bool buttons[BUTTON_COUNT] = {false};
bool buttonsBefore[BUTTON_COUNT] = {false};
uint32_t lastPressedMs[BUTTON_COUNT] = {0};
const int16_t kButtonPins[BUTTON_COUNT] = {4, 5, 6, 7};

int16_t nextToneIndex = -1;
int16_t nextTone = 0;
uint16_t nextToneDurationMs = 0;
uint32_t nextToneTimeMs = 0;

bool currentTetromino[kTetrominoRows][kTetrominoCols] = {0};

void loadTetramino() {
  int16_t data = pgm_read_word_near(&kTetrominoes[tetrType][tetrRot]);
  for (int16_t row = 0; row < kTetrominoRows; ++row) {
    for (int16_t col = 0; col < kTetrominoCols; ++col) {
      currentTetromino[row][col] = (data & 1) == 1;
      data >>= 1;
    }
  }
}

inline bool wasPressed(int16_t btn) {
  return buttons[btn] && !buttonsBefore[btn];
}

inline void drawBox(int16_t row, int16_t col) {
  scr.drawBox(kFieldOffsetX + 2 + col * kBoxSize,
              kFieldOffsetY + 2 + row * kBoxSize,
              kBoxSize - 1,
              kBoxSize - 1);
}

void drawField() {
  scr.clearBuffer();
  scr.drawFrame(kFieldOffsetX,
                kFieldOffsetY,
                kFieldCols * kBoxSize + 3,
                kFieldRows * kBoxSize + 3);
  for (int16_t row = 0; row < kFieldRows; ++row) {
    for (int16_t col = 0; col < kFieldCols; ++col) {
      if (field[row][col]) {
        drawBox(row, col);
      }
    }
  }

  for (int16_t row = 0; row < kTetrominoRows; ++row) {
    for (int16_t col = 0; col < kTetrominoCols; ++col) {
      if (currentTetromino[row][col]) {
        drawBox(tetrRow + row, tetrCol + col);
      }
    }
  }

  scr.setCursor(3, 125);
  scr.print("S");
  scr.print(score);
  scr.setCursor(32, 125);
  scr.print("L");
  scr.print(level + 1);

  scr.sendBuffer();
}

void drawFinalScreen() {
  scr.setDrawColor(0);
  scr.drawBox(0, 47, 64, 18);
  scr.setDrawColor(1);
  scr.setCursor(5, 60);
  scr.print(F("GAME OVER"));
  scr.sendBuffer();
}

bool collides(int16_t trow, int16_t tcol) {
  for (int16_t row = 0; row < kTetrominoRows; ++row) {
    for (int16_t col = 0; col < kTetrominoCols; ++col) {
      if (currentTetromino[row][col]) {
        if (trow + row >= kFieldRows || tcol + col < 0 || tcol + col >= kFieldCols) {
          return true;
        }
        if (field[trow + row][tcol + col]) {
          return true;
        }
      }
    }
  }
  return false;
}

bool isCompleteRow(int16_t row) {
  for (int16_t col = 0; col < kFieldCols; ++col) {
    if (!field[row][col]) {
      return false;
    }
  }
  return true;
}

void deleteRow(int16_t row) {
  for (int16_t i = row; i > 0; --i) {
    for (int16_t col = 0; col < kFieldCols; ++col) {
      field[i][col] = field[i-1][col];
    }
  }
  for (int16_t col = 0; col < kFieldCols; ++col) {
    field[0][col] = false;
  }
  score++;
  if (score > kMaxScore) {
    score = kMaxScore;
  }
  level = score / kLinesPerLevel;
  if (level > kMaxLevel) {
    level = kMaxLevel;
  }
}

void placeTetromino() {
  for (int16_t row = 0; row < kTetrominoRows; ++row) {
    for (int16_t col = 0; col < kTetrominoCols; ++col) {
      if (currentTetromino[row][col]) {
        field[tetrRow + row][tetrCol + col] = true;
      }
    }
  }

  bool deleted;
  do {
    deleted = false;
    for (int16_t row = kFieldRows-1; row >= 0; --row) {
      if (isCompleteRow(row)) {
        deleteRow(row);
        deleted = true;
        break;
      }
    }
  } while (deleted);
}

void step() {
  if (collides(tetrRow + 1, tetrCol)) {
    placeTetromino();

    tetrRow = 0;
    tetrCol = kStartCol;
    tetrRot = 0;
    tetrType = random(kTetrominoCount);
    loadTetramino();

    if (collides(tetrRow, tetrCol)) {
      state = STATE_GAMEOVER;
    }
  } else {
    tetrRow++;
  }
}

// Returns whether there were changes.
bool updateGameState(uint32_t now) {
  bool changesMade = false;
  // Test rotation.
  if (wasPressed(BUTTON_ROT)) {
    // FIXME: load all rotations into RAM, pass rotation to collides().
    tetrRot = (tetrRot + 1) % kRotationCount;
    loadTetramino();
    changesMade = true;
    if (collides(tetrRow, tetrCol)) {
      // Undo.
      tetrRot = (tetrRot - 1) % kRotationCount;
      loadTetramino();
    }
  }

  if (wasPressed(BUTTON_LEFT)) {
    if (!collides(tetrRow, tetrCol - 1)) {
      --tetrCol;
    }
  }

  if (wasPressed(BUTTON_RIGHT)) {
    if (!collides(tetrRow, tetrCol + 1)) {
      ++tetrCol;
    }
  }

  if (now >= nextStepMs) {
    step();
    nextStepMs = now + kStepMs[level];
    changesMade = true;
  }

  return changesMade;
}

void initGame() {
  tetrType = random(kTetrominoCount);
  tetrRot = 0;
  tetrRow = 0;
  tetrCol = kStartCol;
  score = 0;
  for (int16_t row = 0; row < kFieldRows; ++row) {
    for (int16_t col = 0; col < kFieldCols; ++col) {
      field[row][col] = false;
    }
  }
  loadTetramino();
}

void setup() {
  randomSeed(analogRead(0));
  pinMode(kSpeakerPin, OUTPUT);
  for (uint16_t pin : kButtonPins) {
    pinMode(pin, INPUT_PULLUP);
  }
  scr.begin();
  scr.setFont(u8g2_font_profont12_tr);
  initGame();
}

void loop() {
  uint32_t now = millis();
  if (now >= nextToneTimeMs) {
    if (nextTone != 0) {
      tone(kSpeakerPin, nextTone, (uint32_t)nextToneDurationMs);
    }
    nextToneTimeMs = now + nextToneDurationMs;
    nextToneIndex = (nextToneIndex + 1) % kToneCount;
    nextTone = pgm_read_word_near(&kTones[nextToneIndex]);
    nextToneDurationMs = pgm_read_word_near(&kToneDurations[nextToneIndex]);
  }
  for (uint16_t i = 0; i < BUTTON_COUNT; ++i) {
    buttonsBefore[i] = buttons[i];
    if (now - lastPressedMs[i] > kDebounceMs) {
      if (digitalRead(kButtonPins[i]) == LOW) {
        buttons[i] = true;
        lastPressedMs[i] = now;
      } else {
        buttons[i] = false;
      }
    }
  }
  if (state == STATE_RUNNING) {
    if (updateGameState(now)) {
      drawField();
    }
  } else if (state == STATE_GAMEOVER) {
    drawFinalScreen();
  }
}
<|endoftext|>


<commit_before>/*******************************************************************/
/*                               XDMF                              */
/*                   eXtensible Data Model and Format */
/*                                                                 */
/*  Id : Id  */
/*  Date : $Date$ */
/*  Version : $Revision$ */
/*                                                                 */
/*  Author:                                                        */
/*     Jerry A. Clarke                                             */
/*     clarke@arl.army.mil                                         */
/*     US Army Research Laboratory                                 */
/*     Aberdeen Proving Ground, MD                                 */
/*                                                                 */
/*     Copyright @ 2002 US Army Research Laboratory                */
/*     All Rights Reserved                                         */
/*     See Copyright.txt or http://www.arl.hpc.mil/ice for details */
/*                                                                 */
/*     This software is distributed WITHOUT ANY WARRANTY; without  */
/*     even the implied warranty of MERCHANTABILITY or FITNESS     */
/*     FOR A PARTICULAR PURPOSE.  See the above copyright notice   */
/*     for more information.                                       */
/*                                                                 */
/*******************************************************************/
#include "XdmfObject.h"
#include "XdmfValuesHDF.h"
#include "XdmfHDF.h"
#include "XdmfDOM.h"
#include "XdmfDataStructure.h"
#include "XdmfArray.h"

XdmfValuesHDF::XdmfValuesHDF() {
    this->SetFormat(XDMF_FORMAT_HDF);
}

XdmfValuesHDF::~XdmfValuesHDF() {
}

XdmfArray *
XdmfValuesHDF::Read(XdmfArray *anArray){
    XdmfArray   *RetArray = anArray;
    XdmfString  DataSetName = 0;
    XdmfHDF     H5;

    if(!this->DataDesc){
        XdmfErrorMessage("DataDesc has not been set");
        return(NULL);
    }
    H5.SetWorkingDirectory(this->DOM->GetWorkingDirectory());
    XDMF_STRING_DUPLICATE(DataSetName, this->Get("CDATA"));
    if(!DataSetName || strlen(DataSetName) < 1){
        XdmfErrorMessage("Invalid HDF5 Dataset Name");
        return(NULL);
    }
    XDMF_WORD_TRIM(DataSetName);
    //! Possible Read from DSM. Make sure we're connected.
    if(!this->DsmBuffer) this->SetDsmBuffer(anArray->GetDsmBuffer());
    XdmfDebug("Opening HDF5 Data for Reading : " << DataSetName);
    // Allocate Array if Necessary
    if(!RetArray){
        RetArray = new XdmfArray();
        if(!RetArray){
            XdmfErrorMessage("Error Allocating New Array");
            return(NULL);
        }
        RetArray->CopyType(this->DataDesc);
        RetArray->CopyShape(this->DataDesc);
        RetArray->CopySelection(this->DataDesc);
        RetArray->Allocate();
    }
    H5.SetDsmBuffer(this->DsmBuffer);
    if( H5.Open( DataSetName, "r" ) == XDMF_FAIL ) {
        XdmfErrorMessage("Can't Open Dataset " << DataSetName);
        if(!anArray) delete RetArray;
        RetArray = NULL;
    }else{
        if(this->DataDesc->GetSelectionSize() != H5.GetNumberOfElements() ){
          // We're not reading the entire dataset
            if( this->DataDesc->GetSelectionType() == XDMF_HYPERSLAB ){
                XdmfInt32  Rank;
                XdmfInt64  Start[ XDMF_MAX_DIMENSION ];
                XdmfInt64  Stride[ XDMF_MAX_DIMENSION ];
                XdmfInt64  Count[ XDMF_MAX_DIMENSION ];

                // Select the HyperSlab from HDF5
                Rank = this->DataDesc->GetHyperSlab( Start, Stride, Count );
                H5.SelectHyperSlab( Start, Stride, Count );
                if(RetArray->GetSelectionSize() < H5.GetSelectionSize()){
                    XdmfErrorMessage("Return Array No Large Enough to Hold Selected Data");
                    RetArray->SetShapeFromSelection(&H5);
                }
                // RetArray->SetShape(Rank, Count);
                // RetArray->SelectAll();
            } else {
                XdmfInt64  NumberOfCoordinates;
                XdmfInt64  *Coordinates;

                // Select Parametric Coordinates from HDF5
                NumberOfCoordinates = this->DataDesc->GetSelectionSize();
                Coordinates = this->DataDesc->GetCoordinates();
                RetArray->SetNumberOfElements(NumberOfCoordinates);
                H5.SelectCoordinates(NumberOfCoordinates, Coordinates);
                delete Coordinates;
                }
            }
        XdmfDebug("Reading " << H5.GetSelectionSize() << " into Array of " << RetArray->GetSelectionSize() );
        if( H5.Read(RetArray) == NULL ){
            XdmfErrorMessage("Can't Read Dataset " << DataSetName);
            if(!anArray) delete RetArray;
            RetArray = NULL;
        }else{
            this->SetHeavyDataSetName(DataSetName);
        }
    H5.Close();
    }
    delete [] DataSetName;
    return(RetArray);
}

XdmfInt32
XdmfValuesHDF::Write(XdmfArray *anArray, XdmfConstString aHeavyDataSetName){
    char* hds;
    XdmfHDF H5;

    H5.SetWorkingDirectory(this->DOM->GetWorkingDirectory());
    if(!aHeavyDataSetName) aHeavyDataSetName = this->GetHeavyDataSetName();
    if(!aHeavyDataSetName){
        if(anArray->GetHeavyDataSetName()){
            aHeavyDataSetName = (XdmfConstString)anArray->GetHeavyDataSetName();
        }else{
            aHeavyDataSetName = this->GetUniqueName("Xdmf.h5:/Data");
        }
    }
    // Possible Write to DSM. Make sure we're connected
    if(!this->DsmBuffer) this->SetDsmBuffer(anArray->GetDsmBuffer());
    XdmfDebug("Writing Values to " << aHeavyDataSetName);
    if(!this->DataDesc ){
        XdmfErrorMessage("DataDesc has not been set");
        return(XDMF_FAIL);
    }
    if(!anArray){
        XdmfErrorMessage("Array to Write is NULL");
        return(XDMF_FAIL);
    }
    XDMF_STRING_DUPLICATE(hds, aHeavyDataSetName);
    XDMF_WORD_TRIM( hds );
    this->Set("CDATA", hds);
    H5.SetCompression(anArray->GetCompression());
    H5.CopyType(this->DataDesc);
    H5.CopyShape(this->DataDesc);
    H5.CopySelection(this->DataDesc);
    H5.SetDsmBuffer(this->DsmBuffer);
    if(H5.Open(hds, "rw") == XDMF_FAIL){
        XdmfErrorMessage("Error Opening " << hds << " for Writing");
        delete [] hds ;
        return(XDMF_FAIL);
    }
    if(H5.Write(anArray) == XDMF_FAIL){
        XdmfErrorMessage("Error Writing " << hds );
        H5.Close();
        delete [] hds;
        return(XDMF_FAIL);
    }
    H5.Close();
    delete [] hds;
    return(XDMF_SUCCESS);
}

XdmfString XdmfValuesHDF::DataItemFromHDF(XdmfConstString H5DataSet){
    XdmfHDF         H5;
    ostrstream      StringOutput;
    char            *Ptr;
    static XdmfString ReturnString = NULL;

    if(H5.Open(H5DataSet, "r") == XDMF_FAIL){
        XdmfErrorMessage("Can't open H5 Dataset " << H5DataSet << " for reading");
        return(NULL);
    }
    StringOutput << "<DataItem NumberType=\"";
    StringOutput << XdmfTypeToClassString(H5.GetNumberType());
    StringOutput << "\" Precision=\"";
    StringOutput << H5.GetElementSize();
    StringOutput << "\" Dimensions=\"";
    StringOutput << H5.GetShapeAsString();
    StringOutput << "\">" << H5DataSet << "</DataItem>";
    StringOutput << ends;
    H5.Close();

    if ( ReturnString != NULL ) delete [] ReturnString;
    Ptr = StringOutput.str();
    ReturnString = new char[strlen(Ptr) + 2 ];
    strcpy( ReturnString, Ptr );
    return(ReturnString);
}
<commit_msg>ENH: Make xdmf h5 heavy data file foo.h5 when creating foo.xmf.<commit_after>/*******************************************************************/
/*                               XDMF                              */
/*                   eXtensible Data Model and Format */
/*                                                                 */
/*  Id : Id  */
/*  Date : $Date$ */
/*  Version : $Revision$ */
/*                                                                 */
/*  Author:                                                        */
/*     Jerry A. Clarke                                             */
/*     clarke@arl.army.mil                                         */
/*     US Army Research Laboratory                                 */
/*     Aberdeen Proving Ground, MD                                 */
/*                                                                 */
/*     Copyright @ 2002 US Army Research Laboratory                */
/*     All Rights Reserved                                         */
/*     See Copyright.txt or http://www.arl.hpc.mil/ice for details */
/*                                                                 */
/*     This software is distributed WITHOUT ANY WARRANTY; without  */
/*     even the implied warranty of MERCHANTABILITY or FITNESS     */
/*     FOR A PARTICULAR PURPOSE.  See the above copyright notice   */
/*     for more information.                                       */
/*                                                                 */
/*******************************************************************/
#include "XdmfObject.h"
#include "XdmfValuesHDF.h"
#include "XdmfHDF.h"
#include "XdmfDOM.h"
#include "XdmfDataStructure.h"
#include "XdmfArray.h"

XdmfValuesHDF::XdmfValuesHDF() {
    this->SetFormat(XDMF_FORMAT_HDF);
}

XdmfValuesHDF::~XdmfValuesHDF() {
}

XdmfArray *
XdmfValuesHDF::Read(XdmfArray *anArray){
    XdmfArray   *RetArray = anArray;
    XdmfString  DataSetName = 0;
    XdmfHDF     H5;

    if(!this->DataDesc){
        XdmfErrorMessage("DataDesc has not been set");
        return(NULL);
    }
    H5.SetWorkingDirectory(this->DOM->GetWorkingDirectory());
    XDMF_STRING_DUPLICATE(DataSetName, this->Get("CDATA"));
    if(!DataSetName || strlen(DataSetName) < 1){
        XdmfErrorMessage("Invalid HDF5 Dataset Name");
        return(NULL);
    }
    XDMF_WORD_TRIM(DataSetName);
    //! Possible Read from DSM. Make sure we're connected.
    if(!this->DsmBuffer) this->SetDsmBuffer(anArray->GetDsmBuffer());
    XdmfDebug("Opening HDF5 Data for Reading : " << DataSetName);
    // Allocate Array if Necessary
    if(!RetArray){
        RetArray = new XdmfArray();
        if(!RetArray){
            XdmfErrorMessage("Error Allocating New Array");
            return(NULL);
        }
        RetArray->CopyType(this->DataDesc);
        RetArray->CopyShape(this->DataDesc);
        RetArray->CopySelection(this->DataDesc);
        RetArray->Allocate();
    }
    H5.SetDsmBuffer(this->DsmBuffer);
    if( H5.Open( DataSetName, "r" ) == XDMF_FAIL ) {
        XdmfErrorMessage("Can't Open Dataset " << DataSetName);
        if(!anArray) delete RetArray;
        RetArray = NULL;
    }else{
        if(this->DataDesc->GetSelectionSize() != H5.GetNumberOfElements() ){
          // We're not reading the entire dataset
            if( this->DataDesc->GetSelectionType() == XDMF_HYPERSLAB ){
                XdmfInt32  Rank;
                XdmfInt64  Start[ XDMF_MAX_DIMENSION ];
                XdmfInt64  Stride[ XDMF_MAX_DIMENSION ];
                XdmfInt64  Count[ XDMF_MAX_DIMENSION ];

                // Select the HyperSlab from HDF5
                Rank = this->DataDesc->GetHyperSlab( Start, Stride, Count );
                H5.SelectHyperSlab( Start, Stride, Count );
                if(RetArray->GetSelectionSize() < H5.GetSelectionSize()){
                    XdmfErrorMessage("Return Array No Large Enough to Hold Selected Data");
                    RetArray->SetShapeFromSelection(&H5);
                }
                // RetArray->SetShape(Rank, Count);
                // RetArray->SelectAll();
            } else {
                XdmfInt64  NumberOfCoordinates;
                XdmfInt64  *Coordinates;

                // Select Parametric Coordinates from HDF5
                NumberOfCoordinates = this->DataDesc->GetSelectionSize();
                Coordinates = this->DataDesc->GetCoordinates();
                RetArray->SetNumberOfElements(NumberOfCoordinates);
                H5.SelectCoordinates(NumberOfCoordinates, Coordinates);
                delete Coordinates;
                }
            }
        XdmfDebug("Reading " << H5.GetSelectionSize() << " into Array of " << RetArray->GetSelectionSize() );
        if( H5.Read(RetArray) == NULL ){
            XdmfErrorMessage("Can't Read Dataset " << DataSetName);
            if(!anArray) delete RetArray;
            RetArray = NULL;
        }else{
            this->SetHeavyDataSetName(DataSetName);
        }
    H5.Close();
    }
    delete [] DataSetName;
    return(RetArray);
}

XdmfInt32
XdmfValuesHDF::Write(XdmfArray *anArray, XdmfConstString aHeavyDataSetName){
    char* hds;
    XdmfHDF H5;

    H5.SetWorkingDirectory(this->DOM->GetWorkingDirectory());
    if(!aHeavyDataSetName) aHeavyDataSetName = this->GetHeavyDataSetName();
    if(!aHeavyDataSetName){
        if(anArray->GetHeavyDataSetName())
          {
          aHeavyDataSetName = (XdmfConstString)anArray->GetHeavyDataSetName();
          }
        else
          {
          static char FName[256];
          sprintf(FName, "%s", this->DOM->GetOutputFileName());
          char *ext = strstr(FName, ".xmf");
          const char *NewExt = ".h5:/Data";
          if (ext && ext < FName+(256-strlen(NewExt)))
            {
            sprintf(ext, NewExt);
            aHeavyDataSetName = this->GetUniqueName(FName);
            }
          else
            {
            aHeavyDataSetName = this->GetUniqueName("Xdmf.h5:/Data");
            }
          }
    }
    // Possible Write to DSM. Make sure we're connected
    if(!this->DsmBuffer) this->SetDsmBuffer(anArray->GetDsmBuffer());
    XdmfDebug("Writing Values to " << aHeavyDataSetName);
    if(!this->DataDesc ){
        XdmfErrorMessage("DataDesc has not been set");
        return(XDMF_FAIL);
    }
    if(!anArray){
        XdmfErrorMessage("Array to Write is NULL");
        return(XDMF_FAIL);
    }
    XDMF_STRING_DUPLICATE(hds, aHeavyDataSetName);
    XDMF_WORD_TRIM( hds );
    this->Set("CDATA", hds);
    H5.SetCompression(anArray->GetCompression());
    H5.CopyType(this->DataDesc);
    H5.CopyShape(this->DataDesc);
    H5.CopySelection(this->DataDesc);
    H5.SetDsmBuffer(this->DsmBuffer);
    if(H5.Open(hds, "rw") == XDMF_FAIL){
        XdmfErrorMessage("Error Opening " << hds << " for Writing");
        delete [] hds ;
        return(XDMF_FAIL);
    }
    if(H5.Write(anArray) == XDMF_FAIL){
        XdmfErrorMessage("Error Writing " << hds );
        H5.Close();
        delete [] hds;
        return(XDMF_FAIL);
    }
    H5.Close();
    delete [] hds;
    return(XDMF_SUCCESS);
}

XdmfString XdmfValuesHDF::DataItemFromHDF(XdmfConstString H5DataSet){
    XdmfHDF         H5;
    ostrstream      StringOutput;
    char            *Ptr;
    static XdmfString ReturnString = NULL;

    if(H5.Open(H5DataSet, "r") == XDMF_FAIL){
        XdmfErrorMessage("Can't open H5 Dataset " << H5DataSet << " for reading");
        return(NULL);
    }
    StringOutput << "<DataItem NumberType=\"";
    StringOutput << XdmfTypeToClassString(H5.GetNumberType());
    StringOutput << "\" Precision=\"";
    StringOutput << H5.GetElementSize();
    StringOutput << "\" Dimensions=\"";
    StringOutput << H5.GetShapeAsString();
    StringOutput << "\">" << H5DataSet << "</DataItem>";
    StringOutput << ends;
    H5.Close();

    if ( ReturnString != NULL ) delete [] ReturnString;
    Ptr = StringOutput.str();
    ReturnString = new char[strlen(Ptr) + 2 ];
    strcpy( ReturnString, Ptr );
    return(ReturnString);
}
<|endoftext|>


<commit_before>//
// Created by malachi on 12/27/17.
//

#include <catch.hpp>

#include "../coap-dispatcher.h"
#include "test-data.h"

using namespace moducom::coap;
using namespace moducom::coap::experimental;
using namespace moducom::pipeline;

// Specialized prefix checker which does not expect s to be
// null terminated, but does expect prefix to be null terminated
template <typename TChar>
bool starts_with(const TChar* s, int slen, const char* prefix)
{
    while(*prefix && slen--)
    {
        if(*prefix++ != *s++) return false;
    }

    return true;
}

bool starts_with(MemoryChunk::readonly_t chunk, const char* prefix)
{
    return starts_with(chunk.data(), chunk.length(), prefix);
}

class UriPathDispatcherHandler : public DispatcherHandlerBase
{
    const char* prefix;
    IMessageObserver& observer;

public:
    UriPathDispatcherHandler(const char* prefix, IMessageObserver& observer)
            : prefix(prefix),
              observer(observer)
    {

    }

    void on_header(Header header) OVERRIDE
    {
        if(!header.is_request()) interested(Never);
    }

    void on_option(number_t number, uint16_t length) OVERRIDE
    {
        if(is_always_interested())
        {
            observer.on_option(number, length);
            return;
        }
    }

    void on_option(number_t number,
                           const MemoryChunk::readonly_t& option_value_part,
                           bool last_chunk) OVERRIDE
    {
        // If we're always interested, then we've gone into pass thru mode
        if(is_always_interested())
        {
            observer.on_option(number, option_value_part, last_chunk);
            return;
        }

        switch(number)
        {
            case Option::UriPath:
                // FIX: I think we don't need this, because path is already
                // chunked out so 99% of the time we'll want to compare the
                // whole string not just the prefix - but I suppose comparing
                // the as a prefix doesn't hurt us
                if(starts_with(option_value_part, prefix))
                    interested(Always);
                else
                    // If we don't get what we want right away, then we are
                    // no longer interested (more prefix style behavior)
                    interested(Never);

                // TODO: We'll want to not only indicate interest but also
                // have a subordinate dispatcher to act on further observations
                break;
        }
    }

    void on_payload(const MemoryChunk::readonly_t& payload_part, bool last_chunk) OVERRIDE
    {
        ASSERT_WARN(true, is_always_interested(), "Should only arrive here if interested");

        observer.on_payload(payload_part, last_chunk);
    }
};

class TestDispatcherHandler : public DispatcherHandlerBase
{
    int option_test_number;

public:
    TestDispatcherHandler(InterestedEnum i = Always) :
            DispatcherHandlerBase(i),
            option_test_number(0) {}

    virtual void on_header(Header header) OVERRIDE
    {
        REQUIRE(header.is_request());
    }

    virtual void on_token(const MemoryChunk::readonly_t& token_part, bool last_chunk) OVERRIDE
    {
        FAIL("Should not reach here");
    }

    virtual void on_option(number_t number, uint16_t length) OVERRIDE
    {
        switch(option_test_number)
        {
            case 0:
                REQUIRE(number == 270);
                REQUIRE(length == 1);
                break;

            case 1:
                REQUIRE(number == 271);
                REQUIRE(length == 2);
                break;
        }
    }

    virtual void on_option(number_t number, const MemoryChunk::readonly_t& option_value_part, bool last_chunk) OVERRIDE
    {
        switch(option_test_number++)
        {
            case 0:
                REQUIRE(option_value_part[0] == 3);
                REQUIRE(option_value_part.length() == 1);
                break;

            case 1:
                REQUIRE(option_value_part[0] == 4);
                REQUIRE(option_value_part[1] == 5);
                REQUIRE(option_value_part.length() == 2);
                break;
        }
    }

    virtual void on_payload(const MemoryChunk::readonly_t& payload_part, bool last_chunk) OVERRIDE
    {
        REQUIRE(payload_part[0] == buffer_16bit_delta[12]);
        REQUIRE(payload_part[payload_part.length()] == buffer_16bit_delta[12 + payload_part.length()]);
    }
};

extern dispatcher_handler_factory_fn test_sub_factories[];

IDispatcherHandler* test_factory1(MemoryChunk chunk)
{
    return new (chunk.data()) TestDispatcherHandler(IDispatcherHandler::Never);
}

IDispatcherHandler* test_factory2(MemoryChunk chunk)
{
    MemoryChunk& uri_handler_chunk = chunk;
    MemoryChunk v1_handler_chunk = chunk.remainder(sizeof(UriPathDispatcherHandler));
    MemoryChunk v1_handler_inner_chunk = v1_handler_chunk.remainder(sizeof(FactoryDispatcherHandler));

    FactoryDispatcherHandler* fdh = new (v1_handler_chunk.data()) FactoryDispatcherHandler(
            v1_handler_inner_chunk,
            test_sub_factories, 1);

    // TODO: will need some way to invoke fdh destructor
    //return new (uri_handler_chunk.data()) UriPathDispatcherHandler("v1", *fdh);
    // TEST instead of v1 to work with our existing test data
    return new (uri_handler_chunk.data()) UriPathDispatcherHandler("TEST", *fdh);
}

dispatcher_handler_factory_fn test_factories[] =
{
    test_factory1,
    test_factory2
};

class TestDispatcherHandler2 : public DispatcherHandlerBase
{
public:
    void on_payload(const MemoryChunk::readonly_t& payload_part,
                    bool last_chunk) OVERRIDE
    {
        REQUIRE(payload_part[0] == 0x10);
        REQUIRE(payload_part[1] == 0x11);
        REQUIRE(payload_part[2] == 0x12);
        REQUIRE(payload_part.length() == 7);
    }
};

IDispatcherHandler* test_sub_factory1(MemoryChunk chunk)
{
    static TestDispatcherHandler2 handler;

    // To be v1/path1
    //return new (chunk.data()) UriPathDispatcherHandler("path1", handler);
    // TEST/POS to work with our existing test data
    return new (chunk.data()) UriPathDispatcherHandler("POS", handler);
}

dispatcher_handler_factory_fn test_sub_factories[] =
{
    test_sub_factory1
};

TEST_CASE("CoAP dispatcher tests", "[coap-dispatcher]")
{
    SECTION("Test 1")
    {
        MemoryChunk chunk(buffer_16bit_delta, sizeof(buffer_16bit_delta));

        TestDispatcherHandler dispatcherHandler;
        Dispatcher dispatcher;
        //layer3::MemoryChunk<128> chunk;

        dispatcher.head(&dispatcherHandler);
        dispatcher.dispatch(chunk);

    }
    SECTION("Factory")
    {
        MemoryChunk chunk(buffer_plausible, sizeof(buffer_plausible));

        // in-place new holder
        layer3::MemoryChunk<128> dispatcherBuffer;

        FactoryDispatcherHandler fdh(dispatcherBuffer, test_factories, 2);
        Dispatcher dispatcher;

        // doesn't fully test new UriPath handler because TestDispatcherHandler
        // is not stateless (and shouldn't be expected to be) but because of that
        // setting it to "Currently" makes it unable to test its own options properly
        dispatcher.head(&fdh);
        dispatcher.dispatch(chunk);
    }
}<commit_msg>Making helper template for uri+handler combos<commit_after>//
// Created by malachi on 12/27/17.
//

#include <catch.hpp>

#include "../coap-dispatcher.h"
#include "test-data.h"

using namespace moducom::coap;
using namespace moducom::coap::experimental;
using namespace moducom::pipeline;

// Specialized prefix checker which does not expect s to be
// null terminated, but does expect prefix to be null terminated
template <typename TChar>
bool starts_with(const TChar* s, int slen, const char* prefix)
{
    while(*prefix && slen--)
    {
        if(*prefix++ != *s++) return false;
    }

    return true;
}

bool starts_with(MemoryChunk::readonly_t chunk, const char* prefix)
{
    return starts_with(chunk.data(), chunk.length(), prefix);
}

class UriPathDispatcherHandler : public DispatcherHandlerBase
{
    const char* prefix;
    IMessageObserver& observer;

public:
    UriPathDispatcherHandler(const char* prefix, IMessageObserver& observer)
            : prefix(prefix),
              observer(observer)
    {

    }

    void on_header(Header header) OVERRIDE
    {
        if(!header.is_request()) interested(Never);
    }

    void on_option(number_t number, uint16_t length) OVERRIDE
    {
        if(is_always_interested())
        {
            observer.on_option(number, length);
            return;
        }
    }

    void on_option(number_t number,
                           const MemoryChunk::readonly_t& option_value_part,
                           bool last_chunk) OVERRIDE
    {
        // If we're always interested, then we've gone into pass thru mode
        if(is_always_interested())
        {
            observer.on_option(number, option_value_part, last_chunk);
            return;
        }

        switch(number)
        {
            case Option::UriPath:
                // FIX: I think we don't need this, because path is already
                // chunked out so 99% of the time we'll want to compare the
                // whole string not just the prefix - but I suppose comparing
                // the as a prefix doesn't hurt us
                if(starts_with(option_value_part, prefix))
                    interested(Always);
                else
                    // If we don't get what we want right away, then we are
                    // no longer interested (more prefix style behavior)
                    interested(Never);

                // TODO: We'll want to not only indicate interest but also
                // have a subordinate dispatcher to act on further observations
                break;
        }
    }

    void on_payload(const MemoryChunk::readonly_t& payload_part, bool last_chunk) OVERRIDE
    {
        ASSERT_WARN(true, is_always_interested(), "Should only arrive here if interested");

        observer.on_payload(payload_part, last_chunk);
    }
};

class TestDispatcherHandler : public DispatcherHandlerBase
{
    int option_test_number;

public:
    TestDispatcherHandler(InterestedEnum i = Always) :
            DispatcherHandlerBase(i),
            option_test_number(0) {}

    virtual void on_header(Header header) OVERRIDE
    {
        REQUIRE(header.is_request());
    }

    virtual void on_token(const MemoryChunk::readonly_t& token_part, bool last_chunk) OVERRIDE
    {
        FAIL("Should not reach here");
    }

    virtual void on_option(number_t number, uint16_t length) OVERRIDE
    {
        switch(option_test_number)
        {
            case 0:
                REQUIRE(number == 270);
                REQUIRE(length == 1);
                break;

            case 1:
                REQUIRE(number == 271);
                REQUIRE(length == 2);
                break;
        }
    }

    virtual void on_option(number_t number, const MemoryChunk::readonly_t& option_value_part, bool last_chunk) OVERRIDE
    {
        switch(option_test_number++)
        {
            case 0:
                REQUIRE(option_value_part[0] == 3);
                REQUIRE(option_value_part.length() == 1);
                break;

            case 1:
                REQUIRE(option_value_part[0] == 4);
                REQUIRE(option_value_part[1] == 5);
                REQUIRE(option_value_part.length() == 2);
                break;
        }
    }

    virtual void on_payload(const MemoryChunk::readonly_t& payload_part, bool last_chunk) OVERRIDE
    {
        REQUIRE(payload_part[0] == buffer_16bit_delta[12]);
        REQUIRE(payload_part[payload_part.length()] == buffer_16bit_delta[12 + payload_part.length()]);
    }
};

extern dispatcher_handler_factory_fn test_sub_factories[];

IDispatcherHandler* test_factory1(MemoryChunk chunk)
{
    return new (chunk.data()) TestDispatcherHandler(IDispatcherHandler::Never);
}

template <dispatcher_handler_factory_fn* factories, int count, const char* uri_path>
IDispatcherHandler* uri_helper(MemoryChunk chunk)
{
    MemoryChunk& uri_handler_chunk = chunk;
    MemoryChunk sub_handler_chunk = chunk.remainder(sizeof(UriPathDispatcherHandler));
    MemoryChunk sub_handler_inner_chunk = sub_handler_chunk.remainder(sizeof(FactoryDispatcherHandler));

    FactoryDispatcherHandler* fdh = new (sub_handler_chunk.data()) FactoryDispatcherHandler(
            sub_handler_inner_chunk,
            factories, count);

    return new (uri_handler_chunk.data()) UriPathDispatcherHandler(uri_path, *fdh);
}

IDispatcherHandler* test_factory2(MemoryChunk chunk)
{
    MemoryChunk& uri_handler_chunk = chunk;
    MemoryChunk v1_handler_chunk = chunk.remainder(sizeof(UriPathDispatcherHandler));
    MemoryChunk v1_handler_inner_chunk = v1_handler_chunk.remainder(sizeof(FactoryDispatcherHandler));

    FactoryDispatcherHandler* fdh = new (v1_handler_chunk.data()) FactoryDispatcherHandler(
            v1_handler_inner_chunk,
            test_sub_factories, 1);

    // TODO: will need some way to invoke fdh destructor
    //return new (uri_handler_chunk.data()) UriPathDispatcherHandler("v1", *fdh);
    // TEST instead of v1 to work with our existing test data
    return new (uri_handler_chunk.data()) UriPathDispatcherHandler("OLD_TEST", *fdh);
}

extern CONSTEXPR char TEST_FACTORY4_NAME[] = "TEST";

dispatcher_handler_factory_fn test_factories[] =
{
    test_factory1,
    test_factory2,
    uri_helper<test_sub_factories, 1, TEST_FACTORY4_NAME>
};

class TestDispatcherHandler2 : public DispatcherHandlerBase
{
public:
    void on_payload(const MemoryChunk::readonly_t& payload_part,
                    bool last_chunk) OVERRIDE
    {
        REQUIRE(payload_part[0] == 0x10);
        REQUIRE(payload_part[1] == 0x11);
        REQUIRE(payload_part[2] == 0x12);
        REQUIRE(payload_part.length() == 7);
    }
};

IDispatcherHandler* test_sub_factory1(MemoryChunk chunk)
{
    static TestDispatcherHandler2 handler;

    // To be v1/path1
    //return new (chunk.data()) UriPathDispatcherHandler("path1", handler);
    // TEST/POS to work with our existing test data
    return new (chunk.data()) UriPathDispatcherHandler("POS", handler);
}

dispatcher_handler_factory_fn test_sub_factories[] =
{
    test_sub_factory1
};

TEST_CASE("CoAP dispatcher tests", "[coap-dispatcher]")
{
    SECTION("Test 1")
    {
        MemoryChunk chunk(buffer_16bit_delta, sizeof(buffer_16bit_delta));

        TestDispatcherHandler dispatcherHandler;
        Dispatcher dispatcher;
        //layer3::MemoryChunk<128> chunk;

        dispatcher.head(&dispatcherHandler);
        dispatcher.dispatch(chunk);

    }
    SECTION("Factory")
    {
        MemoryChunk chunk(buffer_plausible, sizeof(buffer_plausible));

        // in-place new holder
        layer3::MemoryChunk<128> dispatcherBuffer;

        FactoryDispatcherHandler fdh(dispatcherBuffer, test_factories, 3);
        Dispatcher dispatcher;

        // doesn't fully test new UriPath handler because TestDispatcherHandler
        // is not stateless (and shouldn't be expected to be) but because of that
        // setting it to "Currently" makes it unable to test its own options properly
        dispatcher.head(&fdh);
        dispatcher.dispatch(chunk);
    }
}<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) <2017> <Thomas Ballenthin>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE linux auth test

#include <boost/test/unit_test.hpp>
#include <crypt.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <string>

#include "authenticate.h"
#include "json/cJSON.h"

static std::string create_temp_copy_of_file(std::string source_filename, std::string filename_apendix)
{
	std::string destination_filename(source_filename);
	destination_filename.append(filename_apendix);

	std::ifstream source(source_filename.c_str(), std::ios::binary);
	std::ofstream dest(destination_filename.c_str(), std::ios::binary);

	BOOST_REQUIRE_MESSAGE(source != NULL, "Can't open source file: " << source_filename);
	BOOST_REQUIRE_MESSAGE(dest != NULL, "Can't open destination file: " << destination_filename);
	dest << source.rdbuf();

	source.close();
	dest.close();

	return destination_filename;
}

struct F {
	F()
	{
		int response = load_passwd_data("input_data/passwd_std.json");
		BOOST_REQUIRE_MESSAGE(response == 0, "Loading password file failed.");
	}

	~F()
	{
		free_passwd_data();
	}
};

BOOST_AUTO_TEST_CASE(check_load_passwd_data_error_paths)
{
	int response = load_passwd_data(NULL);
	BOOST_CHECK_MESSAGE(response == 0, "Expected 0 as return value when calling load_passwd_data(NULL).");

	response = load_passwd_data("*/___/");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when calling realpath with '*/___/'.");

	response = load_passwd_data("some_non_existing_file_641587976.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening non-existing file.");

	response = load_passwd_data("input_data/no_json.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening non JSON file.");

	response = load_passwd_data("input_data/passwd_no_user_data.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening passwd file without user data.");

	response = load_passwd_data("input_data/passwd_fetch_group_no_array.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening passwd file without array as fetch group.");

	response = load_passwd_data("input_data/passwd_set_group_no_array.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening passwd file without array as set group.");

	response = load_passwd_data("input_data/passwd_call_group_no_array.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening passwd file without array as callgroup.");

	response = load_passwd_data("input_data/passwd_no_json_data.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening passwd file without any JSON.");
}

BOOST_FIXTURE_TEST_CASE(check_credentials, F)
{
	char username[] = "john";
	char passwd[] = "doe";
	char passwd_to_null[] = "doe";
	char user_no_passwd[] = "john-no_passwd";
	char user_passwd_no_string[] = "john-pw_no_string";
	char unknown_user[] = "mister_x";

	const cJSON *response1 = credentials_ok(NULL, NULL);
	BOOST_CHECK_MESSAGE(response1 == NULL, "Response should be NULL when no user_name nor passwd is provided.");

	const cJSON *response2 = credentials_ok(username, NULL);
	BOOST_CHECK_MESSAGE(response2 == NULL, "Response should be NULL when no passwd is provided.");

	const cJSON *response3 = credentials_ok(NULL, passwd_to_null);
	BOOST_CHECK_MESSAGE(response3 == NULL, "Response should be NULL when no user_name is provided.");
	BOOST_CHECK_MESSAGE(std::strcmp(passwd_to_null, "\0\0\0"), "The password has not been zeroed. Instead it was:\"" << passwd << "\".");

	const cJSON *response4 = credentials_ok(user_no_passwd, passwd_to_null);
	BOOST_CHECK_MESSAGE(response4 == NULL, "Response should be NULL when no password is given in the user database.");

	const cJSON *response5 = credentials_ok(user_passwd_no_string, passwd_to_null);
	BOOST_CHECK_MESSAGE(response5 == NULL, "Response should be NULL when password in database is not a string.");

	const cJSON *response6 = credentials_ok(unknown_user, passwd_to_null);
	BOOST_CHECK_MESSAGE(response6 == NULL, "Response should be NULL when password in database is not a string.");

	const cJSON *response7 = credentials_ok(username, passwd);
	BOOST_REQUIRE_MESSAGE(response7 != NULL, "User authentication failed even with correct credentials.");
}

BOOST_AUTO_TEST_CASE(check_credentials_no_user_data_loaded)
{
	char username[] = "john";
	char passwd[] = "doe";

	const cJSON *response1 = credentials_ok(username, passwd);
	BOOST_CHECK_MESSAGE(response1 == NULL, "Response should be NULL when no user data is loaded in before.");
}

BOOST_AUTO_TEST_CASE(test_copying)
{
	std::string temporarily_file = create_temp_copy_of_file("input_data/passwd_std.json", "_temp");
}
<commit_msg>linux_auth_file_test: add random stub methods<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) <2017> <Thomas Ballenthin>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE linux auth test

#include <boost/test/unit_test.hpp>
#include <crypt.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <string>

#include "authenticate.h"
#include "json/cJSON.h"

extern "C" {
	int cjet_timer_init(struct cjet_timer *timer, struct eventloop *loop){
		(void) timer;
		(void) loop;
		return 0;
	}

	void cjet_timer_destroy(struct cjet_timer *timer){
		(void) timer;
	}

	void cjet_get_random_bytes(void *bytes, size_t num_bytes)
	{
		BOOST_REQUIRE_MESSAGE(false,"the cjet_get_random_bytes function needs to be implemented, when it is actually used.");
		(void) bytes;
		(void) num_bytes;
	}
}

static std::string create_temp_copy_of_file(std::string source_filename, std::string filename_apendix)
{
	std::string destination_filename(source_filename);
	destination_filename.append(filename_apendix);

	std::ifstream source(source_filename.c_str(), std::ios::binary);
	std::ofstream dest(destination_filename.c_str(), std::ios::binary);

	BOOST_REQUIRE_MESSAGE(source != NULL, "Can't open source file: " << source_filename);
	BOOST_REQUIRE_MESSAGE(dest != NULL, "Can't open destination file: " << destination_filename);
	dest << source.rdbuf();

	source.close();
	dest.close();

	return destination_filename;
}

struct F {
	F()
	{
		int response = load_passwd_data("input_data/passwd_std.json");
		BOOST_REQUIRE_MESSAGE(response == 0, "Loading password file failed.");
	}

	~F()
	{
		free_passwd_data();
	}
};

BOOST_AUTO_TEST_CASE(check_load_passwd_data_error_paths)
{
	int response = load_passwd_data(NULL);
	BOOST_CHECK_MESSAGE(response == 0, "Expected 0 as return value when calling load_passwd_data(NULL).");

	response = load_passwd_data("* /___/"); //TODO - leerzeichen
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when calling realpath with '* /___/'.");

	response = load_passwd_data("some_non_existing_file_641587976.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening non-existing file.");

	response = load_passwd_data("input_data/no_json.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening non JSON file.");

	response = load_passwd_data("input_data/passwd_no_user_data.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening passwd file without user data.");

	response = load_passwd_data("input_data/passwd_fetch_group_no_array.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening passwd file without array as fetch group.");

	response = load_passwd_data("input_data/passwd_set_group_no_array.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening passwd file without array as set group.");

	response = load_passwd_data("input_data/passwd_call_group_no_array.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening passwd file without array as callgroup.");

	response = load_passwd_data("input_data/passwd_no_json_data.json");
	BOOST_CHECK_MESSAGE(response == -1, "Error expected when opening passwd file without any JSON.");
}

BOOST_FIXTURE_TEST_CASE(check_credentials, F)
{
	char username[] = "john";
	char passwd[] = "doe";

	char unknown_user[] = "mister_x";
	char passwd_to_null[] = "doe";

	char user_no_passwd[] = "john-no_passwd";
	char user_passwd_no_string[] = "john-pw_no_string";

	const cJSON *response1 = credentials_ok(NULL, NULL);
	BOOST_CHECK_MESSAGE(response1 == NULL, "Response should be NULL when no user_name nor passwd is provided.");

	const cJSON *response2 = credentials_ok(username, NULL);
	BOOST_CHECK_MESSAGE(response2 == NULL, "Response should be NULL when no passwd is provided.");

	const cJSON *response3 = credentials_ok(NULL, passwd_to_null);
	BOOST_CHECK_MESSAGE(response3 == NULL, "Response should be NULL when no user_name is provided.");
	BOOST_CHECK_MESSAGE(std::strcmp(passwd_to_null, "\0\0\0"), "The password has not been zeroed. Instead it was:\"" << passwd << "\".");

	const cJSON *response4 = credentials_ok(user_no_passwd, passwd_to_null);
	BOOST_CHECK_MESSAGE(response4 == NULL, "Response should be NULL when no password is given in the user database.");

	const cJSON *response5 = credentials_ok(user_passwd_no_string, passwd_to_null);
	BOOST_CHECK_MESSAGE(response5 == NULL, "Response should be NULL when password in database is not a string.");

	const cJSON *response6 = credentials_ok(unknown_user, passwd_to_null);
	BOOST_CHECK_MESSAGE(response6 == NULL, "Response should be NULL when password in database is not a string.");

	const cJSON *response7 = credentials_ok(username, passwd);
	BOOST_REQUIRE_MESSAGE(response7 != NULL, "User authentication failed even with correct credentials.");
}

BOOST_AUTO_TEST_CASE(check_credentials_no_user_data_loaded)
{
	char username[] = "john";
	char passwd[] = "doe";

	const cJSON *response1 = credentials_ok(username, passwd);
	BOOST_CHECK_MESSAGE(response1 == NULL, "Response should be NULL when no user data is loaded in before.");
}

BOOST_AUTO_TEST_CASE(test_copying)
{
	std::string temporarily_file = create_temp_copy_of_file("input_data/passwd_std.json", "_temp");
}

<|endoftext|>


<commit_before>#include <QtGui/QGuiApplication>
#include <QQmlContext>
#include <QStateMachine>
#include <QDebug>
#include <memory>
#include "./window.h"
#include "./scene.h"
#include "./nodes.h"
#include "./label_node.h"
#include "./input/invoke_manager.h"
#include "./input/signal_manager.h"
#include "./input/scxml_importer.h"
#include "./mouse_shape_controller.h"
#include "./labeller_model.h"
#include "./labels_model.h"
#include "./labelling/labels.h"
#include "./picking_controller.h"
#include "./forces_visualizer_node.h"
#include "./test_scene_creator.h"

void onLabelChangedUpdateLabelNodes(std::shared_ptr<Nodes> nodes,
                                    Labels::Action action, const Label &label)
{
  auto labelNodes = nodes->getLabelNodes();
  auto labelNode = std::find_if(labelNodes.begin(), labelNodes.end(),
                                [label](std::shared_ptr<LabelNode> labelNode)
                                {
    return labelNode->label.id == label.id;
  });

  if (labelNode == labelNodes.end())
  {
    nodes->addNode(std::make_shared<LabelNode>(label));
  }
  else if (action == Labels::Action::Delete)
  {
    nodes->removeNode(*labelNode);
  }
  else
  {
    (*labelNode)->label = label;
  }
};

int main(int argc, char **argv)
{
  qputenv("QT_MESSAGE_PATTERN",
          QString("%{time [yyyy'-'MM'-'dd' 'hh':'mm':'ss]} - %{threadid} "
                  "%{if-category}%{category}: %{endif}%{message}").toUtf8());
  if (qgetenv("QT_LOGGING_CONF").size() == 0)
    qputenv("QT_LOGGING_CONF", "../config/logging.ini");

  QGuiApplication application(argc, argv);

  auto invokeManager = std::shared_ptr<InvokeManager>(new InvokeManager());
  auto nodes = std::make_shared<Nodes>();
  auto labels = std::make_shared<Labels>();
  auto labeller = std::make_shared<Forces::Labeller>(labels);
  auto forcesVisualizerNode = std::make_shared<ForcesVisualizerNode>(labeller);
  nodes->addNode(forcesVisualizerNode);

  TestSceneCreator sceneCreator(nodes, labels);
  sceneCreator.create();
  auto scene = std::make_shared<Scene>(invokeManager, nodes, labels, labeller);

  auto unsubscribeLabelChanges = labels->subscribe(
      std::bind(&onLabelChangedUpdateLabelNodes, nodes, std::placeholders::_1,
                std::placeholders::_2));

  Window window(scene);
  window.setResizeMode(QQuickView::SizeRootObjectToView);
  window.rootContext()->setContextProperty("window", &window);
  window.rootContext()->setContextProperty("nodes", nodes.get());

  MouseShapeController mouseShapeController;
  PickingController pickingController(scene);

  LabellerModel labellerModel(labeller);
  labellerModel.connect(&labellerModel, &LabellerModel::isVisibleChanged,
                        [&labellerModel, &nodes, &forcesVisualizerNode]()
                        {
    if (labellerModel.getIsVisible())
      nodes->addNode(forcesVisualizerNode);
    else
      nodes->removeNode(forcesVisualizerNode);
  });
  window.rootContext()->setContextProperty("labeller", &labellerModel);

  LabelsModel labelsModel(labels, pickingController);
  window.rootContext()->setContextProperty("labels", &labelsModel);
  window.setSource(QUrl("qrc:ui.qml"));

  auto signalManager = std::shared_ptr<SignalManager>(new SignalManager());
  ScxmlImporter importer(QUrl::fromLocalFile("config/states.xml"),
                         invokeManager, signalManager);

  invokeManager->addHandler(&window);
  invokeManager->addHandler("mouseShape", &mouseShapeController);
  invokeManager->addHandler("picking", &pickingController);
  signalManager->addSender("KeyboardEventSender", &window);
  signalManager->addSender("labels", &labelsModel);

  auto stateMachine = importer.import();

  // just for printCurrentState slot for debugging
  window.stateMachine = stateMachine;

  stateMachine->start();

  window.show();

  auto resultCode = application.exec();

  unsubscribeLabelChanges();

  return resultCode;
}
<commit_msg>Log application start.<commit_after>#include <QtGui/QGuiApplication>
#include <QQmlContext>
#include <QStateMachine>
#include <QDebug>
#include <memory>
#include "./window.h"
#include "./scene.h"
#include "./nodes.h"
#include "./label_node.h"
#include "./input/invoke_manager.h"
#include "./input/signal_manager.h"
#include "./input/scxml_importer.h"
#include "./mouse_shape_controller.h"
#include "./labeller_model.h"
#include "./labels_model.h"
#include "./labelling/labels.h"
#include "./picking_controller.h"
#include "./forces_visualizer_node.h"
#include "./test_scene_creator.h"

void onLabelChangedUpdateLabelNodes(std::shared_ptr<Nodes> nodes,
                                    Labels::Action action, const Label &label)
{
  auto labelNodes = nodes->getLabelNodes();
  auto labelNode = std::find_if(labelNodes.begin(), labelNodes.end(),
                                [label](std::shared_ptr<LabelNode> labelNode)
                                {
    return labelNode->label.id == label.id;
  });

  if (labelNode == labelNodes.end())
  {
    nodes->addNode(std::make_shared<LabelNode>(label));
  }
  else if (action == Labels::Action::Delete)
  {
    nodes->removeNode(*labelNode);
  }
  else
  {
    (*labelNode)->label = label;
  }
};

int main(int argc, char **argv)
{
  qputenv("QT_MESSAGE_PATTERN",
          QString("%{time [yyyy'-'MM'-'dd' 'hh':'mm':'ss]} - %{threadid} "
                  "%{if-category}%{category}: %{endif}%{message}").toUtf8());
  if (qgetenv("QT_LOGGING_CONF").size() == 0)
    qputenv("QT_LOGGING_CONF", "../config/logging.ini");

  QGuiApplication application(argc, argv);

  qDebug() << "Application start";

  auto invokeManager = std::shared_ptr<InvokeManager>(new InvokeManager());
  auto nodes = std::make_shared<Nodes>();
  auto labels = std::make_shared<Labels>();
  auto labeller = std::make_shared<Forces::Labeller>(labels);
  auto forcesVisualizerNode = std::make_shared<ForcesVisualizerNode>(labeller);
  nodes->addNode(forcesVisualizerNode);

  TestSceneCreator sceneCreator(nodes, labels);
  sceneCreator.create();
  auto scene = std::make_shared<Scene>(invokeManager, nodes, labels, labeller);

  auto unsubscribeLabelChanges = labels->subscribe(
      std::bind(&onLabelChangedUpdateLabelNodes, nodes, std::placeholders::_1,
                std::placeholders::_2));

  Window window(scene);
  window.setResizeMode(QQuickView::SizeRootObjectToView);
  window.rootContext()->setContextProperty("window", &window);
  window.rootContext()->setContextProperty("nodes", nodes.get());

  MouseShapeController mouseShapeController;
  PickingController pickingController(scene);

  LabellerModel labellerModel(labeller);
  labellerModel.connect(&labellerModel, &LabellerModel::isVisibleChanged,
                        [&labellerModel, &nodes, &forcesVisualizerNode]()
                        {
    if (labellerModel.getIsVisible())
      nodes->addNode(forcesVisualizerNode);
    else
      nodes->removeNode(forcesVisualizerNode);
  });
  window.rootContext()->setContextProperty("labeller", &labellerModel);

  LabelsModel labelsModel(labels, pickingController);
  window.rootContext()->setContextProperty("labels", &labelsModel);
  window.setSource(QUrl("qrc:ui.qml"));

  auto signalManager = std::shared_ptr<SignalManager>(new SignalManager());
  ScxmlImporter importer(QUrl::fromLocalFile("config/states.xml"),
                         invokeManager, signalManager);

  invokeManager->addHandler(&window);
  invokeManager->addHandler("mouseShape", &mouseShapeController);
  invokeManager->addHandler("picking", &pickingController);
  signalManager->addSender("KeyboardEventSender", &window);
  signalManager->addSender("labels", &labelsModel);

  auto stateMachine = importer.import();

  // just for printCurrentState slot for debugging
  window.stateMachine = stateMachine;

  stateMachine->start();

  window.show();

  auto resultCode = application.exec();

  unsubscribeLabelChanges();

  return resultCode;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "traits_lite.hpp"   //forward declaration of the traits

namespace etl {

template<typename Expr, std::size_t A>
struct aligned_allocator {
    template<typename T>
    static T* allocate(std::size_t size){
        auto required_bytes = sizeof(T) * size;
        auto offset = (A - 1) + sizeof(uintptr_t);
        auto orig = malloc(required_bytes + offset);

        if(!orig){
            return nullptr;
        }

        auto aligned = reinterpret_cast<void**>((reinterpret_cast<size_t>(orig) + offset) & ~(A - 1));
        aligned[-1] = orig;
        return reinterpret_cast<T*>(aligned);
    }

    template<typename T>
    static void release(T* ptr){
        free((reinterpret_cast<void**>(ptr))[-1]);
    }
};

template<typename T>
auto allocate(std::size_t size){
    return std::make_unique<T[]>(size);
}

template<typename T>
T* aligned_allocate(std::size_t size){
    return aligned_allocator<void, 32>::allocate<T>(size);
}

template<typename T>
void aligned_release(T* ptr){
    return aligned_allocator<void, 32>::release<T>(ptr);
}

} //end of namespace etl
<commit_msg>Fix includes<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <memory>

#include "traits_lite.hpp"   //forward declaration of the traits

namespace etl {

template<typename Expr, std::size_t A>
struct aligned_allocator {
    template<typename T>
    static T* allocate(std::size_t size){
        auto required_bytes = sizeof(T) * size;
        auto offset = (A - 1) + sizeof(uintptr_t);
        auto orig = malloc(required_bytes + offset);

        if(!orig){
            return nullptr;
        }

        auto aligned = reinterpret_cast<void**>((reinterpret_cast<size_t>(orig) + offset) & ~(A - 1));
        aligned[-1] = orig;
        return reinterpret_cast<T*>(aligned);
    }

    template<typename T>
    static void release(T* ptr){
        free((reinterpret_cast<void**>(ptr))[-1]);
    }
};

template<typename T>
auto allocate(std::size_t size){
    return std::make_unique<T[]>(size);
}

template<typename T>
T* aligned_allocate(std::size_t size){
    return aligned_allocator<void, 32>::allocate<T>(size);
}

template<typename T>
void aligned_release(T* ptr){
    return aligned_allocator<void, 32>::release<T>(ptr);
}

} //end of namespace etl
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2014 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/config_error.hpp>

// boost
#include <boost/spirit/include/qi.hpp>
#include <boost/bind.hpp>

// stl
#include <algorithm>
#include <cctype>
#include <sstream>

namespace mapnik
{

font_feature_settings::font_feature_settings(std::string const& features)
    : features_()
{
    from_string(features);
}

font_feature_settings::font_feature_settings()
    : features_() {}

void font_feature_settings::from_string(std::string const& features)
{
    features_.clear();

    if (std::all_of(features.begin(), features.end(), isspace)) return;

    namespace qi = boost::spirit::qi;
    qi::char_type char_;
    qi::as_string_type as_string;

    // Call correct overload.
    void (font_feature_settings::*append)(std::string const&) = &font_feature_settings::append;

    if (!qi::parse(features.begin(), features.end(), as_string[+(char_ - ',')][boost::bind(append, this, ::_1)] % ','))
    {
        throw config_error("failed to parse font-feature-settings: '" + features + "'");
    }
}

std::string font_feature_settings::to_string() const
{
    std::ostringstream output;
    constexpr size_t buffsize = 128;
    char buff[buffsize];
    bool first = true;

    for (auto feature : features_)
    {
        if (!first)
        {
            output << ", ";
            first = false;
        }
        hb_feature_to_string(&feature, buff, buffsize);
        output << buff;
    }

    return output.str();
}

void font_feature_settings::append(std::string const& feature)
{
    features_.emplace_back();
    feature_iterator current_feature = features_.end() - 1;

    if (!hb_feature_from_string(feature.c_str(), feature.length(), &*current_feature))
    {
        features_.erase(current_feature);
        throw config_error("failed to parse font-feature-settings: '" + feature + "'");
    }
}

}

<commit_msg>use c++11 features over boost when available<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2014 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/config_error.hpp>

// boost
#include <boost/spirit/include/qi.hpp>

// stl
#include <algorithm>
#include <cctype>
#include <sstream>
#include <functional>

namespace mapnik
{

font_feature_settings::font_feature_settings(std::string const& features)
    : features_()
{
    from_string(features);
}

font_feature_settings::font_feature_settings()
    : features_() {}

void font_feature_settings::from_string(std::string const& features)
{
    features_.clear();

    if (std::all_of(features.begin(), features.end(), isspace)) return;

    namespace qi = boost::spirit::qi;
    qi::char_type char_;
    qi::as_string_type as_string;

    // Call correct overload.
    using std::placeholders::_1;
    void (font_feature_settings::*append)(std::string const&) = &font_feature_settings::append;

    if (!qi::parse(features.begin(), features.end(), as_string[+(char_ - ',')][std::bind(append, this, _1)] % ','))
    {
        throw config_error("failed to parse font-feature-settings: '" + features + "'");
    }
}

std::string font_feature_settings::to_string() const
{
    std::ostringstream output;
    constexpr size_t buffsize = 128;
    char buff[buffsize];
    bool first = true;

    for (auto feature : features_)
    {
        if (!first)
        {
            output << ", ";
            first = false;
        }
        hb_feature_to_string(&feature, buff, buffsize);
        output << buff;
    }

    return output.str();
}

void font_feature_settings::append(std::string const& feature)
{
    features_.emplace_back();
    feature_iterator current_feature = features_.end() - 1;

    if (!hb_feature_from_string(feature.c_str(), feature.length(), &*current_feature))
    {
        features_.erase(current_feature);
        throw config_error("failed to parse font-feature-settings: '" + feature + "'");
    }
}

}
<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief unit test class

	Copyright (C) 2008 Cybozu Labs, Inc., all rights reserved.
*/

#include <stdio.h>
#include <string.h>
#include <string>
#include <list>
#include <iostream>
#include <utility>
#if defined(_MSC_VER) && (MSC_VER <= 1500)
	#include <cybozu/inttype.hpp>
#else
	#include <stdint.h>
#endif

namespace cybozu { namespace test {

class AutoRun {
	typedef void (*Func)();
	typedef std::list<std::pair<const char*, Func> > UnitTestList;
public:
	AutoRun()
		: init_(0)
		, term_(0)
		, okCount_(0)
		, ngCount_(0)
		, exceptionCount_(0)
	{
	}
	void setup(Func init, Func term)
	{
		init_ = init;
		term_ = term;
	}
	void append(const char *name, Func func)
	{
		list_.push_back(std::make_pair(name, func));
	}
	void set(bool isOK)
	{
		if (isOK) {
			okCount_++;
		} else {
			ngCount_++;
		}
	}
	std::string getBaseName(const std::string& name) const
	{
#ifdef _WIN32
		const char sep = '\\';
#else
		const char sep = '/';
#endif
		size_t pos = name.find_last_of(sep);
		std::string ret = name.substr(pos + 1);
		pos = ret.find('.');
		return ret.substr(0, pos);
	}
	int run(int, char *argv[])
	{
		std::string msg;
		try {
			if (init_) init_();
			for (UnitTestList::const_iterator i = list_.begin(), ie = list_.end(); i != ie; ++i) {
				std::cout << "ctest:module=" << i->first << std::endl;
				try {
					(i->second)();
				} catch (std::exception& e) {
					exceptionCount_++;
					std::cout << "ctest:  " << i->first << " is stopped by exception " << e.what() << std::endl;
				} catch (...) {
					exceptionCount_++;
					std::cout << "ctest:  " << i->first << " is stopped by unknown exception" << std::endl;
				}
			}
			if (term_) term_();
		} catch (std::exception& e) {
			msg = std::string("ctest:err:") + e.what();
		} catch (...) {
			msg = "ctest:err: catch unknown exception";
		}
		fflush(stdout);
		if (msg.empty()) {
			std::cout << "ctest:name=" << getBaseName(*argv)
					  << ", module=" << list_.size()
					  << ", total=" << (okCount_ + ngCount_ + exceptionCount_)
					  << ", ok=" << okCount_
					  << ", ng=" << ngCount_
					  << ", exception=" << exceptionCount_ << std::endl;
			return 0;
		} else {
			std::cout << msg << std::endl;
			return 1;
		}
	}
	static inline AutoRun& getInstance()
	{
		static AutoRun instance;
		return instance;
	}
private:
	Func init_;
	Func term_;
	int okCount_;
	int ngCount_;
	int exceptionCount_;
	UnitTestList list_;
};

static AutoRun& autoRun = AutoRun::getInstance();

inline void test(bool ret, const std::string& msg, const std::string& param, const char *file, int line)
{
	autoRun.set(ret);
	if (!ret) {
		printf("%s(%d):ctest:%s(%s);\n", file, line, msg.c_str(), param.c_str());
	}
}

template<typename T, typename U>
bool isEqual(const T& lhs, const U& rhs)
{
	return lhs == rhs;
}

// avoid warning of comparision of integers of different signs
inline bool isEqual(size_t lhs, int rhs)
{
	return lhs == size_t(rhs);
}
inline bool isEqual(int lhs, size_t rhs)
{
	return size_t(lhs) == rhs;
}
inline bool isEqual(const char *lhs, const char *rhs)
{
	return strcmp(lhs, rhs) == 0;
}
inline bool isEqual(char *lhs, const char *rhs)
{
	return strcmp(lhs, rhs) == 0;
}
inline bool isEqual(const char *lhs, char *rhs)
{
	return strcmp(lhs, rhs) == 0;
}
inline bool isEqual(char *lhs, char *rhs)
{
	return strcmp(lhs, rhs) == 0;
}
// avoid to compare float directly
inline bool isEqual(float lhs, float rhs)
{
	union fi {
		float f;
		uint32_t i;
	} lfi, rfi;
	lfi.f = lhs;
	rfi.f = rhs;
	return lfi.i == rfi.i;
}
// avoid to compare double directly
inline bool isEqual(double lhs, double rhs)
{
	union di {
		double d;
		uint64_t i;
	} ldi, rdi;
	ldi.d = lhs;
	rdi.d = rhs;
	return ldi.i == rdi.i;
}

} } // cybozu::test

#ifndef CYBOZU_TEST_DISABLE_AUTO_RUN
int main(int argc, char *argv[])
{
	return cybozu::test::autoRun.run(argc, argv);
}
#endif

/**
	alert if !x
	@param x [in]
*/
#define CYBOZU_TEST_ASSERT(x) cybozu::test::test(!!(x), "CYBOZU_TEST_ASSERT", #x, __FILE__, __LINE__)

/**
	alert if x != y
	@param x [in]
	@param y [in]
*/
#define CYBOZU_TEST_EQUAL(x, y) { \
	bool eq = cybozu::test::isEqual(x, y); \
	cybozu::test::test(eq, "CYBOZU_TEST_EQUAL", #x ", " #y, __FILE__, __LINE__); \
	if (!eq) { \
		std::cout << "ctest:  lhs=" << (x) << std::endl; \
		std::cout << "ctest:  rhs=" << (y) << std::endl; \
	} \
}
/**
	alert if fabs(x, y) >= eps
	@param x [in]
	@param y [in]
*/
#define CYBOZU_TEST_NEAR(x, y, eps) { \
	bool isNear = fabs((x) - (y)) < eps; \
	cybozu::test::test(isNear, "CYBOZU_TEST_NEAR", #x ", " #y, __FILE__, __LINE__); \
	if (!isNear) { \
		std::cout << "ctest:  lhs=" << (x) << std::endl; \
		std::cout << "ctest:  rhs=" << (y) << std::endl; \
	} \
}

#define CYBOZU_TEST_EQUAL_POINTER(x, y) { \
	bool eq = x == y; \
	cybozu::test::test(eq, "CYBOZU_TEST_EQUAL_POINTER", #x ", " #y, __FILE__, __LINE__); \
	if (!eq) { \
		std::cout << "ctest:  lhs=" << static_cast<const void*>(x) << std::endl; \
		std::cout << "ctest:  rhs=" << static_cast<const void*>(y) << std::endl; \
	} \
}
/**
	alert if x[] != y[]
	@param x [in]
	@param y [in]
	@param n [in]
*/
#define CYBOZU_TEST_EQUAL_ARRAY(x, y, n) { \
	for (size_t i = 0, ie = (size_t)(n); i < ie; i++) { \
		bool eq = cybozu::test::isEqual((x)[i], (y)[i]); \
		cybozu::test::test(eq, "CYBOZU_TEST_EQUAL_ARRAY", #x ", " #y ", " #n, __FILE__, __LINE__); \
		if (!eq) { \
			std::cout << "ctest:  i=" << i << std::endl; \
			std::cout << "ctest:  lhs=" << (x)[i] << std::endl; \
			std::cout << "ctest:  rhs=" << (y)[i] << std::endl; \
		} \
	} \
}

/**
	always alert
	@param msg [in]
*/
#define CYBOZU_TEST_FAIL(msg) cybozu::test::test(false, "CYBOZU_TEST_FAIL", msg, __FILE__, __LINE__)

/**
	verify message in exception
*/
#define CYBOZU_TEST_EXCEPTION_MESSAGE(statement, Exception, msg) \
{ \
	int ret = 0; \
	std::string errMsg; \
	try { \
		statement; \
		ret = 1; \
	} catch (const Exception& e) { \
		errMsg = e.what(); \
		if (errMsg.find(msg) == std::string::npos) { \
			ret = 2; \
		} \
	} catch (...) { \
		ret = 3; \
	} \
	if (ret) { \
		cybozu::test::test(false, "CYBOZU_TEST_EXCEPTION_MESSAGE", #statement ", " #Exception ", " #msg, __FILE__, __LINE__); \
		if (ret == 1) { \
			std::cout << "ctest:  no exception" << std::endl; \
		} else if (ret == 2) { \
			std::cout << "ctest:  bad exception msg:" << errMsg << std::endl; \
		} else { \
			std::cout << "ctest:  unexpected exception" << std::endl; \
		} \
	} else { \
		cybozu::test::autoRun.set(true); \
	} \
}

#define CYBOZU_TEST_EXCEPTION(statement, Exception) \
{ \
	int ret = 0; \
	try { \
		statement; \
		ret = 1; \
	} catch (const Exception&) { \
	} catch (...) { \
		ret = 2; \
	} \
	if (ret) { \
		cybozu::test::test(false, "CYBOZU_TEST_EXCEPTION", #statement ", " #Exception, __FILE__, __LINE__); \
		if (ret == 1) { \
			std::cout << "ctest:  no exception" << std::endl; \
		} else { \
			std::cout << "ctest:  unexpected exception" << std::endl; \
		} \
	} else { \
		cybozu::test::autoRun.set(true); \
	} \
}

/**
	verify statement does not throw
*/
#define CYBOZU_TEST_NO_EXCEPTION(statement) \
try { \
	statement; \
	cybozu::test::autoRun.set(true); \
} catch (...) { \
	cybozu::test::test(false, "CYBOZU_TEST_NO_EXCEPTION", #statement, __FILE__, __LINE__); \
}

/**
	append auto unit test
	@param name [in] module name
*/
#define CYBOZU_TEST_AUTO(name) \
void cybozu_test_ ## name(); \
struct cybozu_test_local_ ## name { \
	cybozu_test_local_ ## name() \
	{ \
		cybozu::test::autoRun.append(#name, cybozu_test_ ## name); \
	} \
} cybozu_test_local_instance_ ## name; \
void cybozu_test_ ## name()

/**
	append auto unit test with fixture
	@param name [in] module name
*/
#define CYBOZU_TEST_AUTO_WITH_FIXTURE(name, Fixture) \
void cybozu_test_ ## name(); \
void cybozu_test_real_ ## name() \
{ \
	Fixture f; \
	cybozu_test_ ## name(); \
} \
struct cybozu_test_local_ ## name { \
	cybozu_test_local_ ## name() \
	{ \
		cybozu::test::autoRun.append(#name, cybozu_test_real_ ## name); \
	} \
} cybozu_test_local_instance_ ## name; \
void cybozu_test_ ## name()

/**
	setup fixture
	@param Fixture [in] class name of fixture
	@note cstr of Fixture is called before test and dstr of Fixture is called after test
*/
#define CYBOZU_TEST_SETUP_FIXTURE(Fixture) \
Fixture *cybozu_test_local_fixture; \
void cybozu_test_local_init() \
{ \
	cybozu_test_local_fixture = new Fixture(); \
} \
void cybozu_test_local_term() \
{ \
	delete cybozu_test_local_fixture; \
} \
struct cybozu_test_local_fixture_setup_ { \
	cybozu_test_local_fixture_setup_() \
	{ \
		cybozu::test::autoRun.setup(cybozu_test_local_init, cybozu_test_local_term); \
	} \
} cybozu_test_local_fixture_setup_instance_;
<commit_msg>avoid conflict of var<commit_after>#pragma once
/**
	@file
	@brief unit test class

	Copyright (C) 2008 Cybozu Labs, Inc., all rights reserved.
*/

#include <stdio.h>
#include <string.h>
#include <string>
#include <list>
#include <iostream>
#include <utility>
#if defined(_MSC_VER) && (MSC_VER <= 1500)
	#include <cybozu/inttype.hpp>
#else
	#include <stdint.h>
#endif

namespace cybozu { namespace test {

class AutoRun {
	typedef void (*Func)();
	typedef std::list<std::pair<const char*, Func> > UnitTestList;
public:
	AutoRun()
		: init_(0)
		, term_(0)
		, okCount_(0)
		, ngCount_(0)
		, exceptionCount_(0)
	{
	}
	void setup(Func init, Func term)
	{
		init_ = init;
		term_ = term;
	}
	void append(const char *name, Func func)
	{
		list_.push_back(std::make_pair(name, func));
	}
	void set(bool isOK)
	{
		if (isOK) {
			okCount_++;
		} else {
			ngCount_++;
		}
	}
	std::string getBaseName(const std::string& name) const
	{
#ifdef _WIN32
		const char sep = '\\';
#else
		const char sep = '/';
#endif
		size_t pos = name.find_last_of(sep);
		std::string ret = name.substr(pos + 1);
		pos = ret.find('.');
		return ret.substr(0, pos);
	}
	int run(int, char *argv[])
	{
		std::string msg;
		try {
			if (init_) init_();
			for (UnitTestList::const_iterator i = list_.begin(), ie = list_.end(); i != ie; ++i) {
				std::cout << "ctest:module=" << i->first << std::endl;
				try {
					(i->second)();
				} catch (std::exception& e) {
					exceptionCount_++;
					std::cout << "ctest:  " << i->first << " is stopped by exception " << e.what() << std::endl;
				} catch (...) {
					exceptionCount_++;
					std::cout << "ctest:  " << i->first << " is stopped by unknown exception" << std::endl;
				}
			}
			if (term_) term_();
		} catch (std::exception& e) {
			msg = std::string("ctest:err:") + e.what();
		} catch (...) {
			msg = "ctest:err: catch unknown exception";
		}
		fflush(stdout);
		if (msg.empty()) {
			std::cout << "ctest:name=" << getBaseName(*argv)
					  << ", module=" << list_.size()
					  << ", total=" << (okCount_ + ngCount_ + exceptionCount_)
					  << ", ok=" << okCount_
					  << ", ng=" << ngCount_
					  << ", exception=" << exceptionCount_ << std::endl;
			return 0;
		} else {
			std::cout << msg << std::endl;
			return 1;
		}
	}
	static inline AutoRun& getInstance()
	{
		static AutoRun instance;
		return instance;
	}
private:
	Func init_;
	Func term_;
	int okCount_;
	int ngCount_;
	int exceptionCount_;
	UnitTestList list_;
};

static AutoRun& autoRun = AutoRun::getInstance();

inline void test(bool ret, const std::string& msg, const std::string& param, const char *file, int line)
{
	autoRun.set(ret);
	if (!ret) {
		printf("%s(%d):ctest:%s(%s);\n", file, line, msg.c_str(), param.c_str());
	}
}

template<typename T, typename U>
bool isEqual(const T& lhs, const U& rhs)
{
	return lhs == rhs;
}

// avoid warning of comparision of integers of different signs
inline bool isEqual(size_t lhs, int rhs)
{
	return lhs == size_t(rhs);
}
inline bool isEqual(int lhs, size_t rhs)
{
	return size_t(lhs) == rhs;
}
inline bool isEqual(const char *lhs, const char *rhs)
{
	return strcmp(lhs, rhs) == 0;
}
inline bool isEqual(char *lhs, const char *rhs)
{
	return strcmp(lhs, rhs) == 0;
}
inline bool isEqual(const char *lhs, char *rhs)
{
	return strcmp(lhs, rhs) == 0;
}
inline bool isEqual(char *lhs, char *rhs)
{
	return strcmp(lhs, rhs) == 0;
}
// avoid to compare float directly
inline bool isEqual(float lhs, float rhs)
{
	union fi {
		float f;
		uint32_t i;
	} lfi, rfi;
	lfi.f = lhs;
	rfi.f = rhs;
	return lfi.i == rfi.i;
}
// avoid to compare double directly
inline bool isEqual(double lhs, double rhs)
{
	union di {
		double d;
		uint64_t i;
	} ldi, rdi;
	ldi.d = lhs;
	rdi.d = rhs;
	return ldi.i == rdi.i;
}

} } // cybozu::test

#ifndef CYBOZU_TEST_DISABLE_AUTO_RUN
int main(int argc, char *argv[])
{
	return cybozu::test::autoRun.run(argc, argv);
}
#endif

/**
	alert if !x
	@param x [in]
*/
#define CYBOZU_TEST_ASSERT(x) cybozu::test::test(!!(x), "CYBOZU_TEST_ASSERT", #x, __FILE__, __LINE__)

/**
	alert if x != y
	@param x [in]
	@param y [in]
*/
#define CYBOZU_TEST_EQUAL(x, y) { \
	bool _cybozu_eq = cybozu::test::isEqual(x, y); \
	cybozu::test::test(_cybozu_eq, "CYBOZU_TEST_EQUAL", #x ", " #y, __FILE__, __LINE__); \
	if (!_cybozu_eq) { \
		std::cout << "ctest:  lhs=" << (x) << std::endl; \
		std::cout << "ctest:  rhs=" << (y) << std::endl; \
	} \
}
/**
	alert if fabs(x, y) >= eps
	@param x [in]
	@param y [in]
*/
#define CYBOZU_TEST_NEAR(x, y, eps) { \
	bool _cybozu_isNear = fabs((x) - (y)) < eps; \
	cybozu::test::test(_cybozu_isNear, "CYBOZU_TEST_NEAR", #x ", " #y, __FILE__, __LINE__); \
	if (!_cybozu_isNear) { \
		std::cout << "ctest:  lhs=" << (x) << std::endl; \
		std::cout << "ctest:  rhs=" << (y) << std::endl; \
	} \
}

#define CYBOZU_TEST_EQUAL_POINTER(x, y) { \
	bool _cybozu_eq = x == y; \
	cybozu::test::test(_cybozu_eq, "CYBOZU_TEST_EQUAL_POINTER", #x ", " #y, __FILE__, __LINE__); \
	if (!_cybozu_eq) { \
		std::cout << "ctest:  lhs=" << static_cast<const void*>(x) << std::endl; \
		std::cout << "ctest:  rhs=" << static_cast<const void*>(y) << std::endl; \
	} \
}
/**
	alert if x[] != y[]
	@param x [in]
	@param y [in]
	@param n [in]
*/
#define CYBOZU_TEST_EQUAL_ARRAY(x, y, n) { \
	for (size_t _cybozu_test_i = 0, _cybozu_ie = (size_t)(n); _cybozu_test_i < _cybozu_ie; _cybozu_test_i++) { \
		bool _cybozu_eq = cybozu::test::isEqual((x)[_cybozu_test_i], (y)[_cybozu_test_i]); \
		cybozu::test::test(_cybozu_eq, "CYBOZU_TEST_EQUAL_ARRAY", #x ", " #y ", " #n, __FILE__, __LINE__); \
		if (!_cybozu_eq) { \
			std::cout << "ctest:  i=" << _cybozu_test_i << std::endl; \
			std::cout << "ctest:  lhs=" << (x)[_cybozu_test_i] << std::endl; \
			std::cout << "ctest:  rhs=" << (y)[_cybozu_test_i] << std::endl; \
		} \
	} \
}

/**
	always alert
	@param msg [in]
*/
#define CYBOZU_TEST_FAIL(msg) cybozu::test::test(false, "CYBOZU_TEST_FAIL", msg, __FILE__, __LINE__)

/**
	verify message in exception
*/
#define CYBOZU_TEST_EXCEPTION_MESSAGE(statement, Exception, msg) \
{ \
	int _cybozu_ret = 0; \
	std::string _cybozu_errMsg; \
	try { \
		statement; \
		_cybozu_ret = 1; \
	} catch (const Exception& _cybozu_e) { \
		_cybozu_errMsg = _cybozu_e.what(); \
		if (_cybozu_errMsg.find(msg) == std::string::npos) { \
			_cybozu_ret = 2; \
		} \
	} catch (...) { \
		_cybozu_ret = 3; \
	} \
	if (_cybozu_ret) { \
		cybozu::test::test(false, "CYBOZU_TEST_EXCEPTION_MESSAGE", #statement ", " #Exception ", " #msg, __FILE__, __LINE__); \
		if (_cybozu_ret == 1) { \
			std::cout << "ctest:  no exception" << std::endl; \
		} else if (_cybozu_ret == 2) { \
			std::cout << "ctest:  bad exception msg:" << _cybozu_errMsg << std::endl; \
		} else { \
			std::cout << "ctest:  unexpected exception" << std::endl; \
		} \
	} else { \
		cybozu::test::autoRun.set(true); \
	} \
}

#define CYBOZU_TEST_EXCEPTION(statement, Exception) \
{ \
	int _cybozu_ret = 0; \
	try { \
		statement; \
		_cybozu_ret = 1; \
	} catch (const Exception&) { \
	} catch (...) { \
		_cybozu_ret = 2; \
	} \
	if (_cybozu_ret) { \
		cybozu::test::test(false, "CYBOZU_TEST_EXCEPTION", #statement ", " #Exception, __FILE__, __LINE__); \
		if (_cybozu_ret == 1) { \
			std::cout << "ctest:  no exception" << std::endl; \
		} else { \
			std::cout << "ctest:  unexpected exception" << std::endl; \
		} \
	} else { \
		cybozu::test::autoRun.set(true); \
	} \
}

/**
	verify statement does not throw
*/
#define CYBOZU_TEST_NO_EXCEPTION(statement) \
try { \
	statement; \
	cybozu::test::autoRun.set(true); \
} catch (...) { \
	cybozu::test::test(false, "CYBOZU_TEST_NO_EXCEPTION", #statement, __FILE__, __LINE__); \
}

/**
	append auto unit test
	@param name [in] module name
*/
#define CYBOZU_TEST_AUTO(name) \
void cybozu_test_ ## name(); \
struct cybozu_test_local_ ## name { \
	cybozu_test_local_ ## name() \
	{ \
		cybozu::test::autoRun.append(#name, cybozu_test_ ## name); \
	} \
} cybozu_test_local_instance_ ## name; \
void cybozu_test_ ## name()

/**
	append auto unit test with fixture
	@param name [in] module name
*/
#define CYBOZU_TEST_AUTO_WITH_FIXTURE(name, Fixture) \
void cybozu_test_ ## name(); \
void cybozu_test_real_ ## name() \
{ \
	Fixture f; \
	cybozu_test_ ## name(); \
} \
struct cybozu_test_local_ ## name { \
	cybozu_test_local_ ## name() \
	{ \
		cybozu::test::autoRun.append(#name, cybozu_test_real_ ## name); \
	} \
} cybozu_test_local_instance_ ## name; \
void cybozu_test_ ## name()

/**
	setup fixture
	@param Fixture [in] class name of fixture
	@note cstr of Fixture is called before test and dstr of Fixture is called after test
*/
#define CYBOZU_TEST_SETUP_FIXTURE(Fixture) \
Fixture *cybozu_test_local_fixture; \
void cybozu_test_local_init() \
{ \
	cybozu_test_local_fixture = new Fixture(); \
} \
void cybozu_test_local_term() \
{ \
	delete cybozu_test_local_fixture; \
} \
struct cybozu_test_local_fixture_setup_ { \
	cybozu_test_local_fixture_setup_() \
	{ \
		cybozu::test::autoRun.setup(cybozu_test_local_init, cybozu_test_local_term); \
	} \
} cybozu_test_local_fixture_setup_instance_;
<|endoftext|>