<commit_before>/*
 * File:   AlarmClockTest.cpp
 * Author: Craig Cogdill
 * Created: October 15, 2015 10:45am
 * Modifier: Amanda Carbonari
 * Modified Date: January 5, 2015 3:45pm
 */

#include "AlarmClockTest.h"
#include "AlarmClock.h"
#include "StopWatch.h"
#include <chrono>
#include <iostream>
#include <thread>

std::atomic<unsigned int> AlarmClockTest::mFakeSleepUs(0);

namespace {
   typedef std::chrono::microseconds microseconds;
   typedef std::chrono::milliseconds milliseconds;
   typedef std::chrono::seconds seconds;

   unsigned int kFakeSleepLeeway = 100;

   template<typename T>
   void WaitForAlarmClockToExpire(AlarmClock<T>& alerter) {
      while (!alerter.Expired());
   }

   template<typename Duration>
   unsigned int ConvertToMicroSeconds(Duration t) {
      return std::chrono::duration_cast<microseconds>(t).count();
   }

   template<typename Duration>
   unsigned int ConvertToMilliSeconds(Duration t) {
      return std::chrono::duration_cast<milliseconds>(t).count();
   }

   unsigned int FakeSleep(unsigned int usToSleep) {
      AlarmClockTest::mFakeSleepUs.store(usToSleep);
      std::this_thread::sleep_for(microseconds(100));
      return 0;
   }
}

TEST_F(AlarmClockTest, GetUsSleepTimeInUs) {
   int us = 123456;
   AlarmClock<microseconds> alerter(us);
   EXPECT_EQ(us, alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, GetUsSleepTimeInMs) {
   int us = 123456;
   AlarmClock<microseconds> alerter(us);
   EXPECT_EQ(ConvertToMilliSeconds(microseconds(us)), alerter.SleepTimeMs());
}

TEST_F(AlarmClockTest, GetMsSleepTimeInMs) {
   int ms = 123456;
   AlarmClock<milliseconds> alerter(ms);
   EXPECT_EQ(ms, alerter.SleepTimeMs());
}

TEST_F(AlarmClockTest, GetMsSleepTimeInUs) {
   int ms = 123456;
   AlarmClock<milliseconds> alerter(ms);
   EXPECT_EQ(ConvertToMicroSeconds(milliseconds(ms)), alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, GetSecSleepTimeInUs) {
   int sec = 1;
   AlarmClock<seconds> alerter(sec);
   EXPECT_EQ(ConvertToMicroSeconds(seconds(sec)), alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, GetSecSleepTimeInMs) {
   int sec = 1;
   AlarmClock<seconds> alerter(sec);
   EXPECT_EQ(ConvertToMilliSeconds(seconds(sec)), alerter.SleepTimeMs());
}

TEST_F(AlarmClockTest, microsecondsLessThan500ms) {
   int us = 900;
   AlarmClock<microseconds> alerter(us, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, us-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, us);
}

TEST_F(AlarmClockTest, microsecondsGreaterThan500ms) {
   int us = 600000;
   AlarmClock<microseconds> alerter(us, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, us-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, us);
}

TEST_F(AlarmClockTest, weirdNumberOfMicroseconds) {
   int us = 724509;
   StopWatch sw;
   AlarmClock<microseconds> alerter(us, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, us-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, us);
}

TEST_F(AlarmClockTest, millisecondsLessThan500) {
   unsigned int ms = 100;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs()-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, oneSecondInMilliseconds) {
   unsigned int ms = 1000;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs()-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, millisecondsNotDivisibleBy500) {
   unsigned int ms = 1000;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs()-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, secondsSimple) {
   unsigned int sec = 1;
   AlarmClock<seconds> alerter(sec, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs()-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs());
}

// Not working, not sure what it's supposed to be testing?
TEST_F(AlarmClockTest, LongTimeout_ImmediatelyDestructed) {
   unsigned int sec = 1000;
   StopWatch sw;
   // cout << "TEST: Creating pointer" << endl;
   std::unique_ptr<AlarmClock<seconds>> acPtr(new AlarmClock<seconds>(sec, FakeSleep));
   // cout << "TEST: expecting false for expired" << endl;
   EXPECT_FALSE(acPtr->Expired());
   this_thread::sleep_for(microseconds(10));
   // cout << "TEST: resetting pointer" << endl;
   acPtr.reset();
   // cout << "TEST: expecting true for elapsed seconds" << endl;
   EXPECT_TRUE(sw.ElapsedSec() < 2);
   // cout << "TEST: calling destructor" << endl;
}

TEST_F(AlarmClockTest, milliseconds_ResetAfterExpired) {
   // First run
   int ms = 750;
   // cout << "TEST: creating alarm clock" << endl;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   // cout << "TEST: expecting false for expired" << endl;
   EXPECT_FALSE(alerter.Expired());
   // cout << "TEST: waiting for alarm clock to expire" << endl;
   WaitForAlarmClockToExpire(alerter);
   // cout << "TEST: expecting true for expired" << endl;
   EXPECT_TRUE(alerter.Expired());

   // Reset after AlarmClock has expired
   // cout << "TEST: resetting alarm clock" << endl;
   alerter.Reset();
   // cout << "TEST: expecting false for expired" << endl;
   EXPECT_FALSE(alerter.Expired());
   // cout << "TEST: waiting for alarm clock to expire" << endl;
   WaitForAlarmClockToExpire(alerter);
   // cout << "TEST: expecting true for expired" << endl;
   EXPECT_TRUE(alerter.Expired());
   // cout << "TEST: finished and calling destrcutor" << endl;
}

TEST_F(AlarmClockTest, milliseconds_ResetBeforeExpired) {
   int ms = 7500;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   alerter.Reset();
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
}

TEST_F(AlarmClockTest, milliseconds_MultipleResetsAfterExpired) {
   // First run
   int ms = 750;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());

   // Reset after AlarmClock has expired
   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());

   // Reset again after it has expired
   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
}

TEST_F(AlarmClockTest, milliseconds_MultipleResetsBeforeExpired) {
   int ms = 7500;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   alerter.Reset();
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
}

TEST_F(AlarmClockTest, milliseconds_MultipleResetsMixed) {
   int ms = 750;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());

   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());

   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
}
<commit_msg>Chasing down concurrency issues<commit_after>/*
 * File:   AlarmClockTest.cpp
 * Author: Craig Cogdill
 * Created: October 15, 2015 10:45am
 * Modifier: Amanda Carbonari
 * Modified Date: January 5, 2015 3:45pm
 */

#include "AlarmClockTest.h"
#include "AlarmClock.h"
#include "StopWatch.h"
#include <chrono>
#include <iostream>
#include <thread>

std::atomic<unsigned int> AlarmClockTest::mFakeSleepUs(0);

namespace {
   typedef std::chrono::microseconds microseconds;
   typedef std::chrono::milliseconds milliseconds;
   typedef std::chrono::seconds seconds;

   unsigned int kFakeSleepLeeway = 100;

   template<typename T>
   void WaitForAlarmClockToExpire(AlarmClock<T>& alerter) {
      cout << "WAIT: Entering while" << endl;
      while (!alerter.Expired());
      cout << "WAIT: Exiting" << endl;
   }

   template<typename Duration>
   unsigned int ConvertToMicroSeconds(Duration t) {
      return std::chrono::duration_cast<microseconds>(t).count();
   }

   template<typename Duration>
   unsigned int ConvertToMilliSeconds(Duration t) {
      return std::chrono::duration_cast<milliseconds>(t).count();
   }

   unsigned int FakeSleep(unsigned int usToSleep) {
      AlarmClockTest::mFakeSleepUs.store(usToSleep);
      std::this_thread::sleep_for(microseconds(100));
      return 0;
   }
}

TEST_F(AlarmClockTest, GetUsSleepTimeInUs) {
   int us = 123456;
   AlarmClock<microseconds> alerter(us);
   EXPECT_EQ(us, alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, GetUsSleepTimeInMs) {
   int us = 123456;
   AlarmClock<microseconds> alerter(us);
   EXPECT_EQ(ConvertToMilliSeconds(microseconds(us)), alerter.SleepTimeMs());
}

TEST_F(AlarmClockTest, GetMsSleepTimeInMs) {
   int ms = 123456;
   AlarmClock<milliseconds> alerter(ms);
   EXPECT_EQ(ms, alerter.SleepTimeMs());
}

TEST_F(AlarmClockTest, GetMsSleepTimeInUs) {
   int ms = 123456;
   AlarmClock<milliseconds> alerter(ms);
   EXPECT_EQ(ConvertToMicroSeconds(milliseconds(ms)), alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, GetSecSleepTimeInUs) {
   int sec = 1;
   AlarmClock<seconds> alerter(sec);
   EXPECT_EQ(ConvertToMicroSeconds(seconds(sec)), alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, GetSecSleepTimeInMs) {
   int sec = 1;
   AlarmClock<seconds> alerter(sec);
   EXPECT_EQ(ConvertToMilliSeconds(seconds(sec)), alerter.SleepTimeMs());
}

TEST_F(AlarmClockTest, microsecondsLessThan500ms) {
   int us = 900;
   AlarmClock<microseconds> alerter(us, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, us-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, us);
}

TEST_F(AlarmClockTest, microsecondsGreaterThan500ms) {
   int us = 600000;
   AlarmClock<microseconds> alerter(us, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, us-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, us);
}

TEST_F(AlarmClockTest, weirdNumberOfMicroseconds) {
   int us = 724509;
   StopWatch sw;
   AlarmClock<microseconds> alerter(us, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, us-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, us);
}

TEST_F(AlarmClockTest, millisecondsLessThan500) {
   unsigned int ms = 100;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs()-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, oneSecondInMilliseconds) {
   unsigned int ms = 1000;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs()-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, millisecondsNotDivisibleBy500) {
   unsigned int ms = 1000;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs()-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs());
}

TEST_F(AlarmClockTest, secondsSimple) {
   unsigned int sec = 1;
   AlarmClock<seconds> alerter(sec, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
   EXPECT_GE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs()-kFakeSleepLeeway);
   EXPECT_LE(AlarmClockTest::mFakeSleepUs, alerter.SleepTimeUs());
}

// Not working, not sure what it's supposed to be testing?
TEST_F(AlarmClockTest, LongTimeout_ImmediatelyDestructed) {
   unsigned int sec = 1000;
   StopWatch sw;
   // cout << "TEST: Creating pointer" << endl;
   std::unique_ptr<AlarmClock<seconds>> acPtr(new AlarmClock<seconds>(sec, FakeSleep));
   // cout << "TEST: expecting false for expired" << endl;
   EXPECT_FALSE(acPtr->Expired());
   this_thread::sleep_for(microseconds(10));
   // cout << "TEST: resetting pointer" << endl;
   acPtr.reset();
   // cout << "TEST: expecting true for elapsed seconds" << endl;
   EXPECT_TRUE(sw.ElapsedSec() < 2);
   // cout << "TEST: calling destructor" << endl;
}

TEST_F(AlarmClockTest, milliseconds_ResetAfterExpired) {
   // First run
   int ms = 750;
   // cout << "TEST: creating alarm clock" << endl;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   // cout << "TEST: expecting false for expired" << endl;
   EXPECT_FALSE(alerter.Expired());
   // cout << "TEST: waiting for alarm clock to expire" << endl;
   WaitForAlarmClockToExpire(alerter);
   // cout << "TEST: expecting true for expired" << endl;
   EXPECT_TRUE(alerter.Expired());

   // Reset after AlarmClock has expired
   // cout << "TEST: resetting alarm clock" << endl;
   alerter.Reset();
   // cout << "TEST: expecting false for expired" << endl;
   EXPECT_FALSE(alerter.Expired());
   // cout << "TEST: waiting for alarm clock to expire" << endl;
   WaitForAlarmClockToExpire(alerter);
   // cout << "TEST: expecting true for expired" << endl;
   EXPECT_TRUE(alerter.Expired());
   // cout << "TEST: finished and calling destrcutor" << endl;
}

TEST_F(AlarmClockTest, milliseconds_ResetBeforeExpired) {
   int ms = 7500;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   alerter.Reset();
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
}

TEST_F(AlarmClockTest, milliseconds_MultipleResetsAfterExpired) {
   // First run
   int ms = 750;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());

   // Reset after AlarmClock has expired
   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());

   // Reset again after it has expired
   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
}

