From af1462f955b484756bba318d744e72792b1d8874 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Fri, 6 Feb 2015 00:51:02 +0100 Subject: [PATCH] ui: fixed autocompletion issues * click in autocompletions list causes search * right arrow for autocompletion * changed query operator has from '>' to '.' and operator sub from '.' to '+' * fixed autocompletions to fit to query and * fixed spectral layouting endless looping on unconnected node --- bin/test/data/log/test_log.txt | 44 ++++----- src/app/qt/element/QtSmartSearchBox.cpp | 69 ++++++++++---- src/app/qt/element/QtSmartSearchBox.h | 5 +- .../component/controller/GraphLayouter.cpp | 11 +++ src/lib/data/Storage.cpp | 95 ++++++++++--------- src/lib/data/Storage.h | 3 +- .../graph/filter/GraphFilterConductor.cpp | 5 + src/lib/data/query/QueryOperator.cpp | 4 +- src/lib/data/search/SearchNode.cpp | 15 ++- src/lib/data/search/SearchNode.h | 3 +- src/lib/data/search/SearchResult.cpp | 4 +- src/lib/utility/utilityString.cpp | 8 ++ src/lib/utility/utilityString.h | 1 + src/test/GraphFilterConductorTestSuite.h | 6 +- src/test/QueryTreeTestSuite.h | 52 +++++----- src/test/UtilityStringTestSuite.h | 7 ++ 16 files changed, 206 insertions(+), 126 deletions(-) diff --git a/bin/test/data/log/test_log.txt b/bin/test/data/log/test_log.txt index 2bfb2e81..41b51725 100644 --- a/bin/test/data/log/test_log.txt +++ b/bin/test/data/log/test_log.txt @@ -1,4 +1,25 @@ ConfigManager.cpp ERROR: value path/to/nowhere is not present in config. +Token.cpp ERROR: Location Id was not referenced by this Token. +Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class +Edge.cpp ERROR: Nodes are not plain copies. +Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined +Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined +Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined +Storage.cpp INFO: class: A +Storage.cpp INFO: method: A::A +Storage.cpp INFO: global usage: A::A -> A::count +Storage.cpp INFO: method: A::getCount +Storage.cpp INFO: global usage: A::getCount -> A::count +Storage.cpp INFO: method: A::process +Storage.cpp INFO: field: A::count +Storage.cpp INFO: class: B +Storage.cpp INFO: inheritance: B : A +Storage.cpp INFO: method: B::process +Storage.cpp INFO: type usage: B::process -> int +Storage.cpp INFO: function: main +Storage.cpp INFO: type usage: main -> B +Storage.cpp INFO: call: main -> B::B +Storage.cpp INFO: call: main -> A::getCount Storage.cpp INFO: class: A Storage.cpp INFO: method: A::A Storage.cpp INFO: global usage: A::A -> A::count @@ -31,27 +52,6 @@ SearchMatch.cpp INFO: 237 A::A ^^^^ -Storage.cpp INFO: class: A -Storage.cpp INFO: method: A::A -Storage.cpp INFO: global usage: A::A -> A::count -Storage.cpp INFO: method: A::getCount -Storage.cpp INFO: global usage: A::getCount -> A::count -Storage.cpp INFO: method: A::process -Storage.cpp INFO: field: A::count -Storage.cpp INFO: class: B -Storage.cpp INFO: inheritance: B : A -Storage.cpp INFO: method: B::process -Storage.cpp INFO: type usage: B::process -> int -Storage.cpp INFO: function: main -Storage.cpp INFO: type usage: main -> B -Storage.cpp INFO: call: main -> B::B -Storage.cpp INFO: call: main -> A::getCount -Token.cpp ERROR: Location Id was not referenced by this Token. -Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class -Edge.cpp ERROR: Nodes are not plain copies. -Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined -Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined -Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined Settings.cpp WARNING: File for Settings not found. ConfigManager.cpp ERROR: value Bool is not present in config. ConfigManager.cpp ERROR: value Int is not present in config. @@ -67,7 +67,6 @@ ConfigManager.cpp ERROR: value Int is not present in config. ConfigManager.cpp ERROR: value Float is not present in config. ConfigManager.cpp ERROR: value String is not present in config. ConfigManager.cpp ERROR: value NewBool is not present in config. -Graph.cpp ERROR: Can't remove member edge, without removing the child node. Storage.cpp INFO: typedef: type -> int Storage.cpp INFO: class: Class Storage.cpp INFO: struct: Struct @@ -120,6 +119,7 @@ Storage.cpp INFO: call: main -> isTrue Storage.cpp INFO: function: isTrue Storage.cpp INFO: function: main Storage.cpp INFO: call: main -> isTrue +Graph.cpp ERROR: Can't remove member edge, without removing the child node. TextAccess.cpp WARNING: Index 'firstLine' has to be lower or equal index 'lastLine', is 3 > 2 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 diff --git a/src/app/qt/element/QtSmartSearchBox.cpp b/src/app/qt/element/QtSmartSearchBox.cpp index 56a9bc45..505077b4 100644 --- a/src/app/qt/element/QtSmartSearchBox.cpp +++ b/src/app/qt/element/QtSmartSearchBox.cpp @@ -28,12 +28,6 @@ void QtQueryElement::onChecked(bool) } -void QtSmartSearchBox::search() -{ - editTextToElement(); - MessageSearch(utility::join(m_tokens, "") + text().toStdString()).dispatch(); -} - QtSmartSearchBox::QtSmartSearchBox(QWidget* parent) : QLineEdit(parent) , m_allowTextChange(false) @@ -45,7 +39,6 @@ QtSmartSearchBox::QtSmartSearchBox(QWidget* parent) m_highlightRect->setGeometry(0, 0, 0, 0); m_highlightRect->setObjectName("search_box_highlight"); - connect(this, SIGNAL(returnPressed()), this, SLOT(search()), Qt::QueuedConnection); connect(this, SIGNAL(textEdited(const QString&)), this, SLOT(onTextEdited(const QString&))); connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(onTextChanged(const QString&))); @@ -66,6 +59,11 @@ void QtSmartSearchBox::setAutocompletionList(const std::vector& aut connect(completer, SIGNAL(matchHighlighted(const SearchMatch&)), this, SLOT(onAutocompletionHighlighted(const SearchMatch&)), Qt::DirectConnection); connect(completer, SIGNAL(matchActivated(const SearchMatch&)), this, SLOT(onAutocompletionActivated(const SearchMatch&)), Qt::DirectConnection); + + if (autocompletionList.size()) + { + m_highlightedMatch = *completer->getSearchMatchAt(0); + } } void QtSmartSearchBox::setQuery(const std::string& text) @@ -84,14 +82,27 @@ void QtSmartSearchBox::setFocus() layoutElements(); } +void QtSmartSearchBox::search() +{ + editTextToElement(); + MessageSearch(utility::join(m_tokens, "") + text().toStdString()).dispatch(); +} + bool QtSmartSearchBox::event(QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Tab && completer()->popup()->isVisible()) + if (keyEvent->key() == Qt::Key_Tab) { - onAutocompletionActivated(m_highlightedMatch); + if (completer()->popup()->isVisible()) + { + searchMatchToToken(m_highlightedMatch); + } + else + { + requestAutoCompletions(); + } return true; } } @@ -109,7 +120,14 @@ void QtSmartSearchBox::keyPressEvent(QKeyEvent* event) { m_shiftKeyDown = event->modifiers() & Qt::ShiftModifier; - if (event->key() == Qt::Key_Backspace) + if (event->key() == Qt::Key_Return) + { + if (!completer()->popup()->isVisible()) + { + search(); + } + } + else if (event->key() == Qt::Key_Backspace) { if (hasSelectedElements()) { @@ -162,9 +180,13 @@ void QtSmartSearchBox::keyPressEvent(QKeyEvent* event) selectAllElementsWith(false); layoutElements(); } - else if (cursorPosition() == text().size() && (text().size() || m_cursorIndex < m_elements.size())) + else if (cursorPosition() == text().size()) { - if (!editTextToElement()) + if (completer()->popup()->isVisible()) + { + searchMatchToToken(m_highlightedMatch); + } + else if (!editTextToElement()) { moveCursor(1); } @@ -375,14 +397,11 @@ void QtSmartSearchBox::onAutocompletionHighlighted(const SearchMatch& match) void QtSmartSearchBox::onAutocompletionActivated(const SearchMatch& match) { + searchMatchToToken(match); + if (match.fullName.size()) { - m_oldText.clear(); - clearLineEdit(); - - std::string name = match.encodeForQuery(); - textToToken(name); - updateElements(); + search(); } } @@ -443,6 +462,7 @@ void QtSmartSearchBox::moveCursorTo(int target) { m_cursorIndex = target; layoutElements(); + hideAutoCompletions(); } } @@ -466,6 +486,19 @@ void QtSmartSearchBox::textToToken(std::string text) m_cursorIndex++; } +void QtSmartSearchBox::searchMatchToToken(const SearchMatch& match) +{ + if (match.fullName.size()) + { + m_oldText.clear(); + clearLineEdit(); + + std::string name = match.encodeForQuery(); + textToToken(name); + updateElements(); + } +} + void QtSmartSearchBox::setEditText(const QString& text) { m_allowTextChange = true; diff --git a/src/app/qt/element/QtSmartSearchBox.h b/src/app/qt/element/QtSmartSearchBox.h index 1253347e..b4ac740d 100644 --- a/src/app/qt/element/QtSmartSearchBox.h +++ b/src/app/qt/element/QtSmartSearchBox.h @@ -31,9 +31,6 @@ class QtSmartSearchBox { Q_OBJECT -public slots: - void search(); - public: QtSmartSearchBox(QWidget* parent); virtual ~QtSmartSearchBox(); @@ -41,6 +38,7 @@ public: void setAutocompletionList(const std::vector& autocompletionList); void setQuery(const std::string& text); void setFocus(); + void search(); protected: virtual bool event(QEvent *event); @@ -66,6 +64,7 @@ private: void moveCursorTo(int goal); void textToToken(std::string text); + void searchMatchToToken(const SearchMatch& match); void setEditText(const QString& text); bool editTextToElement(); void editElement(QtQueryElement* element); diff --git a/src/lib/component/controller/GraphLayouter.cpp b/src/lib/component/controller/GraphLayouter.cpp index 7ce7555a..e3db2be5 100644 --- a/src/lib/component/controller/GraphLayouter.cpp +++ b/src/lib/component/controller/GraphLayouter.cpp @@ -76,6 +76,17 @@ void GraphLayouter::layoutSpectralPrototype(std::vector& nodes, const MatrixDynamicBase laplacian = buildLaplacianMatrix(nodes, edges); + // If the laplacian matrix has a zero value in it's diagonal, that means there are unconnected nodes and the spectral + // layouting fails for some reason. In this case we switch to raster layout. + for (unsigned int i = 0; i < laplacian.getColumnsCount(); i++) + { + if (laplacian.getValue(i, i) == 0) + { + layoutSimpleRaster(nodes); + return; + } + } + Eigen::MatrixXd degreeMatrix = Eigen::MatrixXd::Zero(laplacian.getColumnsCount(), laplacian.getRowsCount()); Eigen::MatrixXd eigenMatrix = Eigen::MatrixXd::Zero(laplacian.getColumnsCount(), laplacian.getRowsCount()); diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index f95feacd..e4e46d37 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -590,18 +590,17 @@ std::string Storage::getNameForNodeWithId(Id id) const } } -std::vector Storage::getAutocompletionMatches( - const std::string& query, const std::string& word) const +std::vector Storage::getAutocompletionMatches(const std::string& query, const std::string& word) const { SearchResults tokenResults; - bool usedSubquery = false; + bool hasQueryResults = false; if (query.size()) { - usedSubquery = getSubQuerySearchResults(query, word, &tokenResults); + hasQueryResults = getQuerySearchResults(query, word, &tokenResults); } - if (!usedSubquery && word.size()) + if (!hasQueryResults && word.size()) { tokenResults = m_tokenIndex.runFuzzySearch(word); } @@ -692,28 +691,28 @@ std::shared_ptr Storage::getGraphForActiveTokenIds(const std::vector& Edge* edge = dynamic_cast(token); graph->addEdgeAndAllChildrenAsPlainCopy(edge); } - } - for(const std::pair> nodePair : graph->getNodes()) - { - Node* node = m_graph.getNodeById(nodePair.first); + for (const std::pair> nodePair : graph->getNodes()) + { + Node* node = m_graph.getNodeById(nodePair.first); - node->forEachEdge( - [graph](Edge* edge) - { - if(edge->getType() != Edge::EdgeType::EDGE_MEMBER) + node->forEachEdge( + [graph](Edge* edge) { - Node* from = edge->getFrom(); - Node* to = edge->getTo(); - - if(graph->findNode([from](Node* node){return from->getId() == node->getId();}) != NULL - && graph->findNode([to](Node* node){return to->getId() == node->getId();}) != NULL) + if (edge->getType() != Edge::EdgeType::EDGE_MEMBER) { - graph->addEdge(edge); + Node* from = edge->getFrom(); + Node* to = edge->getTo(); + + if (graph->findNode([from](Node* node){ return from->getId() == node->getId(); }) != NULL && + graph->findNode([to](Node* node){ return to->getId() == node->getId(); }) != NULL) + { + graph->addEdge(edge); + } } } - } - ); + ); + } } return graph; @@ -1050,24 +1049,34 @@ TokenLocation* Storage::addTokenLocation(Token* token, const ParseLocation& loc, return location; } -bool Storage::getSubQuerySearchResults( - const std::string& query, - const std::string& word, - SearchResults* results -) const { +bool Storage::getQuerySearchResults(const std::string& query, const std::string& word, SearchResults* results) const +{ std::string q = query; + bool isCommand = false; - if (QueryOperator::getOperatorType(q.back()) == QueryOperator::OPERATOR_SUB) + switch (QueryOperator::getOperatorType(q.back())) { + case QueryOperator::OPERATOR_AND: + case QueryOperator::OPERATOR_NOT: q.pop_back(); - } - else if (QueryOperator::getOperatorType(q.back()) == QueryOperator::OPERATOR_HAS) - { - q.pop_back(); - } - else if (QueryOperator::getOperatorType(q.back()) != QueryOperator::OPERATOR_NONE) - { return false; + + case QueryOperator::OPERATOR_HAS: + q.pop_back(); + q.append("'member'"); + break; + + case QueryOperator::OPERATOR_SUB: + q.pop_back(); + break; + + case QueryOperator::OPERATOR_COMMAND: + isCommand = true; + case QueryOperator::OPERATOR_NONE: + case QueryOperator::OPERATOR_TOKEN: + case QueryOperator::OPERATOR_GROUP_OPEN: + case QueryOperator::OPERATOR_GROUP_CLOSE: + break; } QueryTree tree(q); @@ -1096,27 +1105,27 @@ bool Storage::getSubQuerySearchResults( { if (word.size()) { - if (searchNodes.size() > 1) - { - SearchResults res = node->runFuzzySearchOnSelf(word); - results->insert(res.begin(), res.end()); - } - else + if (searchNodes.size() == 1 && !isCommand) { SearchResults res = node->runFuzzySearch(word); results->insert(res.begin(), res.end()); } + else + { + SearchResults res = node->runFuzzySearchOnSelf(word); + results->insert(res.begin(), res.end()); + } } - else if (searchNodes.size() == 1) + else if (searchNodes.size() == 1 && !isCommand) { for (const std::shared_ptr& child : node->getChildren()) { - child->addResultsRecursive(*results, 0, child.get()); + child->addResultsRecursive(results, 1, child.get()); } } else { - node->addResultsRecursive(*results, 0, node); + node->addResults(results, 1, node); } } diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index bba74580..057b013a 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -140,8 +140,7 @@ private: Edge* addTypeEdge(Node* node, Edge::EdgeType edgeType, const ParseTypeUsage& typeUsage); TokenLocation* addTokenLocation(Token* token, const ParseLocation& location, bool isScope = false); - bool getSubQuerySearchResults( - const std::string& query, const std::string& word, SearchResults* results) const; + bool getQuerySearchResults(const std::string& query, const std::string& word, SearchResults* results) const; void removeNodeIfUnreferenced(Node* node); diff --git a/src/lib/data/graph/filter/GraphFilterConductor.cpp b/src/lib/data/graph/filter/GraphFilterConductor.cpp index 687be981..19ceed41 100644 --- a/src/lib/data/graph/filter/GraphFilterConductor.cpp +++ b/src/lib/data/graph/filter/GraphFilterConductor.cpp @@ -29,6 +29,11 @@ void GraphFilterConductor::filter(const QueryTree* tree, const FilterableGraph* void GraphFilterConductor::filterRecursively(const QueryNode* node, const FilterableGraph* in, FilterableGraph* out) const { + if (!node) + { + return; + } + if (node->isOperator()) { filterOperatorNode(dynamic_cast(node), in, out); diff --git a/src/lib/data/query/QueryOperator.cpp b/src/lib/data/query/QueryOperator.cpp index a9d16f63..9dafab33 100644 --- a/src/lib/data/query/QueryOperator.cpp +++ b/src/lib/data/query/QueryOperator.cpp @@ -15,8 +15,8 @@ const std::map& QueryOperator::getOperatorTyp operatorMap.emplace(' ', OPERATOR_NONE); operatorMap.emplace('!', OPERATOR_NOT); - operatorMap.emplace('>', OPERATOR_HAS); - operatorMap.emplace('.', OPERATOR_SUB); + operatorMap.emplace('.', OPERATOR_HAS); + operatorMap.emplace('+', OPERATOR_SUB); operatorMap.emplace('&', OPERATOR_AND); operatorMap.emplace('|', OPERATOR_OR); diff --git a/src/lib/data/search/SearchNode.cpp b/src/lib/data/search/SearchNode.cpp index c5802f90..01c0340b 100644 --- a/src/lib/data/search/SearchNode.cpp +++ b/src/lib/data/search/SearchNode.cpp @@ -161,7 +161,7 @@ SearchResults SearchNode::runFuzzySearch(const std::string& query) const FuzzyMap m = n->fuzzyMatchRecursive(query, 0, 0, 0); for (const std::pair& p : m) { - addResultsRecursive(result, p.first, p.second); + addResultsRecursive(&result, p.first, p.second); } } @@ -176,7 +176,7 @@ SearchResults SearchNode::runFuzzySearchOnSelf(const std::string& query) const FuzzyMap m = fuzzyMatchRecursive(query, 0, 0, 0); for (const std::pair& p : m) { - addResultsRecursive(result, p.first, p.second); + addResultsRecursive(&result, p.first, p.second); } // TODO: Currently all matches are added to the ordered set and get compared by their fullName for alphabetical @@ -184,13 +184,18 @@ SearchResults SearchNode::runFuzzySearchOnSelf(const std::string& query) const return result; } -void SearchNode::addResultsRecursive(SearchResults& result, size_t weight, const SearchNode* node) const +void SearchNode::addResults(SearchResults* results, size_t weight, const SearchNode* node) const { - result.insert(SearchResult(weight, node, this)); + results->insert(SearchResult(weight, node, this)); +} + +void SearchNode::addResultsRecursive(SearchResults* results, size_t weight, const SearchNode* node) const +{ + addResults(results, weight, node); for (std::shared_ptr n: node->m_nodes) { - addResultsRecursive(result, weight, n.get()); + addResultsRecursive(results, weight, n.get()); } } diff --git a/src/lib/data/search/SearchNode.h b/src/lib/data/search/SearchNode.h index 44b85df7..05734cc8 100644 --- a/src/lib/data/search/SearchNode.h +++ b/src/lib/data/search/SearchNode.h @@ -46,7 +46,8 @@ public: SearchResults runFuzzySearch(const std::string& query) const; SearchResults runFuzzySearchOnSelf(const std::string& query) const; - void addResultsRecursive(SearchResults& result, size_t weight, const SearchNode* node) const; + void addResults(SearchResults* results, size_t weight, const SearchNode* node) const; + void addResultsRecursive(SearchResults* results, size_t weight, const SearchNode* node) const; private: typedef std::multimap FuzzyMap; diff --git a/src/lib/data/search/SearchResult.cpp b/src/lib/data/search/SearchResult.cpp index 6e36fcc9..90276dab 100644 --- a/src/lib/data/search/SearchResult.cpp +++ b/src/lib/data/search/SearchResult.cpp @@ -1,5 +1,7 @@ #include "data/search/SearchResult.h" +#include "utility/utilityString.h" + #include "data/search/SearchNode.h" SearchResult::SearchResult() @@ -20,5 +22,5 @@ bool SearchResult::operator()(const SearchResult& lhs, const SearchResult& rhs) return lhs.weight > rhs.weight; } - return lhs.node->getFullName() < rhs.node->getFullName(); + return utility::toLowerCase(lhs.node->getFullName()) < utility::toLowerCase(rhs.node->getFullName()); } diff --git a/src/lib/utility/utilityString.cpp b/src/lib/utility/utilityString.cpp index d621010c..fbc7d2be 100644 --- a/src/lib/utility/utilityString.cpp +++ b/src/lib/utility/utilityString.cpp @@ -2,6 +2,7 @@ #include #include +#include #include namespace utility @@ -117,6 +118,13 @@ namespace utility return res.first == prefix.end(); } + std::string toLowerCase(const std::string& in) + { + std::string out; + std::transform(in.begin(), in.end(), std::back_inserter(out), tolower); + return out; + } + bool equalsCaseInsensitive(const std::string& a, const std::string& b) { if (a.size() == b.size()) diff --git a/src/lib/utility/utilityString.h b/src/lib/utility/utilityString.h index 53892c18..bb459ad9 100644 --- a/src/lib/utility/utilityString.h +++ b/src/lib/utility/utilityString.h @@ -33,6 +33,7 @@ namespace utility bool isPrefix(const std::string& prefix, const std::string& text); + std::string toLowerCase(const std::string& in); bool equalsCaseInsensitive(const std::string& a, const std::string& b); std::string replace(std::string str, const std::string& from, const std::string& to); diff --git a/src/test/GraphFilterConductorTestSuite.h b/src/test/GraphFilterConductorTestSuite.h index 4e6a6f6d..3d6f58cd 100644 --- a/src/test/GraphFilterConductorTestSuite.h +++ b/src/test/GraphFilterConductorTestSuite.h @@ -109,7 +109,7 @@ public: void test_operator_sub() { TS_ASSERT_EQUALS( - printedFilteredTestGraph("'class'.'base'"), + printedFilteredTestGraph("'class''base'"), "1 nodes: class:A\n" "0 edges:\n" @@ -119,7 +119,7 @@ public: void test_operator_has() { TS_ASSERT_EQUALS( - printedFilteredTestGraph("\"A\">'field'"), + printedFilteredTestGraph("\"A\".'field'"), "1 nodes: field:A::count\n" "0 edges:\n" @@ -139,7 +139,7 @@ public: void test_operator_group() { TS_ASSERT_EQUALS( - printedFilteredTestGraph("('static'|'const').'public'"), + printedFilteredTestGraph("('static'|'const')'public'"), "1 nodes: method:A::getCount\n" "0 edges:\n" diff --git a/src/test/QueryTreeTestSuite.h b/src/test/QueryTreeTestSuite.h index a80bbed5..3a7e6a13 100644 --- a/src/test/QueryTreeTestSuite.h +++ b/src/test/QueryTreeTestSuite.h @@ -75,7 +75,7 @@ public: "A \" INVALID\n" " \"A\"\n" - ". IMPLICIT\n" + "+ IMPLICIT\n" " \"\"\n" ); } @@ -189,11 +189,11 @@ public: void test_operator_has_query() { TS_ASSERT_EQUALS( - printedQueryTree("\"A\">\"B\""), + printedQueryTree("\"A\".\"B\""), - "\"A\" > \"B\"\n" + "\"A\" . \"B\"\n" " \"A\"\n" - ">\n" + ".\n" " \"B\"\n" ); } @@ -276,7 +276,7 @@ public: "\"A\" ( \"B\" )\n" " \"A\"\n" - ". IMPLICIT\n" + "+ IMPLICIT\n" " (\"B\")\n" ); } @@ -284,12 +284,12 @@ public: void test_operator_precedence_not_before_has() { TS_ASSERT_EQUALS( - printedQueryTree("!'struct'.!'const'"), + printedQueryTree("!'struct'+!'const'"), - "! 'struct' . ! 'const'\n" + "! 'struct' + ! 'const'\n" " !\n" " 'struct'\n" - ".\n" + "+\n" " !\n" " 'const'\n" ); @@ -298,13 +298,13 @@ public: void test_operator_precedence_has_before_sub() { TS_ASSERT_EQUALS( - printedQueryTree("'namespace'>'class'.'base'"), + printedQueryTree("'namespace'.'class'+'base'"), - "'namespace' > 'class' . 'base'\n" + "'namespace' . 'class' + 'base'\n" " 'namespace'\n" - " >\n" + " .\n" " 'class'\n" - ".\n" + "+\n" " 'base'\n" ); } @@ -312,11 +312,11 @@ public: void test_operator_precedence_has_before_or() { TS_ASSERT_EQUALS( - printedQueryTree("'class'>'method'|'field'"), + printedQueryTree("'class'.'method'|'field'"), - "'class' > 'method' | 'field'\n" + "'class' . 'method' | 'field'\n" " 'class'\n" - " >\n" + " .\n" " 'method'\n" "|\n" " 'field'\n" @@ -326,22 +326,22 @@ public: void test_operator_precedence_respects_groups() { TS_ASSERT_EQUALS( - printedQueryTree("'namespace'.('class'>'method')"), + printedQueryTree("'namespace'+('class'.'method')"), - "'namespace' . ( 'class' > 'method' )\n" + "'namespace' + ( 'class' . 'method' )\n" " 'namespace'\n" - ".\n" + "+\n" " 'class'\n" - " (>)\n" + " (.)\n" " 'method'\n" ); TS_ASSERT_EQUALS( - printedQueryTree("'class'>('method'|'field')"), + printedQueryTree("'class'.('method'|'field')"), - "'class' > ( 'method' | 'field' )\n" + "'class' . ( 'method' | 'field' )\n" " 'class'\n" - ">\n" + ".\n" " 'method'\n" " (|)\n" " 'field'\n" @@ -351,15 +351,15 @@ public: void test_spaces_get_stripped_out_of_query() { TS_ASSERT_EQUALS( - printedQueryTree(" \"Field \">('method' | 'field') .'const' | 'public' "), + printedQueryTree(" \"Field \".('method' | 'field') +'const' | 'public' "), - "\"Field\" > ( 'method' | 'field' ) . 'const' | 'public'\n" + "\"Field\" . ( 'method' | 'field' ) + 'const' | 'public'\n" " \"Field\"\n" - " >\n" + " .\n" " 'method'\n" " (|)\n" " 'field'\n" - " .\n" + " +\n" " 'const'\n" "|\n" " 'public'\n" diff --git a/src/test/UtilityStringTestSuite.h b/src/test/UtilityStringTestSuite.h index 67a9e291..94f66c3b 100644 --- a/src/test/UtilityStringTestSuite.h +++ b/src/test/UtilityStringTestSuite.h @@ -212,6 +212,13 @@ public: TS_ASSERT(!utility::isPrefix(bar, foo)); } + void test_to_lower_case() + { + TS_ASSERT_EQUALS("foobar", utility::toLowerCase("FooBar")); + TS_ASSERT_EQUALS("foobar", utility::toLowerCase("FOOBAR")); + TS_ASSERT_EQUALS("foobar", utility::toLowerCase("foobar")); + } + void test_equals_case_insensitive_with_different_cases() { const std::string foo = "FooBar";