Commit 1c5a0796 authored by Paul Asmuth's avatar Paul Asmuth
Browse files

use UnitTest framework in QueryTest

parent 457265d7
Loading
Loading
Loading
Loading
+819 −864
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <assert.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <fnordmetric/util/unittest.h>
#include <fnordmetric/query/query.h>
#include <fnordmetric/query/parser.h>
#include <fnordmetric/query/token.h>
@@ -20,59 +21,65 @@
#include <fnordmetric/query/tablerepository.h>
#include <fnordmetric/query/resultlist.h>

namespace fnordmetric {
//namespace fnordmetric {

using namespace fnordmetric::query;

class QueryTest {
public:
  QueryTest() {}

  void run() {
    //testTokenizerSimple();
    //testTokenizerEscaping();
    //testTokenizerAsClause();
    //testSelectMustBeFirstAssert();
    testSelectWildcard();
    testSelectTableWildcard();
    testSelectDerivedColumn();
    testSelectDerivedColumnWithTableName();
    testSimpleValueExpression();
    testArithmeticValueExpression();
    testArithmeticValueExpressionParens();
    testArithmeticValueExpressionPrecedence();
    testNegatedValueExpression();
    testMethodCallValueExpression();
    testFromList();
    testWhereClause();
    testGroupByClause();
    testOrderByClause();
    testHavingClause();
    testLimitClause();
    testLimitOffsetClause();
    testComplexQueries();
    //testSeriesStatement();
    //testDerivedSeriesStatement();
    testSelectOnlyQuery();
    testSimpleTableScanQuery();
    testTableScanWhereQuery();
    testTableScanWhereLimitQuery();
    testTableScanGroupByQuery();
    testTableScanGroupByCountQuery();
    testTableScanGroupBySumQuery();
    testTableScanGroupWithoutGroupClause();
    //testNamedSeriesQuery();
    //testDerivedSeriesQuery();
    testSimpleDrawQuery();
    testDerivedSeriesDrawQuery();
  }
UNIT_TEST(QueryTest);