TEST_F(AlarmClockTest, milliseconds_MultipleResetsBeforeExpired) {
   int ms = 7500;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   alerter.Reset();
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
}

TEST_F(AlarmClockTest, milliseconds_MultipleResetsMixed) {
   int ms = 750;
   AlarmClock<milliseconds> alerter(ms, FakeSleep);
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());

   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());

   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   alerter.Reset();
   EXPECT_FALSE(alerter.Expired());
   WaitForAlarmClockToExpire(alerter);
   EXPECT_TRUE(alerter.Expired());
}
<|endoftext|>


<commit_before>
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
#include "logstore.h"
#include "datapage.h"
#include "logiterators.h"
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <pthread.h>
#include <sys/time.h>
#include <time.h>

#undef begin
#undef end

#include "check_util.h"

template class diskTreeIterator<datatuple>;

void insertProbeIter(size_t NUM_ENTRIES)
{
    srand(1000);
    unlink("storefile.txt");
    unlink("logfile.txt");

    sync();

    diskTreeComponent::init_stasis();

    int xid = Tbegin();

    logtable ltable;

    int pcount = 5;
    ltable.set_fixed_page_count(pcount);
    recordid table_root = ltable.allocTable(xid);

    Tcommit(xid);

    xid = Tbegin();
    diskTreeComponent *ltable_c1 = ltable.get_tree_c1();

    recordid tree_root = ltable_c1->get_root_rec();

    std::vector<std::string> data_arr;
    std::vector<std::string> key_arr;
    preprandstr(NUM_ENTRIES, data_arr, 5*4096, true);
    preprandstr(NUM_ENTRIES+200, key_arr, 50, true);//well i can handle upto 200

    std::sort(key_arr.begin(), key_arr.end(), &mycmp);

    removeduplicates(key_arr);
    if(key_arr.size() > NUM_ENTRIES)
        key_arr.erase(key_arr.begin()+NUM_ENTRIES, key_arr.end());

    NUM_ENTRIES=key_arr.size();

    if(data_arr.size() > NUM_ENTRIES)
        data_arr.erase(data_arr.begin()+NUM_ENTRIES, data_arr.end());

    printf("Stage 1: Writing %d keys\n", NUM_ENTRIES);

    int dpages = 0;
    int npages = 0;
    DataPage<datatuple> *dp=0;
    int64_t datasize = 0;
    std::vector<pageid_t> dsp;
    for(size_t i = 0; i < NUM_ENTRIES; i++)
    {
        //prepare the tuple
        datatuple* newtuple = datatuple::create(key_arr[i].c_str(), key_arr[i].length()+1, data_arr[i].c_str(), data_arr[i].length()+1);

        datasize += newtuple->byte_length();

        if(dp == NULL)
        {
            dp = ltable.insertTuple(xid, newtuple, ltable_c1);
            dpages++;
            dsp.push_back(dp->get_start_pid());
        }
        else
        {
            if(!dp->append(newtuple))
            {
                npages += dp->get_page_count();
                delete dp;
                dp = ltable.insertTuple(xid, newtuple, ltable_c1);
                dpages++;
                dsp.push_back(dp->get_start_pid());
            }
        }

        datatuple::freetuple(newtuple);
    }

    printf("\nTREE STRUCTURE\n");
    ltable_c1->print_tree(xid);

    printf("Total data set length: %lld\n", datasize);
    printf("Storage utilization: %.2f\n", (datasize+.0) / (PAGE_SIZE * npages));
    printf("Number of datapages: %d\n", dpages);
    printf("Writes complete.\n");

    Tcommit(xid);
    xid = Tbegin();

    printf("Stage 2: Sequentially reading %d tuples\n", NUM_ENTRIES);

    size_t tuplenum = 0;
    diskTreeIterator<datatuple> tree_itr(tree_root);

    datatuple *dt=0;
    while( (dt=tree_itr.getnext()) != NULL)
    {
        assert(dt->keylen() == key_arr[tuplenum].length()+1);
        assert(dt->datalen() == data_arr[tuplenum].length()+1);
        tuplenum++;
        datatuple::freetuple(dt);
        dt = 0;
    }

    assert(tuplenum == key_arr.size());

    printf("Sequential Reads completed.\n");

    int rrsize=key_arr.size() / 3;
    printf("Stage 3: Randomly reading %d tuples by key\n", rrsize);

    for(int i=0; i<rrsize; i++)
    {
        //randomly pick a key
        int ri = rand()%key_arr.size();

		datatuple *dt = ltable.findTuple(xid, (const datatuple::key_t) key_arr[ri].c_str(), (size_t)key_arr[ri].length()+1, ltable_c1);

        assert(dt!=0);
        assert(dt->keylen() == key_arr[ri].length()+1);
        assert(dt->datalen() == data_arr[ri].length()+1);
        datatuple::freetuple(dt);
        dt = 0;
    }

    printf("Random Reads completed.\n");
    Tcommit(xid);
    diskTreeComponent::deinit_stasis();
}

/** @test
 */
int main()
{
    insertProbeIter(15000);

    return 0;
}

<commit_msg>Fix another datapage leak in unit test.<commit_after>
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
#include "logstore.h"
#include "datapage.h"
#include "logiterators.h"
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <pthread.h>
#include <sys/time.h>
#include <time.h>

#undef begin
#undef end

#include "check_util.h"

template class diskTreeIterator<datatuple>;

void insertProbeIter(size_t NUM_ENTRIES)
{
    srand(1000);
    unlink("storefile.txt");
    unlink("logfile.txt");

    sync();

    diskTreeComponent::init_stasis();

    int xid = Tbegin();

    logtable ltable;

    int pcount = 5;
    ltable.set_fixed_page_count(pcount);
    recordid table_root = ltable.allocTable(xid);

    Tcommit(xid);

    xid = Tbegin();
    diskTreeComponent *ltable_c1 = ltable.get_tree_c1();

    recordid tree_root = ltable_c1->get_root_rec();

    std::vector<std::string> data_arr;
    std::vector<std::string> key_arr;
    preprandstr(NUM_ENTRIES, data_arr, 5*4096, true);
    preprandstr(NUM_ENTRIES+200, key_arr, 50, true);//well i can handle upto 200

    std::sort(key_arr.begin(), key_arr.end(), &mycmp);

    removeduplicates(key_arr);
    if(key_arr.size() > NUM_ENTRIES)
        key_arr.erase(key_arr.begin()+NUM_ENTRIES, key_arr.end());

    NUM_ENTRIES=key_arr.size();

    if(data_arr.size() > NUM_ENTRIES)
        data_arr.erase(data_arr.begin()+NUM_ENTRIES, data_arr.end());

    printf("Stage 1: Writing %d keys\n", NUM_ENTRIES);

    int dpages = 0;
    int npages = 0;
    DataPage<datatuple> *dp=0;
    int64_t datasize = 0;
    std::vector<pageid_t> dsp;
    for(size_t i = 0; i < NUM_ENTRIES; i++)
    {
        //prepare the tuple
        datatuple* newtuple = datatuple::create(key_arr[i].c_str(), key_arr[i].length()+1, data_arr[i].c_str(), data_arr[i].length()+1);

        datasize += newtuple->byte_length();

        if(dp == NULL)
        {
            dp = ltable.insertTuple(xid, newtuple, ltable_c1);
            dpages++;
            dsp.push_back(dp->get_start_pid());
        }
        else
        {
            if(!dp->append(newtuple))
            {
                npages += dp->get_page_count();
                delete dp;
                dp = ltable.insertTuple(xid, newtuple, ltable_c1);
                dpages++;
                dsp.push_back(dp->get_start_pid());
            }
        }

        datatuple::freetuple(newtuple);
    }

    printf("\nTREE STRUCTURE\n");
    ltable_c1->print_tree(xid);

    printf("Total data set length: %lld\n", datasize);
    printf("Storage utilization: %.2f\n", (datasize+.0) / (PAGE_SIZE * npages));
    printf("Number of datapages: %d\n", dpages);
    printf("Writes complete.\n");
    if(dp)
    	delete dp;

    Tcommit(xid);
    xid = Tbegin();

    printf("Stage 2: Sequentially reading %d tuples\n", NUM_ENTRIES);

    size_t tuplenum = 0;
    diskTreeIterator<datatuple> tree_itr(tree_root);

    datatuple *dt=0;
    while( (dt=tree_itr.getnext()) != NULL)
    {
        assert(dt->keylen() == key_arr[tuplenum].length()+1);
        assert(dt->datalen() == data_arr[tuplenum].length()+1);
        tuplenum++;
        datatuple::freetuple(dt);
        dt = 0;
    }

    assert(tuplenum == key_arr.size());

    printf("Sequential Reads completed.\n");

    int rrsize=key_arr.size() / 3;
    printf("Stage 3: Randomly reading %d tuples by key\n", rrsize);

    for(int i=0; i<rrsize; i++)
    {
        //randomly pick a key
        int ri = rand()%key_arr.size();

		datatuple *dt = ltable.findTuple(xid, (const datatuple::key_t) key_arr[ri].c_str(), (size_t)key_arr[ri].length()+1, ltable_c1);

        assert(dt!=0);
        assert(dt->keylen() == key_arr[ri].length()+1);
        assert(dt->datalen() == data_arr[ri].length()+1);
        datatuple::freetuple(dt);
        dt = 0;
    }

    printf("Random Reads completed.\n");
    Tcommit(xid);
    diskTreeComponent::deinit_stasis();
}

/** @test
 */
int main()
{
    insertProbeIter(15000);

    return 0;
}

<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of dirtsand.                                             *
 *                                                                            *
 * dirtsand is free software: you can redistribute it and/or modify           *
 * it under the terms of the GNU Affero General Public License as             *
 * published by the Free Software Foundation, either version 3 of the         *
 * License, or (at your option) any later version.                            *
 *                                                                            *
 * dirtsand 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 Affero General Public License for more details.                        *
 *                                                                            *
 * You should have received a copy of the GNU Affero General Public License   *
 * along with dirtsand.  If not, see <http://www.gnu.org/licenses/>.          *
 ******************************************************************************/

#include "streams.h"
#include "errors.h"
#include <string_theory/codecs>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

