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
This commit is contained in:
Eberhard Graether
2015-02-06 00:51:02 +01:00
parent 1f6d503b9c
commit af1462f955
16 changed files with 206 additions and 126 deletions
+22 -22
View File
@@ -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 <input.cc 1:7 1:7>
Storage.cpp INFO: method: A::A <input.cc 4:2 4:2>
Storage.cpp INFO: global usage: A::A -> A::count <input.cc 5:3 5:7>
Storage.cpp INFO: method: A::getCount <input.cc 8:13 8:20>
Storage.cpp INFO: global usage: A::getCount -> A::count <input.cc 10:10 10:14>
Storage.cpp INFO: method: A::process <input.cc 14:15 14:21>
Storage.cpp INFO: field: A::count <input.cc 17:13 17:17>
Storage.cpp INFO: class: B <input.cc 20:7 20:7>
Storage.cpp INFO: inheritance: B : A <input.cc 21:4 21:11>
Storage.cpp INFO: method: B::process <input.cc 24:15 24:21>
Storage.cpp INFO: type usage: B::process -> int <input.cc 26:3 26:5>
Storage.cpp INFO: function: main <input.cc 30:5 30:8>
Storage.cpp INFO: type usage: main -> B <input.cc 32:2 32:2>
Storage.cpp INFO: call: main -> B::B <input.cc 32:4 32:4>
Storage.cpp INFO: call: main -> A::getCount <input.cc 34:9 34:21>
Storage.cpp INFO: class: A <input.cc 1:7 1:7>
Storage.cpp INFO: method: A::A <input.cc 4:2 4:2>
Storage.cpp INFO: global usage: A::A -> A::count <input.cc 5:3 5:7>
@@ -31,27 +52,6 @@ SearchMatch.cpp INFO:
237 A::A
^^^^
Storage.cpp INFO: class: A <input.cc 1:7 1:7>
Storage.cpp INFO: method: A::A <input.cc 4:2 4:2>
Storage.cpp INFO: global usage: A::A -> A::count <input.cc 5:3 5:7>
Storage.cpp INFO: method: A::getCount <input.cc 8:13 8:20>
Storage.cpp INFO: global usage: A::getCount -> A::count <input.cc 10:10 10:14>
Storage.cpp INFO: method: A::process <input.cc 14:15 14:21>
Storage.cpp INFO: field: A::count <input.cc 17:13 17:17>
Storage.cpp INFO: class: B <input.cc 20:7 20:7>
Storage.cpp INFO: inheritance: B : A <input.cc 21:4 21:11>
Storage.cpp INFO: method: B::process <input.cc 24:15 24:21>
Storage.cpp INFO: type usage: B::process -> int <input.cc 26:3 26:5>
Storage.cpp INFO: function: main <input.cc 30:5 30:8>
Storage.cpp INFO: type usage: main -> B <input.cc 32:2 32:2>
Storage.cpp INFO: call: main -> B::B <input.cc 32:4 32:4>
Storage.cpp INFO: call: main -> A::getCount <input.cc 34:9 34:21>
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 <file.cpp 1:1 1:1>
Storage.cpp INFO: class: Class <file.cpp 1:1 1:1>
Storage.cpp INFO: struct: Struct <file.cpp 1:1 1:1>
@@ -120,6 +119,7 @@ Storage.cpp INFO: call: main -> isTrue <file.cpp 1:0 1:0>
Storage.cpp INFO: function: isTrue <file.h 1:0 1:0>
Storage.cpp INFO: function: main <file.cpp 1:0 1:0>
Storage.cpp INFO: call: main -> isTrue <file.cpp 1:0 1:0>
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
+51 -18
View File
@@ -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<SearchMatch>& 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<QKeyEvent*>(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;
+2 -3
View File
@@ -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<SearchMatch>& 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);
@@ -76,6 +76,17 @@ void GraphLayouter::layoutSpectralPrototype(std::vector<DummyNode>& nodes, const
MatrixDynamicBase<int> 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());
+52 -43
View File
@@ -590,18 +590,17 @@ std::string Storage::getNameForNodeWithId(Id id) const
}
}
std::vector<SearchMatch> Storage::getAutocompletionMatches(
const std::string& query, const std::string& word) const
std::vector<SearchMatch> 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<Graph> Storage::getGraphForActiveTokenIds(const std::vector<Id>&
Edge* edge = dynamic_cast<Edge*>(token);
graph->addEdgeAndAllChildrenAsPlainCopy(edge);
}
}
for(const std::pair<Id, std::shared_ptr<Node>> nodePair : graph->getNodes())
{
Node* node = m_graph.getNodeById(nodePair.first);
for (const std::pair<Id, std::shared_ptr<Node>> 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<SearchNode>& 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);
}
}
+1 -2
View File
@@ -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);
@@ -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<const QueryOperator*>(node), in, out);
+2 -2
View File
@@ -15,8 +15,8 @@ const std::map<char, QueryOperator::OperatorType>& 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);
+10 -5
View File
@@ -161,7 +161,7 @@ SearchResults SearchNode::runFuzzySearch(const std::string& query) const
FuzzyMap m = n->fuzzyMatchRecursive(query, 0, 0, 0);
for (const std::pair<size_t, const SearchNode*>& 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<size_t, const SearchNode*>& 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<SearchNode> n: node->m_nodes)
{
addResultsRecursive(result, weight, n.get());
addResultsRecursive(results, weight, n.get());
}
}
+2 -1
View File
@@ -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<size_t, const SearchNode*> FuzzyMap;
+3 -1
View File
@@ -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());
}
+8
View File
@@ -2,6 +2,7 @@
#include <algorithm>
#include <cctype>
#include <iterator>
#include <string>
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())
+1
View File
@@ -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);
+3 -3
View File
@@ -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"
+26 -26
View File
@@ -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"
+7
View File
@@ -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";