  Parser parseTestQuery(const char* query) {
static Parser parseTestQuery(const char* query) {
  Parser parser;
  parser.parse(query, strlen(query));
  return parser;
}

  void testSimpleValueExpression() {
class TestTableRef : public TableRef {
  int getColumnIndex(const std::string& name) override {
    if (name == "one") return 0;
    if (name == "two") return 1;
    if (name == "three") return 2;
    return -1;
  }
  void executeScan(TableScan* scan) override {
    int64_t one = 0;
    int64_t two = 100;
    for (int i = two; i > 0; --i) {
      std::vector<SValue> row;
      row.emplace_back(SValue(++one));
      row.emplace_back(SValue(two--));
      row.emplace_back(SValue((int64_t) (i % 2 ? 10 : 20)));
      if (!scan->nextRow(row.data(), row.size())) {
        return;
      }
    }
  }
};

class TestTable2Ref : public TableRef {
  int getColumnIndex(const std::string& name) override {
    if (name == "one") return 0;
    if (name == "two") return 1;
    if (name == "three") return 2;
    return -1;
  }
  void executeScan(TableScan* scan) override {
    for (int i = 10; i > 0; --i) {
      std::vector<SValue> row;
      row.emplace_back(SValue((int64_t) i));
      row.emplace_back(SValue((int64_t) (i * 2)));
      row.emplace_back(SValue((int64_t) (i % 2 ? 100 : 200)));
      if (!scan->nextRow(row.data(), row.size())) {
        return;
      }
    }
  }
};



// TEST_CASE(CSVInputStreamTest, TestOpenFile, [] () {

TEST_CASE(QueryTest, TestSimpleValueExpression, [] () {
  auto parser = parseTestQuery("SELECT 23 + 5.123 FROM sometable;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -96,9 +103,9 @@ public:
  assert(*expr->getChildren()[1]->getToken() == "5.123");
  const auto& from = stmt->getChildren()[1];
  assert(*from == ASTNode::T_FROM);
  }
});

  void testArithmeticValueExpression() {
TEST_CASE(QueryTest, TestArithmeticValueExpression, [] () {
  auto parser = parseTestQuery("SELECT 1 + 2 / 3;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -111,9 +118,9 @@ public:
  assert(*expr->getChildren()[0]->getToken() == "1");
  assert(*expr->getChildren()[1] == ASTNode::T_DIV_EXPR);
  assert(expr->getChildren()[1]->getChildren().size() == 2);
  }
});

  void testArithmeticValueExpressionParens() {
TEST_CASE(QueryTest, TestArithmeticValueExpressionParens, [] () {
  auto parser = parseTestQuery("SELECT (1 * 2) + 3;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -126,9 +133,9 @@ public:
  assert(*expr->getChildren()[1] == ASTNode::T_LITERAL);
  assert(*expr->getChildren()[1]->getToken() == Token::T_NUMERIC);
  assert(*expr->getChildren()[1]->getToken() == "3");
  }
});

  void testArithmeticValueExpressionPrecedence() {
TEST_CASE(QueryTest, TestArithmeticValueExpressionPrecedence, [] () {
  {
    auto parser = parseTestQuery("SELECT 1 * 2 + 3;");
    assert(parser.getErrors().size() == 0);
@@ -157,9 +164,9 @@ public:
    assert(*expr->getChildren()[1] == ASTNode::T_MUL_EXPR);
    assert(expr->getChildren()[1]->getChildren().size() == 2);
  }
  }
});

  void testMethodCallValueExpression() {
TEST_CASE(QueryTest, TestMethodCallValueExpression, [] () {
  auto parser = parseTestQuery("SELECT 1 + sum(23, 4 + 1) FROM sometable;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -190,9 +197,9 @@ public:
  assert(mcall->getChildren()[1]->getChildren().size() == 2);
  const auto& from = stmt->getChildren()[1];
  assert(*from == ASTNode::T_FROM);
  }
});

  void testNegatedValueExpression() {
TEST_CASE(QueryTest, TestNegatedValueExpression, [] () {
  auto parser = parseTestQuery("SELECT -(23 + 5.123) AS fucol FROM tbl;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -223,9 +230,9 @@ public:
  assert(*col_name->getToken() == "fucol");
  const auto& from = stmt->getChildren()[1];
  assert(*from == ASTNode::T_FROM);
  }
});

  void testSelectWildcard() {
TEST_CASE(QueryTest, TestSelectWildcard, [] () {
  auto parser = parseTestQuery("SELECT * FROM sometable;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -239,9 +246,9 @@ public:
  assert(sl->getChildren()[0]->getToken() == nullptr);
  const auto& from = stmt->getChildren()[1];
  assert(*from == ASTNode::T_FROM);
  }
});

  void testSelectTableWildcard() {
TEST_CASE(QueryTest, TestSelectTableWildcard, [] () {
  auto parser = parseTestQuery("SELECT mytablex.* FROM sometable;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -258,9 +265,9 @@ public:
  assert(*all->getToken() == "mytablex");
  const auto& from = stmt->getChildren()[1];
  assert(*from == ASTNode::T_FROM);
  }
});

  void testSelectDerivedColumn() {
TEST_CASE(QueryTest, TestSelectDerivedColumn, [] () {
  auto parser = parseTestQuery("SELECT somecol AS another FROM sometable;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -281,9 +288,9 @@ public:
  assert(*derived->getChildren()[1]->getToken() == "another");
  const auto& from = stmt->getChildren()[1];
  assert(*from == ASTNode::T_FROM);
  }
});

  void testSelectDerivedColumnWithTableName() {
TEST_CASE(QueryTest, TestSelectDerivedColumnWithTableName, [] () {
  auto parser = parseTestQuery("SELECT tbl.col AS another FROM sometable;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -312,15 +319,15 @@ public:
  assert(*derived->getChildren()[1]->getToken() == "another");
  const auto& from = stmt->getChildren()[1];
  assert(*from == ASTNode::T_FROM);
  }
});

  void testSelectMustBeFirstAssert() {
TEST_CASE(QueryTest, TestSelectMustBeFirstAssert, [] () {
  auto parser = parseTestQuery("GROUP BY SELECT");
  assert(parser.getErrors().size() == 1);
  assert(parser.getErrors()[0].type == Parser::ERR_UNEXPECTED_TOKEN);
  }
});

  void testFromList() {
TEST_CASE(QueryTest, TestFromList, [] () {
  auto parser = parseTestQuery("SELECT a FROM tbl1, tbl2;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -332,9 +339,9 @@ public:
  assert(*from->getChildren()[0]->getToken() == "tbl1");
  assert(*from->getChildren()[1] == ASTNode::T_TABLE_NAME);
  assert(*from->getChildren()[1]->getToken() == "tbl2");
  }
});

  void testWhereClause() {
TEST_CASE(QueryTest, TestWhereClause, [] () {
  auto parser = parseTestQuery("SELECT x FROM t WHERE a=1 AND a+1=2 OR b=3;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -344,9 +351,9 @@ public:
  assert(*where == ASTNode::T_WHERE);
  assert(where->getChildren().size() == 1);
  assert(*where->getChildren()[0] == ASTNode::T_OR_EXPR);
  }
});

  void testGroupByClause() {
TEST_CASE(QueryTest, TestGroupByClause, [] () {
  auto parser = parseTestQuery("select count(x), y from t GROUP BY x;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -356,9 +363,9 @@ public:
  assert(*where == ASTNode::T_GROUP_BY);
  assert(where->getChildren().size() == 1);
  assert(*where->getChildren()[0] == ASTNode::T_COLUMN_NAME);
  }
});

  void testOrderByClause() {
TEST_CASE(QueryTest, TestOrderByClause, [] () {
  auto parser = parseTestQuery("select a FROM t ORDER BY a DESC;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -369,9 +376,9 @@ public:
  assert(order_by->getChildren().size() == 1);
  assert(*order_by->getChildren()[0] == ASTNode::T_SORT_SPEC);
  assert(*order_by->getChildren()[0]->getToken() == Token::T_DESC);
  }
});

  void testHavingClause() {
TEST_CASE(QueryTest, TestHavingClause, [] () {
  auto parser = parseTestQuery("select a FROM t HAVING 1=1;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -381,9 +388,9 @@ public:
  assert(*having == ASTNode::T_HAVING);
  assert(having->getChildren().size() == 1);
  assert(*having->getChildren()[0] == ASTNode::T_EQ_EXPR);
  }
});

  void testLimitClause() {
TEST_CASE(QueryTest, TestLimitClause, [] () {
  auto parser = parseTestQuery("select a FROM t LIMIT 10;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -393,9 +400,9 @@ public:
  assert(*limit == ASTNode::T_LIMIT);
  assert(limit->getChildren().size() == 0);
  assert(*limit->getToken() == "10");
  }
});

  void testLimitOffsetClause() {
TEST_CASE(QueryTest, TestLimitOffsetClause, [] () {
  auto parser = parseTestQuery("select a FROM t LIMIT 10 OFFSET 23;");
  assert(parser.getErrors().size() == 0);
  assert(parser.getStatements().size() == 1);
@@ -407,9 +414,9 @@ public:
  assert(*limit->getToken() == "10");
  assert(*limit->getChildren()[0] == ASTNode::T_OFFSET);
  assert(*limit->getChildren()[0]->getToken() == "23");
  }
});

  void testTokenizerEscaping() {
TEST_CASE(QueryTest, TestTokenizerEscaping, [] () {
  auto parser = parseTestQuery(" SELECT  fnord,sum(blah) from fubar blah.id"
      "= 'fnor\\'dbar' + 123.5;");
  const auto& tl = parser.getTokenList();
@@ -439,9 +446,9 @@ public:
  assert(tl[15].getType() == Token::T_NUMERIC);
  assert(tl[15] == "123.5");
  assert(tl[16].getType() == Token::T_SEMICOLON);
  }
});

  void testTokenizerSimple() {
TEST_CASE(QueryTest, TestTokenizerSimple, [] () {
  auto parser = parseTestQuery(" SELECT  fnord,sum(`blah-field`) from fubar"
      " WHERE blah.id= \"fn'o=,rdbar\" + 123;");
  auto tl = &parser.getTokenList();
@@ -470,9 +477,9 @@ public:
  //assert((*tl)[15].getType() == Token::T_NUMERIC);
  //assert((*tl)[15] == "123");
  //assert((*tl)[16].getType() == Token::T_SEMICOLON);
  }
});

  void testTokenizerAsClause() {
TEST_CASE(QueryTest, TestTokenizerAsClause, [] () {
  auto parser = parseTestQuery(" SELECT fnord As blah from");
  auto tl = &parser.getTokenList();
  assert((*tl)[0].getType() == Token::T_SELECT);
@@ -481,10 +488,10 @@ public:
  assert((*tl)[2].getType() == Token::T_AS);
  assert((*tl)[3].getType() == Token::T_IDENTIFIER);
  assert((*tl)[3] == "blah");
  }
});


  void testComplexQueries() {
TEST_CASE(QueryTest, TestComplexQueries, [] () {
  std::vector<const char*> queries;
  queries.push_back("SELECT -sum(fnord) + (123 * 4);");
  queries.push_back("SELECT (-blah + sum(fnord) / (123 * 4)) as myfield;");
@@ -519,9 +526,9 @@ public:
    assert(parser.getErrors().size() == 0);
    assert(parser.getStatements().size() == 1);
  }
  }
});

  void testSeriesStatement() {
TEST_CASE(QueryTest, TestSeriesStatement, [] () {
  auto parser = parseTestQuery(
      "  SERIES \"myseries\" FROM"
      "    SELECT * FROM tbl;");
@@ -539,9 +546,9 @@ public:
  const auto& select = stmt->getChildren()[1];
  assert(*select == ASTNode::T_SELECT);
  assert(select->getChildren().size() == 2);
  }
});

  void testDerivedSeriesStatement() {
TEST_CASE(QueryTest, TestDerivedSeriesStatement, [] () {
  auto parser = parseTestQuery(
      "  SERIES fnord FROM"
      "    SELECT fnord, blah FROM tbl;");
@@ -559,9 +566,9 @@ public:
  const auto& select = stmt->getChildren()[1];
  assert(*select == ASTNode::T_SELECT);
  assert(select->getChildren().size() == 2);
  }
});

  void testSelectOnlyQuery() {
TEST_CASE(QueryTest, TestSelectOnlyQuery, [] () {
  TableRepository repo;
  std::vector<std::unique_ptr<Query>> dst;

@@ -593,51 +600,9 @@ public:
  //assert(row[3] == "true");
  //assert(row[4] == "false");
  //assert(row[5] == "true");
  }
});

  class TestTableRef : public TableRef {
    int getColumnIndex(const std::string& name) override {
      if (name == "one") return 0;
      if (name == "two") return 1;
      if (name == "three") return 2;
      return -1;
    }
    void executeScan(TableScan* scan) override {
      int64_t one = 0;
      int64_t two = 100;
      for (int i = two; i > 0; --i) {
        std::vector<SValue> row;
        row.emplace_back(SValue(++one));
        row.emplace_back(SValue(two--));
        row.emplace_back(SValue((int64_t) (i % 2 ? 10 : 20)));
        if (!scan->nextRow(row.data(), row.size())) {
          return;
        }
      }
    }
  };

  class TestTable2Ref : public TableRef {
    int getColumnIndex(const std::string& name) override {
      if (name == "one") return 0;
      if (name == "two") return 1;
      if (name == "three") return 2;
      return -1;
    }
    void executeScan(TableScan* scan) override {
      for (int i = 10; i > 0; --i) {
        std::vector<SValue> row;
        row.emplace_back(SValue((int64_t) i));
        row.emplace_back(SValue((int64_t) (i * 2)));
        row.emplace_back(SValue((int64_t) (i % 2 ? 100 : 200)));
        if (!scan->nextRow(row.data(), row.size())) {
          return;
        }
      }
    }
  };

  void testSimpleTableScanQuery() {
TEST_CASE(QueryTest, TestSimpleTableScanQuery, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTableRef()));
@@ -656,9 +621,9 @@ public:
    assert(atoi(row[0].c_str()) == 51 + i);
    assert(atoi(row[1].c_str()) == 100 - i);
  }
  }
});

  void testTableScanWhereQuery() {
TEST_CASE(QueryTest, TestTableScanWhereQuery, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTableRef()));
@@ -676,9 +641,9 @@ public:
  query.execute();
  auto results = query.getResultList(0);
  assert(results->getNumRows() == 51);
  }
});

  void testTableScanWhereLimitQuery() {
TEST_CASE(QueryTest, TestTableScanWhereLimitQuery, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTableRef()));
@@ -700,12 +665,12 @@ public:
  const auto& row = results->getRow(0);
  assert(row[0] == "56");
  assert(row[1] == "46");
  }
});

// select count(*), one, two, three from testtable2 group by case three when
// 200 then 100 else 100 end;

  void testTableScanGroupByQuery() {
TEST_CASE(QueryTest, TestTableScanGroupByQuery, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTable2Ref()));
@@ -725,9 +690,9 @@ public:
  query.execute();
  auto results = query.getResultList(0);
  assert(results->getNumRows() == 4);
  }
});

  void testTableScanGroupByCountQuery() {
TEST_CASE(QueryTest, TestTableScanGroupByCountQuery, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTable2Ref()));
@@ -753,9 +718,9 @@ public:
    sum += atoi(row[0].c_str());
  }
  assert(sum == 10);
  }
});

  void testTableScanGroupBySumQuery() {
TEST_CASE(QueryTest, TestTableScanGroupBySumQuery, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTable2Ref()));
@@ -779,9 +744,9 @@ public:
      (atoi(row[0].c_str()) == 25 && atoi(row[1].c_str()) == 100) ||
      (atoi(row[0].c_str()) == 30 && atoi(row[1].c_str()) == 200));
  }
  }
});

  void testTableScanGroupWithoutGroupClause() {
TEST_CASE(QueryTest, TestTableScanGroupWithoutGroupClause, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTable2Ref()));
@@ -797,9 +762,9 @@ public:
  auto results = query.getResultList(0);
  assert(results->getNumRows() == 1);
  assert(results->getRow(0)[0] == "55");
  }
});

  void testNamedSeriesQuery() {
TEST_CASE(QueryTest, TestNamedSeriesQuery, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTable2Ref()));
@@ -822,9 +787,9 @@ public:
    assert(atoi(row[1].c_str()) == 10 - i);
    assert(atoi(row[2].c_str()) == 20 - i * 2);
  }
  }
});

  void testDerivedSeriesQuery() {
TEST_CASE(QueryTest, TestDerivedSeriesQuery, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTable2Ref()));
@@ -845,9 +810,9 @@ public:
    const auto& row = results->getRow(i);
    assert(atoi(row[0].c_str()) == atoi(row[1].c_str()) * 5);
  }
  }
});

  void testSimpleDrawQuery() {
TEST_CASE(QueryTest, TestSimpleDrawQuery, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTable2Ref()));
@@ -881,9 +846,9 @@ public:
  query.execute();
  auto chart = query.getChart(0);
  //chart->renderSVG();
  }
});

  void testDerivedSeriesDrawQuery() {
TEST_CASE(QueryTest, TestDerivedSeriesDrawQuery, [] () {
  TableRepository repo;
  repo.addTableRef("testtable",
      std::unique_ptr<TableRef>(new TestTable2Ref()));
@@ -904,14 +869,4 @@ public:
  query.execute();
  auto chart = query.getChart(0);
  //chart->renderSVG();
  }

};

}

int main() {
  fnordmetric::QueryTest test;
  test.run();
  printf("all tests passed! :)\n");
}
});