ST::string DS::Stream::readString(size_t length, DS::StringType format)
{
    if (format == e_StringUTF16) {
        ST::utf16_buffer result;
        char16_t* buffer = result.create_writable_buffer(length);
        ssize_t bytes = readBytes(buffer, length * sizeof(char16_t));
        DS_DASSERT(bytes == static_cast<ssize_t>(length * sizeof(char16_t)));
        buffer[length] = 0;
        return ST::string::from_utf16(result, ST::substitute_invalid);
    } else {
        ST::char_buffer result;
        char* buffer = result.create_writable_buffer(length);
        ssize_t bytes = readBytes(buffer, length * sizeof(char));
        DS_DASSERT(bytes == static_cast<ssize_t>(length * sizeof(char)));
        buffer[length] = 0;
        return (format == e_StringUTF8) ? ST::string::from_utf8(result, ST::substitute_invalid)
                                        : ST::string::from_latin_1(result);
    }
}

ST::string DS::Stream::readSafeString(DS::StringType format)
{
    uint16_t length = read<uint16_t>();
    if (!(length & 0xF000))
        read<uint16_t>();   // Discarded
    length &= 0x0FFF;

    if (format == e_StringUTF16) {
        ST::utf16_buffer result;
        char16_t* buffer = result.create_writable_buffer(length);
        ssize_t bytes = readBytes(buffer, length * sizeof(char16_t));
        read<char16_t>(); // redundant u'\0'
        DS_DASSERT(bytes == static_cast<ssize_t>(length * sizeof(char16_t)));
        if (length && (buffer[0] & 0x8000)) {
            for (uint16_t i=0; i<length; ++i)
                buffer[i] = ~buffer[i];
        }
        buffer[length] = 0;
        return ST::string::from_utf16(result, ST::substitute_invalid);
    } else {
        ST::char_buffer result;
        char* buffer = result.create_writable_buffer(length);
        ssize_t bytes = readBytes(buffer, length * sizeof(char));
        DS_DASSERT(bytes == static_cast<ssize_t>(length * sizeof(char)));
        if (length && (buffer[0] & 0x80)) {
            for (uint16_t i=0; i<length; ++i)
                buffer[i] = ~buffer[i];
        }
        buffer[length] = 0;
        return (format == e_StringUTF8)
               ? ST::string::from_utf8(result, ST::substitute_invalid)
               : ST::string::from_latin_1(result);
    }
}

void DS::Stream::writeString(const ST::string& value, DS::StringType format)
{
    if (format == e_StringUTF16) {
        ST::utf16_buffer buffer = value.to_utf16();
        writeBytes(buffer.data(), buffer.size() * sizeof(char16_t));
    } else {
        ST::char_buffer buffer = (format == e_StringUTF8) ? value.to_utf8()
                               : value.to_latin_1(ST::substitute_invalid);
        writeBytes(buffer.data(), buffer.size() * sizeof(char));
    }
}

void DS::Stream::writeSafeString(const ST::string& value, DS::StringType format)
{
    if (format == e_StringUTF16) {
        ST::utf16_buffer buffer = value.to_utf16();
        uint16_t length = value.size() & 0x0FFF;
        ST::utf16_buffer work;
        char16_t* data = work.create_writable_buffer(length);
        memcpy(data, buffer.data(), length * sizeof(char16_t));
        for (uint16_t i=0; i<length; ++i)
            data[i] = ~data[i];
        write<uint16_t>(length | 0xF000);
        writeBytes(data, length * sizeof(char16_t));
        write<char16_t>(0);
    } else {
        ST::char_buffer buffer = (format == e_StringUTF8) ? value.to_utf8()
                               : value.to_latin_1(ST::substitute_invalid);
        uint16_t length = value.size() & 0x0FFF;
        ST::char_buffer work;
        char* data = work.create_writable_buffer(length);
        memcpy(data, buffer.data(), length * sizeof(char));
        for (uint16_t i=0; i<length; ++i)
            data[i] = ~data[i];
        write<uint16_t>(length | 0xF000);
        writeBytes(data, length * sizeof(char));
    }
}

void DS::FileStream::open(const char* filename, const char* mode)
{
    close();
    m_file = fopen(filename, mode);
    if (!m_file)
        throw FileIOException(strerror(errno));
}

uint32_t DS::FileStream::size() const
{
    struct stat statbuf;
    fstat(fileno(m_file), &statbuf);
    return static_cast<uint32_t>(statbuf.st_size);
}

bool DS::FileStream::atEof()
{
    int ch = fgetc(m_file);
    fputc(ch, m_file);
    return (ch == EOF);
}

ssize_t DS::BufferStream::readBytes(void* buffer, size_t count)
{
    if (m_position + count > m_size)
        count = m_size - m_position;
    memcpy(buffer, m_buffer + m_position, count);
    m_position += count;
    return count;
}

ssize_t DS::BufferStream::writeBytes(const void* buffer, size_t count)
{
    if (m_position + count > m_alloc) {
        // Resize stream
        size_t bigger = m_alloc ? m_alloc : 4096;
        while (m_position + count > bigger)
            bigger *= 2;
        uint8_t* newbuffer = new uint8_t[bigger];
        memcpy(newbuffer, m_buffer, m_size);
        delete[] m_buffer;
        m_buffer = newbuffer;
        m_alloc = bigger;
    }
    memcpy(m_buffer + m_position, buffer, count);
    m_position += count;
    if (m_position > m_size)
        m_size = m_position;
    return count;
}

void DS::BufferStream::seek(int32_t offset, int whence)
{
    if (whence == SEEK_SET)
        m_position = offset;
    else if (whence == SEEK_CUR)
        m_position += offset;
    else if (whence == SEEK_END)
        m_position = m_size - offset;

    DS_PASSERT(static_cast<int32_t>(m_position) >= 0 && m_position <= m_size);
}

void DS::BufferStream::set(const void* data, size_t size)
{
    delete[] m_buffer;
    if (data) {
        m_size = m_alloc = size;
        m_buffer = new uint8_t[m_alloc];
        memcpy(m_buffer, data, m_size);
    } else {
        m_buffer = 0;
        m_size = m_alloc = 0;
    }
    m_position = 0;
}

void DS::BufferStream::steal(uint8_t* buffer, size_t size)
{
    delete[] m_buffer;
    m_buffer = buffer;
    m_size = m_alloc = size;
    m_position = 0;
}

ssize_t DS::BlobStream::readBytes(void* buffer, size_t count)
{
    if (m_position + count > m_blob.size())
        count = m_blob.size() - m_position;
    memcpy(buffer, m_blob.buffer() + m_position, count);
    m_position += count;
    return count;
}

ssize_t DS::BlobStream::writeBytes(const void* buffer, size_t count)
{
    throw FileIOException("Cannot write to read-only stream");
}

void DS::BlobStream::seek(int32_t offset, int whence)
{
    if (whence == SEEK_SET)
        m_position = offset;
    else if (whence == SEEK_CUR)
        m_position += offset;
    else if (whence == SEEK_END)
        m_position = m_blob.size() - offset;

    DS_PASSERT(static_cast<int32_t>(m_position) >= 0 && m_position <= m_blob.size());
}

DS::Blob DS::Base64Decode(const ST::string& value)
{
    ST_ssize_t resultLen = ST::base64_decode(value, nullptr, 0);
    DS_PASSERT(resultLen >= 0);

    uint8_t* result = new uint8_t[resultLen];
    ST::base64_decode(value, result, resultLen);
    return Blob::Steal(result, resultLen);
}

DS::Blob DS::HexDecode(const ST::string& value)
{
    ST_ssize_t resultLen = ST::hex_decode(value, nullptr, 0);
    DS_PASSERT(resultLen >= 0);

    uint8_t* result = new uint8_t[resultLen];
    ST::hex_decode(value, result, resultLen);
    return Blob::Steal(result, resultLen);
}
<commit_msg>Don't try to memcpy() from NULL even if size == 0<commit_after>/******************************************************************************
 * This file is part of dirtsand.                                             *
 *                                                                            *
 * dirtsand is free software: you can redistribute it and/or modify           *
 * it under the terms of the GNU Affero General Public License as             *
 * published by the Free Software Foundation, either version 3 of the         *
 * License, or (at your option) any later version.                            *
 *                                                                            *
 * dirtsand 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 Affero General Public License for more details.                        *
 *                                                                            *
 * You should have received a copy of the GNU Affero General Public License   *
 * along with dirtsand.  If not, see <http://www.gnu.org/licenses/>.          *
 ******************************************************************************/

#include "streams.h"
#include "errors.h"
#include <string_theory/codecs>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

ST::string DS::Stream::readString(size_t length, DS::StringType format)
{
    if (format == e_StringUTF16) {
        ST::utf16_buffer result;
        char16_t* buffer = result.create_writable_buffer(length);
        ssize_t bytes = readBytes(buffer, length * sizeof(char16_t));
        DS_DASSERT(bytes == static_cast<ssize_t>(length * sizeof(char16_t)));
        buffer[length] = 0;
        return ST::string::from_utf16(result, ST::substitute_invalid);
    } else {
        ST::char_buffer result;
        char* buffer = result.create_writable_buffer(length);
        ssize_t bytes = readBytes(buffer, length * sizeof(char));
        DS_DASSERT(bytes == static_cast<ssize_t>(length * sizeof(char)));
        buffer[length] = 0;
        return (format == e_StringUTF8) ? ST::string::from_utf8(result, ST::substitute_invalid)
                                        : ST::string::from_latin_1(result);
    }
}

ST::string DS::Stream::readSafeString(DS::StringType format)
{
    uint16_t length = read<uint16_t>();
    if (!(length & 0xF000))
        read<uint16_t>();   // Discarded
    length &= 0x0FFF;

    if (format == e_StringUTF16) {
        ST::utf16_buffer result;
        char16_t* buffer = result.create_writable_buffer(length);
        ssize_t bytes = readBytes(buffer, length * sizeof(char16_t));
        read<char16_t>(); // redundant u'\0'
        DS_DASSERT(bytes == static_cast<ssize_t>(length * sizeof(char16_t)));
        if (length && (buffer[0] & 0x8000)) {
            for (uint16_t i=0; i<length; ++i)
                buffer[i] = ~buffer[i];
        }
        buffer[length] = 0;
        return ST::string::from_utf16(result, ST::substitute_invalid);
    } else {
        ST::char_buffer result;
        char* buffer = result.create_writable_buffer(length);
        ssize_t bytes = readBytes(buffer, length * sizeof(char));
        DS_DASSERT(bytes == static_cast<ssize_t>(length * sizeof(char)));
        if (length && (buffer[0] & 0x80)) {
            for (uint16_t i=0; i<length; ++i)
                buffer[i] = ~buffer[i];
        }
        buffer[length] = 0;
        return (format == e_StringUTF8)
               ? ST::string::from_utf8(result, ST::substitute_invalid)
               : ST::string::from_latin_1(result);
    }
}

void DS::Stream::writeString(const ST::string& value, DS::StringType format)
{
    if (format == e_StringUTF16) {
        ST::utf16_buffer buffer = value.to_utf16();
        writeBytes(buffer.data(), buffer.size() * sizeof(char16_t));
    } else {
        ST::char_buffer buffer = (format == e_StringUTF8) ? value.to_utf8()
                               : value.to_latin_1(ST::substitute_invalid);
        writeBytes(buffer.data(), buffer.size() * sizeof(char));
    }
}

void DS::Stream::writeSafeString(const ST::string& value, DS::StringType format)
{
    if (format == e_StringUTF16) {
        ST::utf16_buffer buffer = value.to_utf16();
        uint16_t length = value.size() & 0x0FFF;
        ST::utf16_buffer work;
        char16_t* data = work.create_writable_buffer(length);
        memcpy(data, buffer.data(), length * sizeof(char16_t));
        for (uint16_t i=0; i<length; ++i)
            data[i] = ~data[i];
        write<uint16_t>(length | 0xF000);
        writeBytes(data, length * sizeof(char16_t));
        write<char16_t>(0);
    } else {
        ST::char_buffer buffer = (format == e_StringUTF8) ? value.to_utf8()
                               : value.to_latin_1(ST::substitute_invalid);
        uint16_t length = value.size() & 0x0FFF;
        ST::char_buffer work;
        char* data = work.create_writable_buffer(length);
        memcpy(data, buffer.data(), length * sizeof(char));
        for (uint16_t i=0; i<length; ++i)
            data[i] = ~data[i];
        write<uint16_t>(length | 0xF000);
        writeBytes(data, length * sizeof(char));
    }
}

void DS::FileStream::open(const char* filename, const char* mode)
{
    close();
    m_file = fopen(filename, mode);
    if (!m_file)
        throw FileIOException(strerror(errno));
}

uint32_t DS::FileStream::size() const
{
    struct stat statbuf;
    fstat(fileno(m_file), &statbuf);
    return static_cast<uint32_t>(statbuf.st_size);
}

bool DS::FileStream::atEof()
{
    int ch = fgetc(m_file);
    fputc(ch, m_file);
    return (ch == EOF);
}

ssize_t DS::BufferStream::readBytes(void* buffer, size_t count)
{
    if (m_position + count > m_size)
        count = m_size - m_position;
    memcpy(buffer, m_buffer + m_position, count);
    m_position += count;
    return count;
}

ssize_t DS::BufferStream::writeBytes(const void* buffer, size_t count)
{
    if (m_position + count > m_alloc) {
        // Resize stream
        size_t bigger = m_alloc ? m_alloc : 4096;
        while (m_position + count > bigger)
            bigger *= 2;
        uint8_t* newbuffer = new uint8_t[bigger];
        if (m_size != 0)
            memcpy(newbuffer, m_buffer, m_size);
        delete[] m_buffer;
        m_buffer = newbuffer;
        m_alloc = bigger;
    }
    memcpy(m_buffer + m_position, buffer, count);
    m_position += count;
    if (m_position > m_size)
        m_size = m_position;
    return count;
}

void DS::BufferStream::seek(int32_t offset, int whence)
{
    if (whence == SEEK_SET)
        m_position = offset;
    else if (whence == SEEK_CUR)
        m_position += offset;
    else if (whence == SEEK_END)
        m_position = m_size - offset;

    DS_PASSERT(static_cast<int32_t>(m_position) >= 0 && m_position <= m_size);
}

void DS::BufferStream::set(const void* data, size_t size)
{
    delete[] m_buffer;
    if (data) {
        m_size = m_alloc = size;
        m_buffer = new uint8_t[m_alloc];
        memcpy(m_buffer, data, m_size);
    } else {
        m_buffer = 0;
        m_size = m_alloc = 0;
    }
    m_position = 0;
}

void DS::BufferStream::steal(uint8_t* buffer, size_t size)
{
    delete[] m_buffer;
    m_buffer = buffer;
    m_size = m_alloc = size;
    m_position = 0;
}

ssize_t DS::BlobStream::readBytes(void* buffer, size_t count)
{
    if (m_position + count > m_blob.size())
        count = m_blob.size() - m_position;
    memcpy(buffer, m_blob.buffer() + m_position, count);
    m_position += count;
    return count;
}

ssize_t DS::BlobStream::writeBytes(const void* buffer, size_t count)
{
    throw FileIOException("Cannot write to read-only stream");
}

void DS::BlobStream::seek(int32_t offset, int whence)
{
    if (whence == SEEK_SET)
        m_position = offset;
    else if (whence == SEEK_CUR)
        m_position += offset;
    else if (whence == SEEK_END)
        m_position = m_blob.size() - offset;

    DS_PASSERT(static_cast<int32_t>(m_position) >= 0 && m_position <= m_blob.size());
}

DS::Blob DS::Base64Decode(const ST::string& value)
{
    ST_ssize_t resultLen = ST::base64_decode(value, nullptr, 0);
    DS_PASSERT(resultLen >= 0);

    uint8_t* result = new uint8_t[resultLen];
    ST::base64_decode(value, result, resultLen);
    return Blob::Steal(result, resultLen);
}

DS::Blob DS::HexDecode(const ST::string& value)
{
    ST_ssize_t resultLen = ST::hex_decode(value, nullptr, 0);
    DS_PASSERT(resultLen >= 0);

    uint8_t* result = new uint8_t[resultLen];
    ST::hex_decode(value, result, resultLen);
    return Blob::Steal(result, resultLen);
}
<|endoftext|>


<commit_before>//===--- ParseGeneric.cpp - Swift Language Parser for Generics ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Generic Parsing and AST Building
//
//===----------------------------------------------------------------------===//

#include "swift/Parse/Parser.h"
#include "swift/AST/DiagnosticsParse.h"
#include "swift/Parse/Lexer.h"
using namespace swift;

/// parseGenericParameters - Parse a sequence of generic parameters, e.g.,
/// < T : Comparable, U : Container> along with an optional requires clause.
///
///   generic-params:
///     '<' generic-param (',' generic-param)* where-clause? '>'
///
///   generic-param:
///     identifier
///     identifier ':' type-identifier
///     identifier ':' type-composition
///
/// When parsing the generic parameters, this routine establishes a new scope
/// and adds those parameters to the scope.
ParserResult<GenericParamList> Parser::parseGenericParameters() {
  // Parse the opening '<'.
  assert(startsWithLess(Tok) && "Generic parameter list must start with '<'");
  return parseGenericParameters(consumeStartingLess());
}

ParserResult<GenericParamList>
Parser::parseGenericParameters(SourceLoc LAngleLoc) {
  // Parse the generic parameter list.
  SmallVector<GenericTypeParamDecl *, 4> GenericParams;
  bool Invalid = false;
  do {
    // Note that we're parsing a declaration.
    StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(),
                                    StructureMarkerKind::Declaration);

    // Parse attributes.
    DeclAttributes attributes;
    if (Tok.hasComment())
      attributes.add(new (Context) RawDocCommentAttr(Tok.getCommentRange()));
    bool foundCCTokenInAttr;
    parseDeclAttributeList(attributes, foundCCTokenInAttr);

    // Parse the name of the parameter.
    Identifier Name;
    SourceLoc NameLoc;
    if (parseIdentifier(Name, NameLoc,
                        diag::expected_generics_parameter_name)) {
      Invalid = true;
      break;
    }

    // Parse the ':' followed by a type.
    SmallVector<TypeLoc, 1> Inherited;
    if (Tok.is(tok::colon)) {
      (void)consumeToken();
      ParserResult<TypeRepr> Ty;

      if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol, tok::kw_Any)) {
        Ty = parseTypeForInheritance(diag::expected_identifier_for_type,
                                     diag::expected_ident_type_in_inheritance);
      } else if (Tok.is(tok::kw_class)) {
        diagnose(Tok, diag::unexpected_class_constraint);
        diagnose(Tok, diag::suggest_anyobject, Name)
          .fixItReplace(Tok.getLoc(), "AnyObject");
        consumeToken();
        Invalid = true;
      } else {
        diagnose(Tok, diag::expected_generics_type_restriction, Name);
        Invalid = true;
      }

      if (Ty.hasCodeCompletion())
        return makeParserCodeCompletionStatus();

      if (Ty.isNonNull())
        Inherited.push_back(Ty.get());
    }

    // We always create generic type parameters with a depth of zero.
    // Semantic analysis fills in the depth when it processes the generic
    // parameter list.
    auto Param = new (Context) GenericTypeParamDecl(CurDeclContext, Name,
                                                    NameLoc, /*depth=*/0,
                                                    GenericParams.size());
    if (!Inherited.empty())
      Param->setInherited(Context.AllocateCopy(Inherited));
    GenericParams.push_back(Param);

    // Attach attributes.
    Param->getAttrs() = attributes;

    // Add this parameter to the scope.
    addToScope(Param);

    // Parse the comma, if the list continues.
  } while (consumeIf(tok::comma));

  // Parse the optional where-clause.
  SourceLoc WhereLoc;
  SmallVector<RequirementRepr, 4> Requirements;
  bool FirstTypeInComplete;
  if (Tok.is(tok::kw_where) &&
      parseGenericWhereClause(WhereLoc, Requirements,
                              FirstTypeInComplete).isError()) {
    Invalid = true;
  }

  // Parse the closing '>'.
  SourceLoc RAngleLoc;
  if (startsWithGreater(Tok)) {
    RAngleLoc = consumeStartingGreater();
  } else {
    if (!Invalid) {
      diagnose(Tok, diag::expected_rangle_generics_param);
      diagnose(LAngleLoc, diag::opening_angle);
      Invalid = true;
    }

    // Skip until we hit the '>'.
    RAngleLoc = skipUntilGreaterInTypeList();
  }

  if (GenericParams.empty() || Invalid) {
    // FIXME: We should really return the generic parameter list here,
    // even if some generic parameters were invalid, since we rely on
    // decl->setGenericParams() to re-parent the GenericTypeParamDecls
    // into the right DeclContext.
    for (auto Param : GenericParams)
      Param->setInvalid();
    return nullptr;
  }

  return makeParserResult(GenericParamList::create(Context, LAngleLoc,
                                                   GenericParams, WhereLoc,
                                                   Requirements, RAngleLoc));
}

ParserResult<GenericParamList> Parser::maybeParseGenericParams() {
  if (!startsWithLess(Tok))
    return nullptr;

  if (!isInSILMode())
    return parseGenericParameters();

  // In SIL mode, we can have multiple generic parameter lists, with the
  // first one being the outmost generic parameter list.
  GenericParamList *gpl = nullptr, *outer_gpl = nullptr;
  do {
    gpl = parseGenericParameters().getPtrOrNull();
    if (!gpl)
      return nullptr;

    if (outer_gpl)
      gpl->setOuterParameters(outer_gpl);
    outer_gpl = gpl;
  } while (startsWithLess(Tok));
  return makeParserResult(gpl);
}

void
Parser::diagnoseWhereClauseInGenericParamList(const GenericParamList *
                                              GenericParams) {
  if (GenericParams == nullptr || GenericParams->getWhereLoc().isInvalid())
    return;

  auto WhereRangeInsideBrackets = GenericParams->getWhereClauseSourceRange();

  // Move everything immediately following the last generic parameter
  // as written all the way to the right angle bracket (">")
  auto LastGenericParam = GenericParams->getParams().back();
  auto EndOfLastGenericParam =
      Lexer::getLocForEndOfToken(SourceMgr, LastGenericParam->getEndLoc());

  CharSourceRange RemoveWhereRange { SourceMgr,
    EndOfLastGenericParam,
    GenericParams->getRAngleLoc()
  };

  auto WhereCharRange =
    Lexer::getCharSourceRangeFromSourceRange(SourceMgr,
                                  GenericParams->getWhereClauseSourceRange());

  SmallString<64> Buffer;
  llvm::raw_svector_ostream WhereClauseText(Buffer);
  WhereClauseText << SourceMgr.extractText(Tok.is(tok::kw_where)
                                           ? WhereCharRange
                                           : RemoveWhereRange);

  // If, for some reason, there was a where clause in both locations, we're
  // adding to the list of requirements, so tack on a comma here before
  // inserting it at the head of the later where clause.
  if (Tok.is(tok::kw_where))
    WhereClauseText << ',';

  auto Diag = diagnose(WhereRangeInsideBrackets.Start,
                       diag::where_inside_brackets);
  Diag.fixItRemoveChars(RemoveWhereRange.getStart(),
                        RemoveWhereRange.getEnd());

  if (Tok.is(tok::kw_where)) {
    Diag.fixItReplace(Tok.getLoc(), WhereClauseText.str());
  } else {
    Diag.fixItInsert(Lexer::getLocForEndOfToken(SourceMgr, PreviousLoc),
                     WhereClauseText.str());
  }
}

/// parseGenericWhereClause - Parse a 'where' clause, which places additional
/// constraints on generic parameters or types based on them.
///
///   where-clause:
///     'where' requirement (',' requirement) *
///
///   requirement:
///     conformance-requirement
///     same-type-requirement
///
///   conformance-requirement:
///     type-identifier ':' type-identifier
///     type-identifier ':' type-composition
///
///   same-type-requirement:
///     type-identifier '==' type
ParserStatus Parser::parseGenericWhereClause(
               SourceLoc &WhereLoc,
               SmallVectorImpl<RequirementRepr> &Requirements,
               bool &FirstTypeInComplete,
               bool AllowLayoutConstraints) {
  ParserStatus Status;
  // Parse the 'where'.
  WhereLoc = consumeToken(tok::kw_where);
  FirstTypeInComplete = false;
  do {
    // Parse the leading type-identifier.
    ParserResult<TypeRepr> FirstType = parseTypeIdentifier();
    if (FirstType.isNull()) {
      Status.setIsParseError();
      if (FirstType.hasCodeCompletion()) {
        Status.setHasCodeCompletion();
        FirstTypeInComplete = true;
      }
      break;
    }

    if (Tok.is(tok::colon)) {
      // A conformance-requirement.
      SourceLoc ColonLoc = consumeToken();

      if (Tok.is(tok::identifier) &&
          getLayoutConstraintInfo(Context.getIdentifier(Tok.getText()),
                                  Context)) {
        // Parse a layout constraint.
        auto LayoutName = Context.getIdentifier(Tok.getText());
        auto LayoutLoc = consumeToken();
        auto LayoutInfo = parseLayoutConstraint(LayoutName);
        if (!LayoutInfo.isKnownLayout()) {
          // There was a bug in the layout constraint.
          Status.setIsParseError();
        }
        auto Layout = LayoutConstraint(Context.AllocateObjectCopy(LayoutInfo));
        if (!AllowLayoutConstraints) {
          diagnose(LayoutLoc,
                   diag::layout_constraints_only_inside_specialize_attr);
        } else {
          // Add the layout requirement.
          Requirements.push_back(RequirementRepr::getLayoutConstraint(
              FirstType.get(), ColonLoc,
              LayoutConstraintLoc(Layout, LayoutLoc)));
        }
      } else {
        // Parse the protocol or composition.
        ParserResult<TypeRepr> Protocol =
            parseTypeForInheritance(diag::expected_identifier_for_type,
                                    diag::expected_ident_type_in_inheritance);

        if (Protocol.isNull()) {
          Status.setIsParseError();
          if (Protocol.hasCodeCompletion())
            Status.setHasCodeCompletion();
          break;
        }

        // Add the requirement.
        Requirements.push_back(RequirementRepr::getTypeConstraint(
            FirstType.get(), ColonLoc, Protocol.get()));
      }
    } else if ((Tok.isAnyOperator() && Tok.getText() == "==") ||
               Tok.is(tok::equal)) {
      // A same-type-requirement
      if (Tok.is(tok::equal)) {
        diagnose(Tok, diag::requires_single_equal)
          .fixItReplace(SourceRange(Tok.getLoc()), "==");
      }
      SourceLoc EqualLoc = consumeToken();

      // Parse the second type.
      ParserResult<TypeRepr> SecondType = parseType();
      if (SecondType.isNull()) {
        Status.setIsParseError();
        if (SecondType.hasCodeCompletion())
          Status.setHasCodeCompletion();
        break;
      }

      // Add the requirement
      Requirements.push_back(RequirementRepr::getSameType(FirstType.get(),
                                                      EqualLoc,
                                                      SecondType.get()));
    } else {
      diagnose(Tok, diag::expected_requirement_delim);
      Status.setIsParseError();
      break;
    }
    // If there's a comma, keep parsing the list.
  } while (consumeIf(tok::comma));

  return Status;
}

/// Parse a free-standing where clause attached to a declaration, adding it to
/// a generic parameter list that may (or may not) already exist.
ParserStatus Parser::
parseFreestandingGenericWhereClause(GenericParamList *&genericParams,
                                    WhereClauseKind kind) {
  assert(Tok.is(tok::kw_where) && "Shouldn't call this without a where");

  // Push the generic arguments back into a local scope so that references will
  // find them.
  Scope S(this, ScopeKind::Generics);

  if (genericParams)
    for (auto pd : genericParams->getParams())
      addToScope(pd);

  SmallVector<RequirementRepr, 4> Requirements;
  if (genericParams)
    Requirements.append(genericParams->getRequirements().begin(),
                        genericParams->getRequirements().end());

  SourceLoc WhereLoc;
  bool FirstTypeInComplete;
  auto result = parseGenericWhereClause(WhereLoc, Requirements,
                                        FirstTypeInComplete);
  if (result.shouldStopParsing() || Requirements.empty())
    return result;

  if (!genericParams)
    diagnose(WhereLoc, diag::where_without_generic_params, unsigned(kind));
  else
    genericParams = GenericParamList::create(Context,
                                             genericParams->getLAngleLoc(),
                                             genericParams->getParams(),
                                             WhereLoc, Requirements,
                                             genericParams->getRAngleLoc());
  return ParserStatus();
}

<commit_msg>Parser: Don't return valid location from parseGenericWhereClause() if there were no requirements<commit_after>//===--- ParseGeneric.cpp - Swift Language Parser for Generics ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Generic Parsing and AST Building
//
//===----------------------------------------------------------------------===//

#include "swift/Parse/Parser.h"
#include "swift/AST/DiagnosticsParse.h"
#include "swift/Parse/Lexer.h"
using namespace swift;

/// parseGenericParameters - Parse a sequence of generic parameters, e.g.,
/// < T : Comparable, U : Container> along with an optional requires clause.
///
///   generic-params:
///     '<' generic-param (',' generic-param)* where-clause? '>'
///
///   generic-param:
///     identifier
///     identifier ':' type-identifier
///     identifier ':' type-composition
///
/// When parsing the generic parameters, this routine establishes a new scope
/// and adds those parameters to the scope.
ParserResult<GenericParamList> Parser::parseGenericParameters() {
  // Parse the opening '<'.
  assert(startsWithLess(Tok) && "Generic parameter list must start with '<'");
  return parseGenericParameters(consumeStartingLess());
}

ParserResult<GenericParamList>
Parser::parseGenericParameters(SourceLoc LAngleLoc) {
  // Parse the generic parameter list.
  SmallVector<GenericTypeParamDecl *, 4> GenericParams;
  bool Invalid = false;
  do {
    // Note that we're parsing a declaration.
    StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(),
                                    StructureMarkerKind::Declaration);

    // Parse attributes.
    DeclAttributes attributes;
    if (Tok.hasComment())
      attributes.add(new (Context) RawDocCommentAttr(Tok.getCommentRange()));
    bool foundCCTokenInAttr;
    parseDeclAttributeList(attributes, foundCCTokenInAttr);

    // Parse the name of the parameter.
    Identifier Name;
    SourceLoc NameLoc;
    if (parseIdentifier(Name, NameLoc,
                        diag::expected_generics_parameter_name)) {
      Invalid = true;
      break;
    }

    // Parse the ':' followed by a type.
    SmallVector<TypeLoc, 1> Inherited;
    if (Tok.is(tok::colon)) {
      (void)consumeToken();
      ParserResult<TypeRepr> Ty;

      if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol, tok::kw_Any)) {
        Ty = parseTypeForInheritance(diag::expected_identifier_for_type,
                                     diag::expected_ident_type_in_inheritance);
      } else if (Tok.is(tok::kw_class)) {
        diagnose(Tok, diag::unexpected_class_constraint);
        diagnose(Tok, diag::suggest_anyobject, Name)
          .fixItReplace(Tok.getLoc(), "AnyObject");
        consumeToken();
        Invalid = true;
      } else {
        diagnose(Tok, diag::expected_generics_type_restriction, Name);
        Invalid = true;
      }

      if (Ty.hasCodeCompletion())
        return makeParserCodeCompletionStatus();

      if (Ty.isNonNull())
        Inherited.push_back(Ty.get());
    }

    // We always create generic type parameters with a depth of zero.
    // Semantic analysis fills in the depth when it processes the generic
    // parameter list.
    auto Param = new (Context) GenericTypeParamDecl(CurDeclContext, Name,
                                                    NameLoc, /*depth=*/0,
                                                    GenericParams.size());
    if (!Inherited.empty())
      Param->setInherited(Context.AllocateCopy(Inherited));
    GenericParams.push_back(Param);

    // Attach attributes.
    Param->getAttrs() = attributes;

    // Add this parameter to the scope.
    addToScope(Param);

    // Parse the comma, if the list continues.
  } while (consumeIf(tok::comma));

  // Parse the optional where-clause.
  SourceLoc WhereLoc;
  SmallVector<RequirementRepr, 4> Requirements;
  bool FirstTypeInComplete;
  if (Tok.is(tok::kw_where) &&
      parseGenericWhereClause(WhereLoc, Requirements,
                              FirstTypeInComplete).isError()) {
    Invalid = true;
  }

  // Parse the closing '>'.
  SourceLoc RAngleLoc;
  if (startsWithGreater(Tok)) {
    RAngleLoc = consumeStartingGreater();
  } else {
    if (!Invalid) {
      diagnose(Tok, diag::expected_rangle_generics_param);
      diagnose(LAngleLoc, diag::opening_angle);
      Invalid = true;
    }

    // Skip until we hit the '>'.
    RAngleLoc = skipUntilGreaterInTypeList();
  }

  if (GenericParams.empty() || Invalid) {
    // FIXME: We should really return the generic parameter list here,
    // even if some generic parameters were invalid, since we rely on
    // decl->setGenericParams() to re-parent the GenericTypeParamDecls
    // into the right DeclContext.
    for (auto Param : GenericParams)
      Param->setInvalid();
    return nullptr;
  }

  return makeParserResult(GenericParamList::create(Context, LAngleLoc,
                                                   GenericParams, WhereLoc,
                                                   Requirements, RAngleLoc));
}

ParserResult<GenericParamList> Parser::maybeParseGenericParams() {
  if (!startsWithLess(Tok))
    return nullptr;

  if (!isInSILMode())
    return parseGenericParameters();

  // In SIL mode, we can have multiple generic parameter lists, with the
  // first one being the outmost generic parameter list.
  GenericParamList *gpl = nullptr, *outer_gpl = nullptr;
  do {
    gpl = parseGenericParameters().getPtrOrNull();
    if (!gpl)
      return nullptr;

    if (outer_gpl)
      gpl->setOuterParameters(outer_gpl);
    outer_gpl = gpl;
  } while (startsWithLess(Tok));
  return makeParserResult(gpl);
}

void
Parser::diagnoseWhereClauseInGenericParamList(const GenericParamList *
                                              GenericParams) {
  if (GenericParams == nullptr || GenericParams->getWhereLoc().isInvalid())
    return;

  auto WhereRangeInsideBrackets = GenericParams->getWhereClauseSourceRange();

  // Move everything immediately following the last generic parameter
  // as written all the way to the right angle bracket (">")
  auto LastGenericParam = GenericParams->getParams().back();
  auto EndOfLastGenericParam =
      Lexer::getLocForEndOfToken(SourceMgr, LastGenericParam->getEndLoc());

  CharSourceRange RemoveWhereRange { SourceMgr,
    EndOfLastGenericParam,
    GenericParams->getRAngleLoc()
  };

  auto WhereCharRange =
    Lexer::getCharSourceRangeFromSourceRange(SourceMgr,
                                  GenericParams->getWhereClauseSourceRange());

  SmallString<64> Buffer;
  llvm::raw_svector_ostream WhereClauseText(Buffer);
  WhereClauseText << SourceMgr.extractText(Tok.is(tok::kw_where)
                                           ? WhereCharRange
                                           : RemoveWhereRange);

  // If, for some reason, there was a where clause in both locations, we're
  // adding to the list of requirements, so tack on a comma here before
  // inserting it at the head of the later where clause.
  if (Tok.is(tok::kw_where))
    WhereClauseText << ',';

  auto Diag = diagnose(WhereRangeInsideBrackets.Start,
                       diag::where_inside_brackets);
  Diag.fixItRemoveChars(RemoveWhereRange.getStart(),
                        RemoveWhereRange.getEnd());

  if (Tok.is(tok::kw_where)) {
    Diag.fixItReplace(Tok.getLoc(), WhereClauseText.str());
  } else {
    Diag.fixItInsert(Lexer::getLocForEndOfToken(SourceMgr, PreviousLoc),
                     WhereClauseText.str());
  }
}

/// parseGenericWhereClause - Parse a 'where' clause, which places additional
/// constraints on generic parameters or types based on them.
///
///   where-clause:
///     'where' requirement (',' requirement) *
///
///   requirement:
///     conformance-requirement
///     same-type-requirement
///
///   conformance-requirement:
///     type-identifier ':' type-identifier
///     type-identifier ':' type-composition
///
///   same-type-requirement:
///     type-identifier '==' type
ParserStatus Parser::parseGenericWhereClause(
               SourceLoc &WhereLoc,
               SmallVectorImpl<RequirementRepr> &Requirements,
               bool &FirstTypeInComplete,
               bool AllowLayoutConstraints) {
  ParserStatus Status;
  // Parse the 'where'.
  WhereLoc = consumeToken(tok::kw_where);
  FirstTypeInComplete = false;
  do {
    // Parse the leading type-identifier.
    ParserResult<TypeRepr> FirstType = parseTypeIdentifier();
    if (FirstType.isNull()) {
      Status.setIsParseError();
      if (FirstType.hasCodeCompletion()) {
        Status.setHasCodeCompletion();
        FirstTypeInComplete = true;
      }
      break;
    }

    if (Tok.is(tok::colon)) {
      // A conformance-requirement.
      SourceLoc ColonLoc = consumeToken();

      if (Tok.is(tok::identifier) &&
          getLayoutConstraintInfo(Context.getIdentifier(Tok.getText()),
                                  Context)) {
        // Parse a layout constraint.
        auto LayoutName = Context.getIdentifier(Tok.getText());
        auto LayoutLoc = consumeToken();
        auto LayoutInfo = parseLayoutConstraint(LayoutName);
        if (!LayoutInfo.isKnownLayout()) {
          // There was a bug in the layout constraint.
          Status.setIsParseError();
        }
        auto Layout = LayoutConstraint(Context.AllocateObjectCopy(LayoutInfo));
        if (!AllowLayoutConstraints) {
          diagnose(LayoutLoc,
                   diag::layout_constraints_only_inside_specialize_attr);
        } else {
          // Add the layout requirement.
          Requirements.push_back(RequirementRepr::getLayoutConstraint(
              FirstType.get(), ColonLoc,
              LayoutConstraintLoc(Layout, LayoutLoc)));
        }
      } else {
        // Parse the protocol or composition.
        ParserResult<TypeRepr> Protocol =
            parseTypeForInheritance(diag::expected_identifier_for_type,
                                    diag::expected_ident_type_in_inheritance);

        if (Protocol.isNull()) {
          Status.setIsParseError();
          if (Protocol.hasCodeCompletion())
            Status.setHasCodeCompletion();
          break;
        }

        // Add the requirement.
        Requirements.push_back(RequirementRepr::getTypeConstraint(
            FirstType.get(), ColonLoc, Protocol.get()));
      }
    } else if ((Tok.isAnyOperator() && Tok.getText() == "==") ||
               Tok.is(tok::equal)) {
      // A same-type-requirement
      if (Tok.is(tok::equal)) {
        diagnose(Tok, diag::requires_single_equal)
          .fixItReplace(SourceRange(Tok.getLoc()), "==");
      }
      SourceLoc EqualLoc = consumeToken();

      // Parse the second type.
      ParserResult<TypeRepr> SecondType = parseType();
      if (SecondType.isNull()) {
        Status.setIsParseError();
        if (SecondType.hasCodeCompletion())
          Status.setHasCodeCompletion();
        break;
      }

      // Add the requirement
      Requirements.push_back(RequirementRepr::getSameType(FirstType.get(),
                                                      EqualLoc,
                                                      SecondType.get()));
    } else {
      diagnose(Tok, diag::expected_requirement_delim);
      Status.setIsParseError();
      break;
    }
    // If there's a comma, keep parsing the list.
  } while (consumeIf(tok::comma));

  if (Requirements.empty())
    WhereLoc = SourceLoc();

  return Status;
}

/// Parse a free-standing where clause attached to a declaration, adding it to
/// a generic parameter list that may (or may not) already exist.
ParserStatus Parser::
parseFreestandingGenericWhereClause(GenericParamList *&genericParams,
                                    WhereClauseKind kind) {
  assert(Tok.is(tok::kw_where) && "Shouldn't call this without a where");

  // Push the generic arguments back into a local scope so that references will
  // find them.
  Scope S(this, ScopeKind::Generics);

  if (genericParams)
    for (auto pd : genericParams->getParams())
      addToScope(pd);

  SmallVector<RequirementRepr, 4> Requirements;
  if (genericParams)
    Requirements.append(genericParams->getRequirements().begin(),
                        genericParams->getRequirements().end());

  SourceLoc WhereLoc;
  bool FirstTypeInComplete;
  auto result = parseGenericWhereClause(WhereLoc, Requirements,
                                        FirstTypeInComplete);
  if (result.shouldStopParsing() || Requirements.empty())
    return result;

  if (!genericParams)
    diagnose(WhereLoc, diag::where_without_generic_params, unsigned(kind));
  else
    genericParams = GenericParamList::create(Context,
                                             genericParams->getLAngleLoc(),
                                             genericParams->getParams(),
                                             WhereLoc, Requirements,
                                             genericParams->getRAngleLoc());
  return ParserStatus();
}

<|endoftext|>


<commit_before>#include "../gtest/src/gtest/include/gtest/gtest.h"
#include "SQLiteDatabaseHelper.h"

TEST(SQLiteDatabaseHelper, read_write_test) {

    SQLiteDatabaseHelper dbHelper;

    // First call to get writeable creates the database
    auto& db = dbHelper.getWriteableDatabase();

    EXPECT_TRUE(db.isOpen());

    db.close();

    EXPECT_FALSE(db.isOpen());

    EXPECT_THROW(db.execQuery("SELECT * from cars"), sqlite::SQLiteDatabaseException);

    db = dbHelper.getReadableDatabase();
    EXPECT_TRUE(db.isOpen());
    db.close();
    //EXPECT_NO_THROW(dbHelper.close());
}

TEST(SQLiteDatabaseHelper, read_only_test) {

    SQLiteDatabaseHelper dbHelper;

    // First call to get writeable creates the database
    auto& db = dbHelper.getWriteableDatabase();
    db.close();

    // Test read only database
    db = dbHelper.getReadableDatabase();
    EXPECT_TRUE(db.isOpen());

    EXPECT_NO_THROW(db.execQuery("SELECT * from cars"));

    db.close();

    EXPECT_FALSE(db.isOpen());
}

struct Car{
    std::string make;
    int mpg;
    int weight;
};

<commit_msg>added car test datastructure<commit_after>#include "../gtest/src/gtest/include/gtest/gtest.h"
#include "SQLiteDatabaseHelper.h"

// Test Car Data Structure
struct Car{
    std::string make;
    int mpg;
    int weight;
};

TEST(SQLiteDatabaseHelper, read_write_test) {

    SQLiteDatabaseHelper dbHelper;

    // First call to get writeable creates the database
    auto& db = dbHelper.getWriteableDatabase();

    EXPECT_TRUE(db.isOpen());

    db.close();

    EXPECT_FALSE(db.isOpen());

    EXPECT_THROW(db.execQuery("SELECT * from cars"), sqlite::SQLiteDatabaseException);

    db = dbHelper.getReadableDatabase();
    EXPECT_TRUE(db.isOpen());
    db.close();
    //EXPECT_NO_THROW(dbHelper.close());
}

TEST(SQLiteDatabaseHelper, read_only_test) {

    SQLiteDatabaseHelper dbHelper;

    // First call to get writeable creates the database
    auto& db = dbHelper.getWriteableDatabase();
    db.close();

    // Test read only database
    db = dbHelper.getReadableDatabase();
    EXPECT_TRUE(db.isOpen());

    EXPECT_NO_THROW(db.execQuery("SELECT * from cars"));

    db.close();

    EXPECT_FALSE(db.isOpen());
}

<|endoftext|>


<commit_before>/*
 * %injeqt copyright begin%
 * Copyright 2014 Rafał Malinowski (rafal.przemyslaw.malinowski@gmail.com)
 * %injeqt copyright end%
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "exception/empty-type-exception.cpp"
#include "exception/exception.cpp"
#include "exception/interface-not-implemented-exception.cpp"
#include "exception/invalid-qobject-exception.cpp"
#include "exception/qobject-type-exception.cpp"
#include "implementation.cpp"
#include "interfaces-utils.cpp"
#include "resolved-dependency.cpp"
#include "setter-method.cpp"
#include "type.cpp"

#include "expect.h"
#include "make-setter-method.h"
#include "utils.h"

#include <QtTest/QtTest>

using namespace injeqt::internal;
using namespace injeqt::v1;

class type_1 : public QObject
{
	Q_OBJECT
};

class type_1_subtype_1 : public QObject
{
	Q_OBJECT
};

class type_2 : public QObject
{
	Q_OBJECT
};

class injected_type : public QObject
{
	Q_OBJECT

public:
	type_1 *_1 = nullptr;
	type_2 *_2 = nullptr;

public slots:
	INJEQT_SETTER void setter_1(type_1 *a) { _1 = a; }
	INJEQT_SETTER void setter_1_subtype_1(type_1_subtype_1 *) {}
	INJEQT_SETTER void setter_2(type_2 *a) { _2 = a; }

};

class resolved_dependency_test : public QObject
{
	Q_OBJECT

public:
	resolved_dependency_test();

private slots:
	void should_properly_apply_on_valid_object();

private:
	type type_1_type;
	type type_1_subtype_1_type;
	type type_2_type;
	type injected_type_type;
	setter_method setter_1_method;
	setter_method setter_1_subtype_1_method;
	setter_method setter_2_method;

};

resolved_dependency_test::resolved_dependency_test() :
	type_1_type{make_type<type_1>()},
	type_1_subtype_1_type{make_type<type_1_subtype_1>()},
	type_2_type{make_type<type_2>()},
	injected_type_type{make_type<injected_type>()},
	setter_1_method{make_setter_method<injected_type>("setter_1(type_1*)")},
	setter_1_subtype_1_method{make_setter_method<injected_type>("setter_1_subtype_1(type_1_subtype_1*)")},
	setter_2_method{make_setter_method<injected_type>("setter_2(type_2*)")}
{
}

void resolved_dependency_test::should_properly_apply_on_valid_object()
{
	auto object_1 = make_object<type_1>();
	auto object_2 = make_object<type_2>();
	auto apply_on_object = make_object<injected_type>();
	auto resolved_1 = resolved_dependency{implementation{type_1_type, object_1.get()}, setter_1_method};
	auto resolved_2 = resolved_dependency{implementation{type_2_type, object_2.get()}, setter_2_method};

	QCOMPARE(static_cast<QObject *>(nullptr), static_cast<injected_type *>(apply_on_object.get())->_1);
	QCOMPARE(static_cast<QObject *>(nullptr), static_cast<injected_type *>(apply_on_object.get())->_2);

	resolved_1.apply_on(apply_on_object.get());

	QCOMPARE(object_1.get(), static_cast<injected_type *>(apply_on_object.get())->_1);
	QCOMPARE(static_cast<QObject *>(nullptr), static_cast<injected_type *>(apply_on_object.get())->_2);

	resolved_2.apply_on(apply_on_object.get());

	QCOMPARE(object_1.get(), static_cast<injected_type *>(apply_on_object.get())->_1);
	QCOMPARE(object_2.get(), static_cast<injected_type *>(apply_on_object.get())->_2);
}

QTEST_APPLESS_MAIN(resolved_dependency_test)
#include "resolved-dependency-test.moc"
<commit_msg>update resolved_dependency_test<commit_after>/*
 * %injeqt copyright begin%
 * Copyright 2014 Rafał Malinowski (rafal.przemyslaw.malinowski@gmail.com)
 * %injeqt copyright end%
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "exception/empty-type-exception.cpp"
#include "exception/exception.cpp"
#include "exception/interface-not-implemented-exception.cpp"
#include "exception/invalid-qobject-exception.cpp"
#include "exception/qobject-type-exception.cpp"
#include "implementation.cpp"
#include "interfaces-utils.cpp"
#include "resolved-dependency.cpp"
#include "setter-method.cpp"
#include "type.cpp"

#include "expect.h"
#include "make-setter-method.h"
#include "utils.h"

#include <QtTest/QtTest>

using namespace injeqt::internal;
using namespace injeqt::v1;

class type_1 : public QObject
{
	Q_OBJECT
};

class type_1_subtype_1 : public QObject
{
	Q_OBJECT
};

class type_2 : public QObject
{
	Q_OBJECT
};

class injected_type : public QObject
{
	Q_OBJECT

public:
	type_1 *_1 = nullptr;
	type_2 *_2 = nullptr;

public slots:
	INJEQT_SETTER void setter_1(type_1 *a) { _1 = a; }
	INJEQT_SETTER void setter_1_subtype_1(type_1_subtype_1 *) {}
	INJEQT_SETTER void setter_2(type_2 *a) { _2 = a; }

};

class resolved_dependency_test : public QObject
{
	Q_OBJECT

private slots:
	void should_properly_apply_on_valid_object();

};

void resolved_dependency_test::should_properly_apply_on_valid_object()
{
	auto object_1 = make_object<type_1>();
	auto object_2 = make_object<type_2>();
	auto apply_on_object = make_object<injected_type>();
	auto resolved_1 = resolved_dependency{implementation{make_type<type_1>(), object_1.get()}, make_setter_method<injected_type>("setter_1(type_1*)")};
	auto resolved_2 = resolved_dependency{implementation{make_type<type_2>(), object_2.get()}, make_setter_method<injected_type>("setter_2(type_2*)")};

	QCOMPARE(static_cast<QObject *>(nullptr), static_cast<injected_type *>(apply_on_object.get())->_1);
	QCOMPARE(static_cast<QObject *>(nullptr), static_cast<injected_type *>(apply_on_object.get())->_2);

	resolved_1.apply_on(apply_on_object.get());

	QCOMPARE(object_1.get(), static_cast<injected_type *>(apply_on_object.get())->_1);
	QCOMPARE(static_cast<QObject *>(nullptr), static_cast<injected_type *>(apply_on_object.get())->_2);

	resolved_2.apply_on(apply_on_object.get());

	QCOMPARE(object_1.get(), static_cast<injected_type *>(apply_on_object.get())->_1);
	QCOMPARE(object_2.get(), static_cast<injected_type *>(apply_on_object.get())->_2);
}

QTEST_APPLESS_MAIN(resolved_dependency_test)
#include "resolved-dependency-test.moc"
<|endoftext|>


<commit_before>//=============================================================================================================
/**
 * @file     main.cpp
 * @author   Ruben Dörfel <ruben.doerfel@tu-ilmenau.de>;
 * @version  dev
 * @date     February, 2020
 *
 * @section  LICENSE
 *
 * Copyright (C) 2020, Ruben Dörfel. All rights reserved.
 *
 * 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.
 *     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
 *       to endorse or promote products derived from this software without specific prior written permission.
 *
 * 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 COPYRIGHT OWNER 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.
 *
 *
 * @brief     Test for fitHpi function in inverse library.
 *
 */

///=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <iostream>
#include <vector>
#include <math.h>

#include <fiff/fiff.h>
#include <fiff/fiff_info.h>
#include <fiff/fiff_dig_point_set.h>
#include <fiff/fiff_cov.h>

#include <inverse/hpiFit/hpifit.h>
#include <inverse/hpiFit/hpifitdata.h>

#include <utils/ioutils.h>
#include <utils/generics/applicationlogger.h>

#include <fwd/fwd_coil_set.h>

#include <Eigen/Dense>
#include <Eigen/Geometry>
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QCommandLineParser>
#include <QDebug>
#include <QQuaternion>
#include <QtTest>

//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace FIFFLIB;
using namespace UTILSLIB;
using namespace INVERSELIB;
using namespace Eigen;
//=============================================================================================================
/**
 * DECLARE CLASS TestFiffRFR
 *
 * @brief The TestFitHPI class provides hpi fit verifivcation tests
 *
 */
class TestFitHPI: public QObject
{
    Q_OBJECT

public:
    TestFitHPI();

private slots:
    void initTestCase();
    void compareTranslation();
    void compareRotation();
    void compareTime();
    void cleanupTestCase();

private:
    double errorTrans = 0.0003;
    double errorQuat = 0.002;
    double errorTime = 0.00000001;
    MatrixXd ref_pos;
    MatrixXd hpi_pos;
};

//=============================================================================================================

TestFitHPI::TestFitHPI()
{
}

//=============================================================================================================

void TestFitHPI::initTestCase()
{
    qInstallMessageHandler(UTILSLIB::ApplicationLogger::customLogWriter);
    qInfo() << "Error Translation" << errorTrans;
    qInfo() << "Error Quaternion" << errorQuat;
    QFile t_fileIn(QCoreApplication::applicationDirPath() + "/mne-cpp-test-data/MEG/sample/test_hpiFit_raw.fif");

    // Make sure test folder exists
    QFileInfo t_fileInInfo(t_fileIn);
    QDir().mkdir(t_fileInInfo.path());

    printf(">>>>>>>>>>>>>>>>>>>>>>>>> Read Raw and HPI fit >>>>>>>>>>>>>>>>>>>>>>>>>\n");

    // Setup for reading the raw data
    FiffRawData raw;
    raw = FiffRawData(t_fileIn);
    QSharedPointer<FiffInfo> pFiffInfo = QSharedPointer<FIFFLIB::FiffInfo>(new FiffInfo(raw.info));

    // Only filter MEG channels
    RowVectorXi picks = raw.info.pick_types(true, false, false);
    RowVectorXd cals;

    // Set up the reading parameters
    fiff_int_t from;
    fiff_int_t to;
    fiff_int_t first = raw.first_samp;
    fiff_int_t last = raw.last_samp;
    MatrixXd matData, times;

    float quantum_sec = 0.2f;   //read and write in 200 ms junks
    fiff_int_t quantum = ceil(quantum_sec*pFiffInfo->sfreq);

    // Read Quaternion File from maxfilter
    UTILSLIB::IOUtils::read_eigen_matrix(ref_pos, QCoreApplication::applicationDirPath() + "/mne-cpp-test-data/Result/ref_hpiFit_pos.txt");

    // Setup informations for HPI fit
    QVector<int> vFreqs {166,154,161,158};
    QVector<double> vError;
    VectorXd vGoF;
    FiffDigPointSet fittedPointSet;
    Eigen::MatrixXd matProjectors = Eigen::MatrixXd::Identity(pFiffInfo->chs.size(), pFiffInfo->chs.size());
    QString sHPIResourceDir = QCoreApplication::applicationDirPath() + "/HPIFittingDebug";
    bool bDoDebug = true;

    for(int i = 0; i < ref_pos.rows(); i++) {
        from = first + ref_pos(i,0)*pFiffInfo->sfreq;
        to = from + quantum;
        if (to > last) {
            to = last;
        }
        qInfo()  << "Reading...";
        if(!raw.read_raw_segment(matData, times, from, to)) {
            qWarning("error during read_raw_segment\n");
        }

        qInfo()  << "HPI-Fit...";
        HPIFit::fitHPI(matData,
                       matProjectors,
                       pFiffInfo->dev_head_t,
                       vFreqs,
                       vError,
                       vGoF,
                       fittedPointSet,
                       pFiffInfo,
                       bDoDebug = 0,
                       sHPIResourceDir);
        qInfo() << "[done]\n";
        HPIFit::storeHeadPosition(ref_pos(i,0), pFiffInfo->dev_head_t.trans, hpi_pos, vGoF, vError);
    }
    // For debug: position file for HPIFit
    UTILSLIB::IOUtils::write_eigen_matrix(hpi_pos, QCoreApplication::applicationDirPath() + "/MNE-sample-data/hpi_pos.txt");
}

//=============================================================================================================

void TestFitHPI::compareTranslation()
{
    MatrixXd diff = MatrixXd::Zero(ref_pos.rows(),3);
    RowVector3d diff_trans;
    diff_trans(0) = (ref_pos.col(4)-hpi_pos.col(4)).mean();
    diff_trans(1) = (ref_pos.col(5)-hpi_pos.col(5)).mean();
    diff_trans(2) = (ref_pos.col(6)-hpi_pos.col(6)).mean();
    qDebug() << "errorTrans x: " << std::abs(diff_trans(0));
    qDebug() << "errorTrans y: " << std::abs(diff_trans(1));
    qDebug() << "errorTrans z: " << std::abs(diff_trans(2));
    QVERIFY(std::abs(diff_trans(0)) < errorTrans);
    QVERIFY(std::abs(diff_trans(1)) < errorTrans);
    QVERIFY(std::abs(diff_trans(2)) < errorTrans);
}

//=============================================================================================================

void TestFitHPI::compareRotation()
{
    MatrixXd diff = MatrixXd::Zero(ref_pos.rows(),3);
    RowVector3d diff_quat;
    diff_quat(0) = (ref_pos.col(1)-hpi_pos.col(1)).mean();
    diff_quat(1) = (ref_pos.col(2)-hpi_pos.col(2)).mean();
    diff_quat(2) = (ref_pos.col(3)-hpi_pos.col(3)).mean();
    qDebug() << "errorQuat q1: " <<std::abs(diff_quat(0));
    qDebug() << "errorQuat q2: " <<std::abs(diff_quat(1));
    qDebug() << "errorQuat q3: " <<std::abs(diff_quat(2));
    QVERIFY(std::abs(diff_quat(0)) < errorQuat);
    QVERIFY(std::abs(diff_quat(1)) < errorQuat);
    QVERIFY(std::abs(diff_quat(2)) < errorQuat);
}

//=============================================================================================================

void TestFitHPI::compareTime()
{
    MatrixXd diff = MatrixXd::Zero(ref_pos.rows(),1);
    diff.col(0) = ref_pos.col(0)-hpi_pos.col(0);
    float diff_t = diff.col(0).mean();
    qDebug() << "errorTime: " << diff_t;
    QVERIFY(std::abs(diff_t) < errorTime);
}

//=============================================================================================================

void TestFitHPI::cleanupTestCase()
{
}

//=============================================================================================================
// MAIN
//=============================================================================================================

QTEST_GUILESS_MAIN(TestFitHPI)
#include "test_hpiFit.moc"
<commit_msg>ENH: implement test for new functions<commit_after>//=============================================================================================================
/**
 * @file     main.cpp
 * @author   Ruben Dörfel <ruben.doerfel@tu-ilmenau.de>;
 * @version  dev
 * @date     February, 2020
 *
 * @section  LICENSE
 *
 * Copyright (C) 2020, Ruben Dörfel. All rights reserved.
 *
 * 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.
 *     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
 *       to endorse or promote products derived from this software without specific prior written permission.
 *
 * 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 COPYRIGHT OWNER 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.
 *
 *
 * @brief     Test for fitHpi function in inverse library.
 *
 */

///=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <iostream>
#include <vector>
#include <math.h>

#include <fiff/fiff.h>
#include <fiff/fiff_info.h>
#include <fiff/fiff_dig_point_set.h>
#include <fiff/fiff_cov.h>

#include <inverse/hpiFit/hpifit.h>
#include <inverse/hpiFit/hpifitdata.h>

#include <utils/ioutils.h>
#include <utils/generics/applicationlogger.h>
#include <utils/mnemath.h>

#include <fwd/fwd_coil_set.h>

#include <Eigen/Dense>
#include <Eigen/Geometry>
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QCommandLineParser>
#include <QDebug>
#include <QQuaternion>
#include <QtTest>

//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace FIFFLIB;
using namespace UTILSLIB;
using namespace INVERSELIB;
using namespace Eigen;
//=============================================================================================================
/**
 * DECLARE CLASS TestFiffRFR
 *
 * @brief The TestFitHPI class provides hpi fit verifivcation tests
 *
 */
class TestFitHPI: public QObject
{
    Q_OBJECT

public:
    TestFitHPI();

private slots:
    void initTestCase();
    void compareTranslation();
    void compareRotation();
    void compareAngle();
    void compareMove();
    void compareCompare();
    void compareTime();
    void cleanupTestCase();

private:
    double errorTrans = 0.0003;
    double errorQuat = 0.002;
    double errorTime = 0.00000001;
    double errorAngle = 0.1; // in degree
    double errorMove = 0.0003; // in m
    double errorCompare = 0;
    MatrixXd ref_pos;
    MatrixXd hpi_pos;
    MatrixXd ref_result;
    MatrixXd hpi_result;
};

//=============================================================================================================

TestFitHPI::TestFitHPI()
{
}

//=============================================================================================================

void TestFitHPI::initTestCase()
{
    qInstallMessageHandler(ApplicationLogger::customLogWriter);
    qInfo() << "Error Translation" << errorTrans;
    qInfo() << "Error Quaternion" << errorQuat;
    QFile t_fileIn(QCoreApplication::applicationDirPath() + "/mne-cpp-test-data/MEG/sample/test_hpiFit_raw.fif");

    // Make sure test folder exists
    QFileInfo t_fileInInfo(t_fileIn);
    QDir().mkdir(t_fileInInfo.path());

    printf(">>>>>>>>>>>>>>>>>>>>>>>>> Read Raw and HPI fit >>>>>>>>>>>>>>>>>>>>>>>>>\n");

    // Setup for reading the raw data
    FiffRawData raw;
    raw = FiffRawData(t_fileIn);
    QSharedPointer<FiffInfo> pFiffInfo = QSharedPointer<FIFFLIB::FiffInfo>(new FiffInfo(raw.info));

    // Only filter MEG channels
    RowVectorXi picks = raw.info.pick_types(true, false, false);
    RowVectorXd cals;

    FiffCoordTrans devHeadT = pFiffInfo->dev_head_t;

    // Set up the reading parameters
    fiff_int_t from;
    fiff_int_t to;
    fiff_int_t first = raw.first_samp;
    fiff_int_t last = raw.last_samp;
    MatrixXd matData, times;

    float quantum_sec = 0.2f;   //read and write in 200 ms junks
    fiff_int_t quantum = ceil(quantum_sec*pFiffInfo->sfreq);

    // Read Quaternion File from maxfilter and calculated movements/rotations with python
    IOUtils::read_eigen_matrix(ref_pos, QCoreApplication::applicationDirPath() + "/mne-cpp-test-data/Result/ref_hpiFit_pos.txt");
    IOUtils::read_eigen_matrix(ref_result, QCoreApplication::applicationDirPath() + "/mne-cpp-test-data/Result/ref_angle_move.txt");

    hpi_result = ref_result;

    // define thresholds for big head movement detection
    float threshRot = 2;
    float threshTrans = 0.002;

    // Setup informations for HPI fit
    QVector<int> vFreqs {166,154,161,158};
    QVector<double> vError;
    VectorXd vGoF;
    FiffDigPointSet fittedPointSet;
    Eigen::MatrixXd matProjectors = Eigen::MatrixXd::Identity(pFiffInfo->chs.size(), pFiffInfo->chs.size());
    QString sHPIResourceDir = QCoreApplication::applicationDirPath() + "/HPIFittingDebug";
    bool bDoDebug = true;

    for(int i = 0; i < ref_pos.rows(); i++) {
        from = first + ref_pos(i,0)*pFiffInfo->sfreq;
        to = from + quantum;
        if (to > last) {
            to = last;
        }
        qInfo()  << "Reading...";
        if(!raw.read_raw_segment(matData, times, from, to)) {
            qWarning("error during read_raw_segment\n");
        }

        qInfo()  << "HPI-Fit...";
        HPIFit::fitHPI(matData,
                       matProjectors,
                       pFiffInfo->dev_head_t,
                       vFreqs,
                       vError,
                       vGoF,
                       fittedPointSet,
                       pFiffInfo,
                       bDoDebug = 0,
                       sHPIResourceDir);
        qInfo() << "[done]\n";

        if(MNEMath::compareTransformation(devHeadT.trans, pFiffInfo->dev_head_t.trans, threshRot, threshTrans)) {
            hpi_result(i,2) = 1;
        }

        HPIFit::storeHeadPosition(ref_pos(i,0), pFiffInfo->dev_head_t.trans, hpi_pos, vGoF, vError);
        hpi_result(i,0) = devHeadT.translationTo(pFiffInfo->dev_head_t.trans);
        hpi_result(i,1) = devHeadT.angleTo(pFiffInfo->dev_head_t.trans);

    }
    // For debug: position file for HPIFit
//    UTILSLIB::IOUtils::write_eigen_matrix(hpi_pos, QCoreApplication::applicationDirPath() + "/MNE-sample-data/hpi_pos.txt");
}

//=============================================================================================================

void TestFitHPI::compareTranslation()
{
    MatrixXd diff = MatrixXd::Zero(ref_pos.rows(),3);
    RowVector3d diff_trans;
    diff_trans(0) = (ref_pos.col(4)-hpi_pos.col(4)).mean();
    diff_trans(1) = (ref_pos.col(5)-hpi_pos.col(5)).mean();
    diff_trans(2) = (ref_pos.col(6)-hpi_pos.col(6)).mean();
    qDebug() << "errorTrans x: " << std::abs(diff_trans(0));
    qDebug() << "errorTrans y: " << std::abs(diff_trans(1));
    qDebug() << "errorTrans z: " << std::abs(diff_trans(2));
    QVERIFY(std::abs(diff_trans(0)) < errorTrans);
    QVERIFY(std::abs(diff_trans(1)) < errorTrans);
    QVERIFY(std::abs(diff_trans(2)) < errorTrans);
}

//=============================================================================================================

void TestFitHPI::compareRotation()
{
    MatrixXd diff = MatrixXd::Zero(ref_pos.rows(),3);
    RowVector3d diff_quat;
    diff_quat(0) = (ref_pos.col(1)-hpi_pos.col(1)).mean();
    diff_quat(1) = (ref_pos.col(2)-hpi_pos.col(2)).mean();
    diff_quat(2) = (ref_pos.col(3)-hpi_pos.col(3)).mean();
    qDebug() << "errorQuat q1: " <<std::abs(diff_quat(0));
    qDebug() << "errorQuat q2: " <<std::abs(diff_quat(1));
    qDebug() << "errorQuat q3: " <<std::abs(diff_quat(2));
    QVERIFY(std::abs(diff_quat(0)) < errorQuat);
    QVERIFY(std::abs(diff_quat(1)) < errorQuat);
    QVERIFY(std::abs(diff_quat(2)) < errorQuat);
}

//=============================================================================================================

void TestFitHPI::compareMove()
{
    MatrixXd diff = MatrixXd::Zero(ref_result.rows(),1);
    float diffMove = (ref_result.col(0)-hpi_result.col(0)).mean();
    diffMove = std::abs(diffMove);
    qDebug() << "diffMove: [m]" << diffMove;

    QVERIFY(std::abs(diffMove) < errorMove);
}

//=============================================================================================================

void TestFitHPI::compareAngle()
{
    MatrixXd diff = MatrixXd::Zero(ref_result.rows(),1);
    float diffAngle = (ref_result.col(1)-ref_result.col(1)).mean();
    diffAngle = std::abs(diffAngle);
    qDebug() << "diffAngle: [degree]" << diffAngle;

    QVERIFY(std::abs(diffAngle) < errorAngle);
}

//=============================================================================================================

void TestFitHPI::compareCompare()
{
    MatrixXd diff = MatrixXd::Zero(ref_result.rows(),1);
    float diffCompare = (ref_result.col(2)-ref_result.col(2)).mean();
    diffCompare = std::abs(diffCompare);

    qDebug() << "diffCompare: " << diffCompare;
    QVERIFY(std::abs(diffCompare) == errorCompare);
}

//=============================================================================================================

void TestFitHPI::compareTime()
{
    MatrixXd diff = MatrixXd::Zero(ref_pos.rows(),1);
    diff.col(0) = ref_pos.col(0)-hpi_pos.col(0);
    float diff_t = diff.col(0).mean();
    qDebug() << "errorTime: " << diff_t;
    QVERIFY(std::abs(diff_t) < errorTime);
}

//=============================================================================================================

void TestFitHPI::cleanupTestCase()
{
}

//=============================================================================================================
// MAIN
//=============================================================================================================

QTEST_GUILESS_MAIN(TestFitHPI)
#include "test_hpiFit.moc"
<|endoftext|>