152a38012Sejakowatz// QueryTest.cpp
252a38012Sejakowatz
352a38012Sejakowatz#include <ctype.h>
452a38012Sejakowatz#include <fs_info.h>
552a38012Sejakowatz#include <stdio.h>
652a38012Sejakowatz#include <string>
752a38012Sejakowatz#include <unistd.h>
852a38012Sejakowatz
952a38012Sejakowatz#include "QueryTest.h"
1052a38012Sejakowatz
1152a38012Sejakowatz#include <Application.h>
1252a38012Sejakowatz#include <Message.h>
1352a38012Sejakowatz#include <MessageQueue.h>
1452a38012Sejakowatz#include <Messenger.h>
1552a38012Sejakowatz#include <NodeMonitor.h>
161f8b3fdbSAdrien Destugues#include <ObjectList.h>
1752a38012Sejakowatz#include <OS.h>
1852a38012Sejakowatz#include <Path.h>
1952a38012Sejakowatz#include <Query.h>
2052a38012Sejakowatz#include <String.h>
2152a38012Sejakowatz#include <Volume.h>
22aad997bdSTyler Dauwalder#include <TestApp.h>
23aad997bdSTyler Dauwalder#include <TestUtils.h>
2452a38012Sejakowatz
2552a38012Sejakowatz// Query
2652a38012Sejakowatz
2752a38012Sejakowatzclass Query : public BQuery {
2852a38012Sejakowatzpublic:
29aad997bdSTyler Dauwalder#if TEST_R5
3052a38012Sejakowatz	status_t PushValue(int32 value)			{ PushInt32(value); return B_OK; }
3152a38012Sejakowatz	status_t PushValue(uint32 value)		{ PushUInt32(value); return B_OK; }
3252a38012Sejakowatz	status_t PushValue(int64 value)			{ PushInt64(value); return B_OK; }
3352a38012Sejakowatz	status_t PushValue(uint64 value)		{ PushUInt64(value); return B_OK; }
3452a38012Sejakowatz	status_t PushValue(float value)			{ PushFloat(value); return B_OK; }
3552a38012Sejakowatz	status_t PushValue(double value)		{ PushDouble(value); return B_OK; }
3652a38012Sejakowatz	status_t PushValue(const BString value, bool caseInsensitive = false)
3752a38012Sejakowatz	{
3852a38012Sejakowatz		PushString(value.String(), caseInsensitive); return B_OK;
3952a38012Sejakowatz	}
4052a38012Sejakowatz	status_t PushAttr(const char *attribute)
4152a38012Sejakowatz	{
4252a38012Sejakowatz		BQuery::PushAttr(attribute);
4352a38012Sejakowatz		return B_OK;
4452a38012Sejakowatz	}
4552a38012Sejakowatz	status_t PushOp(query_op op)
4652a38012Sejakowatz	{
4752a38012Sejakowatz		BQuery::PushOp(op);
4852a38012Sejakowatz		return B_OK;
4952a38012Sejakowatz	}
5052a38012Sejakowatz#else
5152a38012Sejakowatz	status_t PushValue(int32 value)			{ return PushInt32(value); }
5252a38012Sejakowatz	status_t PushValue(uint32 value)		{ return PushUInt32(value); }
5352a38012Sejakowatz	status_t PushValue(int64 value)			{ return PushInt64(value); }
5452a38012Sejakowatz	status_t PushValue(uint64 value)		{ return PushUInt64(value); }
5552a38012Sejakowatz	status_t PushValue(float value)			{ return PushFloat(value); }
5652a38012Sejakowatz	status_t PushValue(double value)		{ return PushDouble(value); }
5752a38012Sejakowatz	status_t PushValue(const BString value, bool caseInsensitive = false)
5852a38012Sejakowatz	{
5952a38012Sejakowatz		return PushString(value.String(), caseInsensitive);
6052a38012Sejakowatz	}
6152a38012Sejakowatz#endif
6252a38012Sejakowatz};
6352a38012Sejakowatz
6452a38012Sejakowatz
6552a38012Sejakowatz// PredicateNode
6652a38012Sejakowatz
6752a38012Sejakowatzclass PredicateNode {
6852a38012Sejakowatzpublic:
6952a38012Sejakowatz	virtual ~PredicateNode() {}
7052a38012Sejakowatz
7152a38012Sejakowatz	virtual status_t push(Query &query) const = 0;
7252a38012Sejakowatz	virtual BString toString() const = 0;
7352a38012Sejakowatz};
7452a38012Sejakowatz
7552a38012Sejakowatz
7652a38012Sejakowatz// ValueNode
7752a38012Sejakowatz
7852a38012Sejakowatztemplate<typename ValueType>
7952a38012Sejakowatzclass ValueNode : public PredicateNode {
8052a38012Sejakowatzpublic:
8152a38012Sejakowatz	ValueNode(ValueType v) : value(v) {}
8252a38012Sejakowatz
8352a38012Sejakowatz	virtual ~ValueNode() {}
8452a38012Sejakowatz
8552a38012Sejakowatz	virtual status_t push(Query &query) const
8652a38012Sejakowatz	{
8752a38012Sejakowatz		return query.PushValue(value);
8852a38012Sejakowatz	}
8952a38012Sejakowatz
9052a38012Sejakowatz	virtual BString toString() const
9152a38012Sejakowatz	{
9252a38012Sejakowatz		return BString() << value;
9352a38012Sejakowatz	}
9452a38012Sejakowatz
9552a38012Sejakowatz	ValueType value;
9652a38012Sejakowatz};
9752a38012Sejakowatz
9852a38012Sejakowatz// float specialization
9977aa0e2aSOliver Tappetemplate<>
10052a38012SejakowatzBString
10152a38012SejakowatzValueNode<float>::toString() const
10252a38012Sejakowatz{
10352a38012Sejakowatz	char buffer[32];
10452a38012Sejakowatz	sprintf(buffer, "0x%08lx", *(int32*)&value);
10552a38012Sejakowatz	return BString() << buffer;
10652a38012Sejakowatz}
10752a38012Sejakowatz
10852a38012Sejakowatz// double specialization
10977aa0e2aSOliver Tappetemplate<>
11052a38012SejakowatzBString
11152a38012SejakowatzValueNode<double>::toString() const
11252a38012Sejakowatz{
11352a38012Sejakowatz	char buffer[32];
11452a38012Sejakowatz	sprintf(buffer, "0x%016Lx", *(int64*)&value);
11552a38012Sejakowatz	return BString() << buffer;
11652a38012Sejakowatz}
11752a38012Sejakowatz
11852a38012Sejakowatz// StringNode
11952a38012Sejakowatz
12052a38012Sejakowatzclass StringNode : public PredicateNode {
12152a38012Sejakowatzpublic:
12252a38012Sejakowatz	StringNode(BString v, bool caseInsensitive = false)
12352a38012Sejakowatz		: value(v), caseInsensitive(caseInsensitive)
12452a38012Sejakowatz	{
12552a38012Sejakowatz	}
12652a38012Sejakowatz
12752a38012Sejakowatz	virtual ~StringNode() {}
12852a38012Sejakowatz
12952a38012Sejakowatz	virtual status_t push(Query &query) const
13052a38012Sejakowatz	{
13152a38012Sejakowatz		return query.PushValue(value, caseInsensitive);
13252a38012Sejakowatz	}
13352a38012Sejakowatz
13452a38012Sejakowatz	virtual BString toString() const
13552a38012Sejakowatz	{
13652a38012Sejakowatz		BString escaped;
13752a38012Sejakowatz		if (caseInsensitive) {
13852a38012Sejakowatz			const char *str = value.String();
13952a38012Sejakowatz			int32 len = value.Length();
14052a38012Sejakowatz			for (int32 i = 0; i < len; i++) {
14152a38012Sejakowatz				char c = str[i];
14252a38012Sejakowatz				if (isalpha(c)) {
14352a38012Sejakowatz					int lower = tolower(c);
14452a38012Sejakowatz					int upper = toupper(c);
14552a38012Sejakowatz					if (lower < 0 || upper < 0)
14652a38012Sejakowatz						escaped << c;
14752a38012Sejakowatz					else
14852a38012Sejakowatz						escaped << "[" << (char)lower << (char)upper << "]";
14952a38012Sejakowatz				} else
15052a38012Sejakowatz					escaped << c;
15152a38012Sejakowatz			}
15252a38012Sejakowatz		} else
15352a38012Sejakowatz			escaped = value;
15452a38012Sejakowatz		escaped.CharacterEscape("\"\\'", '\\');
15552a38012Sejakowatz		return BString("\"") << escaped << "\"";
15652a38012Sejakowatz	}
15752a38012Sejakowatz
15852a38012Sejakowatz	BString value;
15952a38012Sejakowatz	bool	caseInsensitive;
16052a38012Sejakowatz};
16152a38012Sejakowatz
16252a38012Sejakowatz
16352a38012Sejakowatz// DateNode
16452a38012Sejakowatz
16552a38012Sejakowatzclass DateNode : public PredicateNode {
16652a38012Sejakowatzpublic:
16752a38012Sejakowatz	DateNode(BString v) : value(v) {}
16852a38012Sejakowatz
16952a38012Sejakowatz	virtual ~DateNode() {}
17052a38012Sejakowatz
17152a38012Sejakowatz	virtual status_t push(Query &query) const
17252a38012Sejakowatz	{
17352a38012Sejakowatz		return query.PushDate(value.String());
17452a38012Sejakowatz	}
17552a38012Sejakowatz
17652a38012Sejakowatz	virtual BString toString() const
17752a38012Sejakowatz	{
17852a38012Sejakowatz		BString escaped(value);
17952a38012Sejakowatz		escaped.CharacterEscape("%\"\\'", '\\');
18052a38012Sejakowatz		return BString("%") << escaped << "%";
18152a38012Sejakowatz	}
18252a38012Sejakowatz
18352a38012Sejakowatz	BString value;
18452a38012Sejakowatz};
18552a38012Sejakowatz
18652a38012Sejakowatz
18752a38012Sejakowatz// AttributeNode
18852a38012Sejakowatz
18952a38012Sejakowatzclass AttributeNode : public PredicateNode {
19052a38012Sejakowatzpublic:
19152a38012Sejakowatz	AttributeNode(BString v) : value(v) {}
19252a38012Sejakowatz
19352a38012Sejakowatz	virtual ~AttributeNode() {}
19452a38012Sejakowatz
19552a38012Sejakowatz	virtual status_t push(Query &query) const
19652a38012Sejakowatz	{
19752a38012Sejakowatz		return query.PushAttr(value.String());
19852a38012Sejakowatz	}
19952a38012Sejakowatz
20052a38012Sejakowatz	virtual BString toString() const
20152a38012Sejakowatz	{
20252a38012Sejakowatz		return value;
20352a38012Sejakowatz	}
20452a38012Sejakowatz
20552a38012Sejakowatz	BString value;
20652a38012Sejakowatz};
20752a38012Sejakowatz
20852a38012Sejakowatz
20952a38012Sejakowatz// short hands
21052a38012Sejakowatztypedef ValueNode<int32>	Int32Node;
21152a38012Sejakowatztypedef ValueNode<uint32>	UInt32Node;
21252a38012Sejakowatztypedef ValueNode<int64>	Int64Node;
21352a38012Sejakowatztypedef ValueNode<uint64>	UInt64Node;
21452a38012Sejakowatztypedef ValueNode<float>	FloatNode;
21552a38012Sejakowatztypedef ValueNode<double>	DoubleNode;
21652a38012Sejakowatz
21752a38012Sejakowatz
21852a38012Sejakowatz// ListNode
21952a38012Sejakowatz
22052a38012Sejakowatzclass ListNode : public PredicateNode {
22152a38012Sejakowatzpublic:
22252a38012Sejakowatz	ListNode(PredicateNode *child1 = NULL, PredicateNode *child2 = NULL,
22352a38012Sejakowatz			 PredicateNode *child3 = NULL, PredicateNode *child4 = NULL,
22452a38012Sejakowatz			 PredicateNode *child5 = NULL, PredicateNode *child6 = NULL)
22552a38012Sejakowatz		: children()
22652a38012Sejakowatz	{
22752a38012Sejakowatz		addChild(child1);
22852a38012Sejakowatz		addChild(child2);
22952a38012Sejakowatz		addChild(child3);
23052a38012Sejakowatz		addChild(child4);
23152a38012Sejakowatz		addChild(child5);
23252a38012Sejakowatz		addChild(child6);
23352a38012Sejakowatz	}
23452a38012Sejakowatz
23552a38012Sejakowatz	virtual ~ListNode()
23652a38012Sejakowatz	{
23752a38012Sejakowatz		for (int32 i = 0; PredicateNode *child = childAt(i); i++)
23852a38012Sejakowatz			delete child;
23952a38012Sejakowatz	}
24052a38012Sejakowatz
24152a38012Sejakowatz	virtual status_t push(Query &query) const
24252a38012Sejakowatz	{
24352a38012Sejakowatz		status_t error = B_OK;
24452a38012Sejakowatz		for (int32 i = 0; PredicateNode *child = childAt(i); i++) {
24552a38012Sejakowatz			error = child->push(query);
24652a38012Sejakowatz			if (error != B_OK)
24752a38012Sejakowatz				break;
24852a38012Sejakowatz		}
24952a38012Sejakowatz		return error;
25052a38012Sejakowatz	}
25152a38012Sejakowatz
25252a38012Sejakowatz	virtual BString toString() const
25352a38012Sejakowatz	{
25452a38012Sejakowatz		return BString("INVALID");
25552a38012Sejakowatz	}
25652a38012Sejakowatz
25752a38012Sejakowatz	ListNode &addChild(PredicateNode *child)
25852a38012Sejakowatz	{
25952a38012Sejakowatz		if (child)
26052a38012Sejakowatz			children.AddItem(child);
26152a38012Sejakowatz		return *this;
26252a38012Sejakowatz	}
26352a38012Sejakowatz
26452a38012Sejakowatz	PredicateNode *childAt(int32 index) const
26552a38012Sejakowatz	{
26652a38012Sejakowatz		return (PredicateNode*)children.ItemAt(index);
26752a38012Sejakowatz	}
26852a38012Sejakowatz
2691f8b3fdbSAdrien Destugues	BObjectList<PredicateNode> children;
27052a38012Sejakowatz};
27152a38012Sejakowatz
27252a38012Sejakowatz// OpNode
27352a38012Sejakowatz
27452a38012Sejakowatzclass OpNode : public ListNode {
27552a38012Sejakowatzpublic:
27652a38012Sejakowatz	OpNode(query_op op, PredicateNode *left, PredicateNode *right = NULL)
27752a38012Sejakowatz		: ListNode(left, right), op(op) {}
27852a38012Sejakowatz
27952a38012Sejakowatz	virtual ~OpNode() { }
28052a38012Sejakowatz
28152a38012Sejakowatz	virtual status_t push(Query &query) const
28252a38012Sejakowatz	{
28352a38012Sejakowatz		status_t error = ListNode::push(query);
28452a38012Sejakowatz		if (error == B_OK)
28552a38012Sejakowatz			error = query.PushOp(op);
28652a38012Sejakowatz		return error;
28752a38012Sejakowatz	}
28852a38012Sejakowatz
28952a38012Sejakowatz	virtual BString toString() const
29052a38012Sejakowatz	{
29152a38012Sejakowatz		PredicateNode *left = childAt(0);
29252a38012Sejakowatz		PredicateNode *right = childAt(1);
29352a38012Sejakowatz		if (!left)
29452a38012Sejakowatz			return "INVALID ARGS";
29552a38012Sejakowatz		BString result;
29652a38012Sejakowatz		BString leftString = left->toString();
29752a38012Sejakowatz		BString rightString;
29852a38012Sejakowatz		if (right)
29952a38012Sejakowatz			rightString = right->toString();
30052a38012Sejakowatz		switch (op) {
30152a38012Sejakowatz			case B_INVALID_OP:
30252a38012Sejakowatz				result = "INVALID";
30352a38012Sejakowatz				break;
30452a38012Sejakowatz			case B_EQ:
30552a38012Sejakowatz				result << "(" << leftString << "==" << rightString << ")";
30652a38012Sejakowatz				break;
30752a38012Sejakowatz			case B_GT:
30852a38012Sejakowatz				result << "(" << leftString << ">" << rightString << ")";
30952a38012Sejakowatz				break;
31052a38012Sejakowatz			case B_GE:
31152a38012Sejakowatz				result << "(" << leftString << ">=" << rightString << ")";
31252a38012Sejakowatz				break;
31352a38012Sejakowatz			case B_LT:
31452a38012Sejakowatz				result << "(" << leftString << "<" << rightString << ")";
31552a38012Sejakowatz				break;
31652a38012Sejakowatz			case B_LE:
31752a38012Sejakowatz				result << "(" << leftString << "<=" << rightString << ")";
31852a38012Sejakowatz				break;
31952a38012Sejakowatz			case B_NE:
32052a38012Sejakowatz				result << "(" << leftString << "!=" << rightString << ")";
32152a38012Sejakowatz				break;
32252a38012Sejakowatz			case B_CONTAINS:
32352a38012Sejakowatz			{
32452a38012Sejakowatz				StringNode *strNode = dynamic_cast<StringNode*>(right);
32552a38012Sejakowatz				if (strNode) {
32652a38012Sejakowatz					rightString = StringNode(BString("*") << strNode->value
32752a38012Sejakowatz											 << "*").toString();
32852a38012Sejakowatz				}
32952a38012Sejakowatz				result << "(" << leftString << "==" << rightString << ")";
33052a38012Sejakowatz				break;
33152a38012Sejakowatz			}
33252a38012Sejakowatz			case B_BEGINS_WITH:
33352a38012Sejakowatz			{
33452a38012Sejakowatz				StringNode *strNode = dynamic_cast<StringNode*>(right);
33552a38012Sejakowatz				if (strNode) {
33652a38012Sejakowatz					rightString = StringNode(BString(strNode->value) << "*")
33752a38012Sejakowatz											 .toString();
33852a38012Sejakowatz				}
33952a38012Sejakowatz				result << "(" << leftString << "==" << rightString << ")";
34052a38012Sejakowatz				break;
34152a38012Sejakowatz			}
34252a38012Sejakowatz			case B_ENDS_WITH:
34352a38012Sejakowatz			{
34452a38012Sejakowatz				StringNode *strNode = dynamic_cast<StringNode*>(right);
34552a38012Sejakowatz				if (strNode) {
34652a38012Sejakowatz					rightString = StringNode(BString("*") << strNode->value)
34752a38012Sejakowatz											 .toString();
34852a38012Sejakowatz				}
34952a38012Sejakowatz				result << "(" << leftString << "==" << rightString << ")";
35052a38012Sejakowatz				break;
35152a38012Sejakowatz			}
35252a38012Sejakowatz			case B_AND:
35352a38012Sejakowatz				result << "(" << leftString << "&&" << rightString << ")";
35452a38012Sejakowatz				break;
35552a38012Sejakowatz			case B_OR:
35652a38012Sejakowatz				result << "(" << leftString << "||" << rightString << ")";
35752a38012Sejakowatz				break;
35852a38012Sejakowatz			case B_NOT:
35952a38012Sejakowatz				result << "(" << "!" << leftString << ")";
36052a38012Sejakowatz				break;
36152a38012Sejakowatz			case _B_RESERVED_OP_:
36252a38012Sejakowatz				result = "RESERVED";
36352a38012Sejakowatz				break;
36452a38012Sejakowatz		}
36552a38012Sejakowatz		return result;
36652a38012Sejakowatz	}
36752a38012Sejakowatz
36852a38012Sejakowatz	query_op op;
36952a38012Sejakowatz};
37052a38012Sejakowatz
37152a38012Sejakowatz
37252a38012Sejakowatz// QueryTestEntry
37352a38012Sejakowatzclass QueryTestEntry {
37452a38012Sejakowatzpublic:
37552a38012Sejakowatz	QueryTestEntry(string path, node_flavor kind,
37652a38012Sejakowatz				   const QueryTestEntry *linkTarget = NULL)
37752a38012Sejakowatz		: path(path),
37852a38012Sejakowatz		  cpath(NULL),
37952a38012Sejakowatz		  kind(kind),
38052a38012Sejakowatz		  linkToPath(),
38152a38012Sejakowatz		  clinkToPath(NULL),
38252a38012Sejakowatz		  directory(-1),
38352a38012Sejakowatz		  node(-1),
38452a38012Sejakowatz		  name()
38552a38012Sejakowatz	{
38652a38012Sejakowatz		cpath = this->path.c_str();
38752a38012Sejakowatz		if (linkTarget)
38852a38012Sejakowatz			linkToPath = linkTarget->path;
38952a38012Sejakowatz		clinkToPath = this->linkToPath.c_str();
39052a38012Sejakowatz	}
39152a38012Sejakowatz
39252a38012Sejakowatz	string operator+(string leaf) const
39352a38012Sejakowatz	{
39452a38012Sejakowatz		return path + "/" + leaf;
39552a38012Sejakowatz	}
39652a38012Sejakowatz
39752a38012Sejakowatz	string		path;
39852a38012Sejakowatz	const char	*cpath;
39952a38012Sejakowatz	node_flavor	kind;
40052a38012Sejakowatz	string		linkToPath;
40152a38012Sejakowatz	const char	*clinkToPath;
40252a38012Sejakowatz	ino_t		directory;
40352a38012Sejakowatz	ino_t		node;
40452a38012Sejakowatz	string		name;
40552a38012Sejakowatz};
40652a38012Sejakowatz
40752a38012Sejakowatzstatic const char *testVolumeImage	= "/tmp/query-test-image";
40852a38012Sejakowatzstatic const char *testMountPoint	= "/non-existing-mount-point";
40952a38012Sejakowatz
41052a38012Sejakowatz// the test entry hierarchy:
41152a38012Sejakowatz// mountPoint
41252a38012Sejakowatz// + dir1
41352a38012Sejakowatz//   + subdir11
41452a38012Sejakowatz//   + subdir12
41552a38012Sejakowatz//   + file11
41652a38012Sejakowatz//   + file12
41752a38012Sejakowatz//   + link11
41852a38012Sejakowatz// + dir2
41952a38012Sejakowatz//   + subdir21
42052a38012Sejakowatz//   + subdir22
42152a38012Sejakowatz//   + subdir23
42252a38012Sejakowatz//   + file21
42352a38012Sejakowatz//   + file22
42452a38012Sejakowatz//   + link21
42552a38012Sejakowatz// + dir3
42652a38012Sejakowatz//   + subdir31
42752a38012Sejakowatz//   + subdir32
42852a38012Sejakowatz//   + file31
42952a38012Sejakowatz//   + file32
43052a38012Sejakowatz//   + link31
43152a38012Sejakowatz// + file1
43252a38012Sejakowatz// + file2
43352a38012Sejakowatz// + file3
43452a38012Sejakowatz// + link1
43552a38012Sejakowatz// + link2
43652a38012Sejakowatz// + link3
43752a38012Sejakowatzstatic QueryTestEntry mountPoint(testMountPoint, B_DIRECTORY_NODE);
43852a38012Sejakowatzstatic QueryTestEntry dir1(mountPoint + "dir1", B_DIRECTORY_NODE);
43952a38012Sejakowatzstatic QueryTestEntry subdir11(dir1 + "subdir11", B_DIRECTORY_NODE);
44052a38012Sejakowatzstatic QueryTestEntry subdir12(dir1 + "subdir12", B_DIRECTORY_NODE);
44152a38012Sejakowatzstatic QueryTestEntry file11(dir1 + "file11", B_FILE_NODE);
44252a38012Sejakowatzstatic QueryTestEntry file12(dir1 + "file12", B_FILE_NODE);
44352a38012Sejakowatzstatic QueryTestEntry link11(dir1 + "link11", B_SYMLINK_NODE, &file11);
44452a38012Sejakowatzstatic QueryTestEntry dir2(mountPoint + "dir2", B_DIRECTORY_NODE);
44552a38012Sejakowatzstatic QueryTestEntry subdir21(dir2 + "subdir21", B_DIRECTORY_NODE);
44652a38012Sejakowatzstatic QueryTestEntry subdir22(dir2 + "subdir22", B_DIRECTORY_NODE);
44752a38012Sejakowatzstatic QueryTestEntry subdir23(dir2 + "subdir23", B_DIRECTORY_NODE);
44852a38012Sejakowatzstatic QueryTestEntry file21(dir2 + "file21", B_FILE_NODE);
44952a38012Sejakowatzstatic QueryTestEntry file22(dir2 + "file22", B_FILE_NODE);
45052a38012Sejakowatzstatic QueryTestEntry link21(dir2 + "link21", B_SYMLINK_NODE, &file12);
45152a38012Sejakowatzstatic QueryTestEntry dir3(mountPoint + "dir3", B_DIRECTORY_NODE);
45252a38012Sejakowatzstatic QueryTestEntry subdir31(dir3 + "subdir31", B_DIRECTORY_NODE);
45352a38012Sejakowatzstatic QueryTestEntry subdir32(dir3 + "subdir32", B_DIRECTORY_NODE);
45452a38012Sejakowatzstatic QueryTestEntry file31(dir3 + "file31", B_FILE_NODE);
45552a38012Sejakowatzstatic QueryTestEntry file32(dir3 + "file32", B_FILE_NODE);
45652a38012Sejakowatzstatic QueryTestEntry link31(dir3 + "link31", B_SYMLINK_NODE, &file22);
45752a38012Sejakowatzstatic QueryTestEntry file1(mountPoint + "file1", B_FILE_NODE);
45852a38012Sejakowatzstatic QueryTestEntry file2(mountPoint + "file2", B_FILE_NODE);
45952a38012Sejakowatzstatic QueryTestEntry file3(mountPoint + "file3", B_FILE_NODE);
46052a38012Sejakowatzstatic QueryTestEntry link1(mountPoint + "link1", B_SYMLINK_NODE, &file1);
46152a38012Sejakowatzstatic QueryTestEntry link2(mountPoint + "link2", B_SYMLINK_NODE, &file2);
46252a38012Sejakowatzstatic QueryTestEntry link3(mountPoint + "link3", B_SYMLINK_NODE, &file3);
46352a38012Sejakowatz
46452a38012Sejakowatzstatic QueryTestEntry *allTestEntries[] = {
46552a38012Sejakowatz	&dir1, &subdir11, &subdir12, &file11, &file12, &link11,
46652a38012Sejakowatz	&dir2, &subdir21, &subdir22, &subdir23, &file21, &file22, &link21,
46752a38012Sejakowatz	&dir3, &subdir31, &subdir32, &file31, &file32, &link31,
46852a38012Sejakowatz	&file1, &file2, &file3, &link1, &link2, &link3
46952a38012Sejakowatz};
47052a38012Sejakowatzstatic const int32 allTestEntryCount
47152a38012Sejakowatz	= sizeof(allTestEntries) / sizeof(QueryTestEntry*);
47252a38012Sejakowatz
47352a38012Sejakowatz// create_test_entries
47452a38012Sejakowatzvoid
47552a38012Sejakowatzcreate_test_entries(QueryTestEntry **testEntries, int32 count)
47652a38012Sejakowatz{
47752a38012Sejakowatz	// create the command line
47852a38012Sejakowatz	string cmdLine("true");
47952a38012Sejakowatz	for (int32 i = 0; i < count; i++) {
48052a38012Sejakowatz		const QueryTestEntry *entry = testEntries[i];
48152a38012Sejakowatz		switch (entry->kind) {
48252a38012Sejakowatz			case B_DIRECTORY_NODE:
48352a38012Sejakowatz				cmdLine += " ; mkdir " + entry->path;
48452a38012Sejakowatz				break;
48552a38012Sejakowatz			case B_FILE_NODE:
48652a38012Sejakowatz				cmdLine += " ; touch " + entry->path;
48752a38012Sejakowatz				break;
48852a38012Sejakowatz			case B_SYMLINK_NODE:
48952a38012Sejakowatz				cmdLine += " ; ln -s " + entry->linkToPath + " " + entry->path;
49052a38012Sejakowatz				break;
49152a38012Sejakowatz			case B_ANY_NODE:
49252a38012Sejakowatz			default:
49352a38012Sejakowatz				printf("WARNING: invalid node kind\n");
49452a38012Sejakowatz				break;
49552a38012Sejakowatz		}
49652a38012Sejakowatz	}
49752a38012Sejakowatz	BasicTest::execCommand(cmdLine);
49852a38012Sejakowatz}
49952a38012Sejakowatz
50052a38012Sejakowatz// delete_test_entries
50152a38012Sejakowatzvoid
50252a38012Sejakowatzdelete_test_entries(QueryTestEntry **testEntries, int32 count)
50352a38012Sejakowatz{
50452a38012Sejakowatz	// create the command line
50552a38012Sejakowatz	string cmdLine("true");
50652a38012Sejakowatz	for (int32 i = 0; i < count; i++) {
50752a38012Sejakowatz		const QueryTestEntry *entry = testEntries[i];
50852a38012Sejakowatz		switch (entry->kind) {
50952a38012Sejakowatz			case B_DIRECTORY_NODE:
51052a38012Sejakowatz			case B_FILE_NODE:
51152a38012Sejakowatz			case B_SYMLINK_NODE:
51252a38012Sejakowatz				cmdLine += " ; rm -rf " + entry->path;
51352a38012Sejakowatz				break;
51452a38012Sejakowatz			case B_ANY_NODE:
51552a38012Sejakowatz			default:
51652a38012Sejakowatz				printf("WARNING: invalid node kind\n");
51752a38012Sejakowatz				break;
51852a38012Sejakowatz		}
51952a38012Sejakowatz	}
52052a38012Sejakowatz	BasicTest::execCommand(cmdLine);
52152a38012Sejakowatz}
52252a38012Sejakowatz
52352a38012Sejakowatz
52452a38012Sejakowatz
52552a38012Sejakowatz
52652a38012Sejakowatz// QueryTest
52752a38012Sejakowatz
52852a38012Sejakowatz// Suite
52952a38012SejakowatzCppUnit::Test*
53052a38012SejakowatzQueryTest::Suite() {
53152a38012Sejakowatz	CppUnit::TestSuite *suite = new CppUnit::TestSuite();
53252a38012Sejakowatz	typedef CppUnit::TestCaller<QueryTest> TC;
53352a38012Sejakowatz
53452a38012Sejakowatz	suite->addTest( new TC("BQuery::Predicate Test",
53552a38012Sejakowatz						   &QueryTest::PredicateTest) );
53652a38012Sejakowatz	suite->addTest( new TC("BQuery::Parameter Test",
53752a38012Sejakowatz						   &QueryTest::ParameterTest) );
53852a38012Sejakowatz	suite->addTest( new TC("BQuery::Fetch Test", &QueryTest::FetchTest) );
53952a38012Sejakowatz	suite->addTest( new TC("BQuery::Live Test", &QueryTest::LiveTest) );
54052a38012Sejakowatz
54152a38012Sejakowatz	return suite;
54252a38012Sejakowatz}
54352a38012Sejakowatz
54452a38012Sejakowatz// setUp
54552a38012Sejakowatzvoid
54652a38012SejakowatzQueryTest::setUp()
54752a38012Sejakowatz{
54852a38012Sejakowatz	BasicTest::setUp();
549242a6db2STyler Dauwalder	fApplication = new BTestApp("application/x-vnd.obos.query-test");
55052a38012Sejakowatz	if (fApplication->Init() != B_OK) {
55152a38012Sejakowatz		fprintf(stderr, "Failed to initialize application.\n");
55252a38012Sejakowatz		delete fApplication;
55352a38012Sejakowatz		fApplication = NULL;
55452a38012Sejakowatz	}
55552a38012Sejakowatz	fVolumeCreated = false;
55652a38012Sejakowatz}
55752a38012Sejakowatz
55852a38012Sejakowatz// tearDown
55952a38012Sejakowatzvoid
56052a38012SejakowatzQueryTest::tearDown()
56152a38012Sejakowatz{
56252a38012Sejakowatz	BasicTest::tearDown();
56352a38012Sejakowatz	if (fApplication) {
56452a38012Sejakowatz		fApplication->Terminate();
56552a38012Sejakowatz		delete fApplication;
56652a38012Sejakowatz		fApplication = NULL;
56752a38012Sejakowatz	}
56852a38012Sejakowatz	if (fVolumeCreated) {
56952a38012Sejakowatz		deleteVolume(testVolumeImage, testMountPoint);
57052a38012Sejakowatz		fVolumeCreated = false;
57152a38012Sejakowatz	}
57252a38012Sejakowatz}
57352a38012Sejakowatz
57452a38012Sejakowatz// TestPredicate
57552a38012Sejakowatzstatic
57652a38012Sejakowatzvoid
57752a38012SejakowatzTestPredicate(const PredicateNode &predicateNode, status_t pushResult = B_OK,
57852a38012Sejakowatz			  status_t getResult = B_OK)
57952a38012Sejakowatz{
58052a38012Sejakowatz	BString predicateString = predicateNode.toString().String();
58152a38012Sejakowatz//printf("predicate: `%s'\n", predicateString.String());
58252a38012Sejakowatz	// GetPredicate(BString *)
58352a38012Sejakowatz	{
58452a38012Sejakowatz		Query query;
58552a38012Sejakowatz//		CPPUNIT_ASSERT( predicateNode.push(query) == pushResult );
58652a38012Sejakowatzstatus_t error = predicateNode.push(query);
58752a38012Sejakowatzif (error != pushResult) {
58852a38012Sejakowatzprintf("predicate: `%s'\n", predicateString.String());
58952a38012Sejakowatzprintf("error: %lx vs %lx\n", error, pushResult);
59052a38012Sejakowatz}
59152a38012SejakowatzCPPUNIT_ASSERT( error == pushResult );
59252a38012Sejakowatz		if (pushResult == B_OK) {
59352a38012Sejakowatz			BString predicate;
59452a38012Sejakowatz//			CPPUNIT_ASSERT( query.GetPredicate(&predicate) == getResult );
59552a38012Sejakowatzerror = query.GetPredicate(&predicate);
59652a38012Sejakowatzif (error != getResult) {
59752a38012Sejakowatzprintf("predicate: `%s'\n", predicateString.String());
59852a38012Sejakowatzprintf("error: %lx vs %lx\n", error, getResult);
59952a38012Sejakowatz}
60052a38012SejakowatzCPPUNIT_ASSERT( error == getResult );
60152a38012Sejakowatz			if (getResult == B_OK) {
60252a38012Sejakowatz				CPPUNIT_ASSERT( (int32)query.PredicateLength()
60352a38012Sejakowatz								== predicateString.Length() + 1 );
60452a38012Sejakowatz				CPPUNIT_ASSERT( predicateString == predicate );
60552a38012Sejakowatz			}
60652a38012Sejakowatz		}
60752a38012Sejakowatz	}
60852a38012Sejakowatz	// GetPredicate(char *, size_t)
60952a38012Sejakowatz	{
61052a38012Sejakowatz		Query query;
61152a38012Sejakowatz		CPPUNIT_ASSERT( predicateNode.push(query) == pushResult );
61252a38012Sejakowatz		if (pushResult == B_OK) {
61352a38012Sejakowatz			char buffer[1024];
61452a38012Sejakowatz			CPPUNIT_ASSERT( query.GetPredicate(buffer, sizeof(buffer))
61552a38012Sejakowatz							== getResult );
61652a38012Sejakowatz			if (getResult == B_OK)
61752a38012Sejakowatz				CPPUNIT_ASSERT( predicateString == buffer );
61852a38012Sejakowatz		}
61952a38012Sejakowatz	}
62052a38012Sejakowatz	// PredicateLength()
62152a38012Sejakowatz	{
62252a38012Sejakowatz		Query query;
62352a38012Sejakowatz		CPPUNIT_ASSERT( predicateNode.push(query) == pushResult );
62452a38012Sejakowatz		if (pushResult == B_OK) {
62552a38012Sejakowatz			size_t expectedLength
62652a38012Sejakowatz				= (getResult == B_OK ? predicateString.Length() + 1 : 0);
62752a38012Sejakowatz			CPPUNIT_ASSERT( query.PredicateLength() == expectedLength );
62852a38012Sejakowatz		}
62952a38012Sejakowatz	}
63052a38012Sejakowatz	// SetPredicate()
63152a38012Sejakowatz	{
63252a38012Sejakowatz		Query query;
63352a38012Sejakowatz		CPPUNIT_ASSERT( query.SetPredicate(predicateString.String()) == B_OK );
63452a38012Sejakowatz		CPPUNIT_ASSERT( (int32)query.PredicateLength()
63552a38012Sejakowatz						== predicateString.Length() + 1 );
63652a38012Sejakowatz		BString predicate;
63752a38012Sejakowatz		CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK );
63852a38012Sejakowatz		CPPUNIT_ASSERT( predicateString == predicate );
63952a38012Sejakowatz	}
64052a38012Sejakowatz}
64152a38012Sejakowatz
64252a38012Sejakowatz// TestOperator
64352a38012Sejakowatzstatic
64452a38012Sejakowatzvoid
64552a38012SejakowatzTestOperator(query_op op)
64652a38012Sejakowatz{
64752a38012Sejakowatz	// well formed
64852a38012Sejakowatz	TestPredicate(OpNode(op,
64952a38012Sejakowatz		new AttributeNode("attribute"),
65052a38012Sejakowatz		new Int32Node(42)
65152a38012Sejakowatz	));
65252a38012Sejakowatz	TestPredicate(OpNode(op,
65352a38012Sejakowatz		new AttributeNode("attribute"),
65452a38012Sejakowatz		new StringNode("some string")
65552a38012Sejakowatz	));
65652a38012Sejakowatz	TestPredicate(OpNode(op,
65752a38012Sejakowatz		new AttributeNode("attribute"),
65852a38012Sejakowatz		new DateNode("22 May 2002")
65952a38012Sejakowatz	));
66052a38012Sejakowatz	// ill formed
66152a38012Sejakowatz	TestPredicate(OpNode(op, new AttributeNode("attribute"), NULL), B_OK,
66252a38012Sejakowatz				  B_NO_INIT);
66352a38012Sejakowatz// R5: crashs when pushing B_CONTAINS/B_BEGINS/ENDS_WITH on an empty stack
664aad997bdSTyler Dauwalder#if TEST_R5
66552a38012Sejakowatzif (op < B_CONTAINS || op > B_ENDS_WITH)
66652a38012Sejakowatz#endif
66752a38012Sejakowatz	TestPredicate(OpNode(op, NULL, NULL), B_OK, B_NO_INIT);
66852a38012Sejakowatz	TestPredicate(OpNode(op,
66952a38012Sejakowatz		new AttributeNode("attribute"),
67052a38012Sejakowatz		new DateNode("22 May 2002")
67152a38012Sejakowatz	).addChild(new Int32Node(42)), B_OK, B_NO_INIT);
67252a38012Sejakowatz}
67352a38012Sejakowatz
67452a38012Sejakowatz// PredicateTest
67552a38012Sejakowatzvoid
67652a38012SejakowatzQueryTest::PredicateTest()
67752a38012Sejakowatz{
67852a38012Sejakowatz	// tests:
67952a38012Sejakowatz	// * Push*()
68052a38012Sejakowatz	// * Set/GetPredicate(), PredicateLength()
68152a38012Sejakowatz	// empty predicate
682aad997bdSTyler Dauwalder	NextSubTest();
68352a38012Sejakowatz	char buffer[1024];
68452a38012Sejakowatz	{
68552a38012Sejakowatz		Query query;
68652a38012Sejakowatz		BString predicate;
68752a38012Sejakowatz		CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_NO_INIT );
68852a38012Sejakowatz	}
68952a38012Sejakowatz	{
69052a38012Sejakowatz		Query query;
69152a38012Sejakowatz		CPPUNIT_ASSERT( query.GetPredicate(buffer, sizeof(buffer))
69252a38012Sejakowatz						== B_NO_INIT );
69352a38012Sejakowatz	}
69452a38012Sejakowatz	// one element predicates
695aad997bdSTyler Dauwalder	NextSubTest();
69652a38012Sejakowatz	TestPredicate(Int32Node(42));
69752a38012Sejakowatz	TestPredicate(UInt32Node(42));
69852a38012Sejakowatz	TestPredicate(Int64Node(42));
69952a38012Sejakowatz// R5: buggy PushUInt64() implementation.
700aad997bdSTyler Dauwalder#if !TEST_R5
70152a38012Sejakowatz	TestPredicate(UInt64Node(42));
70252a38012Sejakowatz#endif
70352a38012Sejakowatz	TestPredicate(FloatNode(42));
70452a38012Sejakowatz	TestPredicate(DoubleNode(42));
70552a38012Sejakowatz	TestPredicate(StringNode("some \" chars ' to \\ be ( escaped ) or "
70652a38012Sejakowatz							 "% not!"));
70752a38012Sejakowatz	TestPredicate(StringNode("some \" chars ' to \\ be ( escaped ) or "
70852a38012Sejakowatz							 "% not!", true));
70952a38012Sejakowatz	TestPredicate(DateNode("+15 min"));
71052a38012Sejakowatz	TestPredicate(DateNode("22 May 2002"));
71152a38012Sejakowatz	TestPredicate(DateNode("tomorrow"));
71252a38012Sejakowatz	TestPredicate(DateNode("17:57"));
71352a38012Sejakowatz	TestPredicate(DateNode("invalid date"), B_BAD_VALUE);
71452a38012Sejakowatz	TestPredicate(AttributeNode("some attribute"));
71552a38012Sejakowatz	// operators
716aad997bdSTyler Dauwalder	NextSubTest();
71752a38012Sejakowatz	TestOperator(B_EQ);
71852a38012Sejakowatz	TestOperator(B_GT);
71952a38012Sejakowatz	TestOperator(B_GE);
72052a38012Sejakowatz	TestOperator(B_LT);
72152a38012Sejakowatz	TestOperator(B_LE);
72252a38012Sejakowatz	TestOperator(B_NE);
72352a38012Sejakowatz	TestOperator(B_CONTAINS);
72452a38012Sejakowatz	TestOperator(B_BEGINS_WITH);
72552a38012Sejakowatz	TestOperator(B_ENDS_WITH);
72652a38012Sejakowatz	TestOperator(B_AND);
72752a38012Sejakowatz	TestOperator(B_OR);
72852a38012Sejakowatz	{
72952a38012Sejakowatz		// B_NOT
73052a38012Sejakowatz		TestPredicate(OpNode(B_NOT, new AttributeNode("attribute")));
73152a38012Sejakowatz		TestPredicate(OpNode(B_NOT, new Int32Node(42)));
73252a38012Sejakowatz		TestPredicate(OpNode(B_NOT, new StringNode("some string")));
73352a38012Sejakowatz		TestPredicate(OpNode(B_NOT, new StringNode("some string", true)));
73452a38012Sejakowatz		TestPredicate(OpNode(B_NOT, new DateNode("22 May 2002")));
73552a38012Sejakowatz		TestPredicate(OpNode(B_NOT, NULL), B_OK, B_NO_INIT);
73652a38012Sejakowatz	}
73752a38012Sejakowatz	// well formed, legal predicate
738aad997bdSTyler Dauwalder	NextSubTest();
73952a38012Sejakowatz	TestPredicate(OpNode(B_AND,
74052a38012Sejakowatz		new OpNode(B_CONTAINS,
74152a38012Sejakowatz			new AttributeNode("attribute"),
74252a38012Sejakowatz			new StringNode("hello")
74352a38012Sejakowatz		),
74452a38012Sejakowatz		new OpNode(B_OR,
74552a38012Sejakowatz			new OpNode(B_NOT,
74652a38012Sejakowatz				new OpNode(B_EQ,
74752a38012Sejakowatz					new AttributeNode("attribute2"),
74852a38012Sejakowatz					new UInt32Node(7)
74952a38012Sejakowatz				),
75052a38012Sejakowatz				NULL
75152a38012Sejakowatz			),
75252a38012Sejakowatz			new OpNode(B_GE,
75352a38012Sejakowatz				new AttributeNode("attribute3"),
75452a38012Sejakowatz				new DateNode("20 May 2002")
75552a38012Sejakowatz			)
75652a38012Sejakowatz		)
75752a38012Sejakowatz	));
75852a38012Sejakowatz	// well formed, illegal predicate
759aad997bdSTyler Dauwalder	NextSubTest();
76052a38012Sejakowatz	TestPredicate(OpNode(B_EQ,
76152a38012Sejakowatz		new StringNode("hello"),
76252a38012Sejakowatz		new OpNode(B_LE,
76352a38012Sejakowatz			new OpNode(B_NOT,
76452a38012Sejakowatz				new Int32Node(17),
76552a38012Sejakowatz				NULL
76652a38012Sejakowatz			),
76752a38012Sejakowatz			new DateNode("20 May 2002")
76852a38012Sejakowatz		)
76952a38012Sejakowatz	));
77052a38012Sejakowatz	// ill formed predicates
77152a38012Sejakowatz	// Some have already been tested in TestOperator, so we only test a few
77252a38012Sejakowatz	// special ones.
773aad997bdSTyler Dauwalder	NextSubTest();
77452a38012Sejakowatz	TestPredicate(ListNode(new Int32Node(42), new StringNode("hello!")),
77552a38012Sejakowatz				  B_OK, B_NO_INIT);
77652a38012Sejakowatz	TestPredicate(OpNode(B_EQ,
77752a38012Sejakowatz		new StringNode("hello"),
77852a38012Sejakowatz		new OpNode(B_NOT, NULL)
77952a38012Sejakowatz	), B_OK, B_NO_INIT);
78052a38012Sejakowatz	// precedence Push*() over SetPredicate()
781aad997bdSTyler Dauwalder	NextSubTest();
78252a38012Sejakowatz	{
78352a38012Sejakowatz		Query query;
78452a38012Sejakowatz		OpNode predicate1(B_CONTAINS,
78552a38012Sejakowatz			new AttributeNode("attribute"),
78652a38012Sejakowatz			new StringNode("hello")
78752a38012Sejakowatz		);
78852a38012Sejakowatz		StringNode predicate2("I'm the loser. :��-(");
78952a38012Sejakowatz		CPPUNIT_ASSERT( predicate1.push(query) == B_OK );
79052a38012Sejakowatz		CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String())
79152a38012Sejakowatz						== B_OK );
79252a38012Sejakowatz		BString predicate;
79352a38012Sejakowatz		CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK );
79452a38012Sejakowatz		CPPUNIT_ASSERT( predicate == predicate1.toString() );
79552a38012Sejakowatz	}
79652a38012Sejakowatz	// GetPredicate() clears the stack
797aad997bdSTyler Dauwalder	NextSubTest();
79852a38012Sejakowatz	{
79952a38012Sejakowatz		Query query;
80052a38012Sejakowatz		OpNode predicate1(B_CONTAINS,
80152a38012Sejakowatz			new AttributeNode("attribute"),
80252a38012Sejakowatz			new StringNode("hello")
80352a38012Sejakowatz		);
80452a38012Sejakowatz		StringNode predicate2("I'm the winner. :-)");
80552a38012Sejakowatz		CPPUNIT_ASSERT( predicate1.push(query) == B_OK );
80652a38012Sejakowatz		BString predicate;
80752a38012Sejakowatz		CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK );
80852a38012Sejakowatz		CPPUNIT_ASSERT( predicate == predicate1.toString() );
80952a38012Sejakowatz		CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String())
81052a38012Sejakowatz						== B_OK );
81152a38012Sejakowatz		CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK );
81252a38012Sejakowatz		CPPUNIT_ASSERT( predicate == predicate2.toString() );
81352a38012Sejakowatz	}
81452a38012Sejakowatz	// PredicateLength() clears the stack
815aad997bdSTyler Dauwalder	NextSubTest();
81652a38012Sejakowatz	{
81752a38012Sejakowatz		Query query;
81852a38012Sejakowatz		OpNode predicate1(B_CONTAINS,
81952a38012Sejakowatz			new AttributeNode("attribute"),
82052a38012Sejakowatz			new StringNode("hello")
82152a38012Sejakowatz		);
82252a38012Sejakowatz		StringNode predicate2("I'm the winner. :-)");
82352a38012Sejakowatz		CPPUNIT_ASSERT( predicate1.push(query) == B_OK );
82452a38012Sejakowatz		CPPUNIT_ASSERT( (int32)query.PredicateLength()
82552a38012Sejakowatz						== predicate1.toString().Length() + 1 );
82652a38012Sejakowatz		CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String())
82752a38012Sejakowatz						== B_OK );
82852a38012Sejakowatz		BString predicate;
82952a38012Sejakowatz		CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK );
83052a38012Sejakowatz		CPPUNIT_ASSERT( predicate == predicate2.toString() );
83152a38012Sejakowatz	}
83252a38012Sejakowatz	// SetPredicate(), Push*() fail after Fetch()
833aad997bdSTyler Dauwalder	NextSubTest();
83452a38012Sejakowatz	{
83552a38012Sejakowatz		Query query;
83652a38012Sejakowatz		CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
83752a38012Sejakowatz						== B_OK );
83852a38012Sejakowatz		BVolume volume(dev_for_path("/boot"));
83952a38012Sejakowatz		CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
84052a38012Sejakowatz		CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
84152a38012Sejakowatz		CPPUNIT_ASSERT( query.Fetch() == B_OK );
84252a38012Sejakowatz		CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExistEither\"")
84352a38012Sejakowatz						== B_NOT_ALLOWED );
84452a38012Sejakowatz// R5: Push*()ing a new predicate does work, though it doesn't make any sense
845aad997bdSTyler Dauwalder#if TEST_R5
84652a38012Sejakowatz		CPPUNIT_ASSERT( query.PushDate("20 May 2002") == B_OK );
84752a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((int32)42) == B_OK );
84852a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((uint32)42) == B_OK );
84952a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((int64)42) == B_OK );
85052a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((uint64)42) == B_OK );
85152a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((float)42) == B_OK );
85252a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((double)42) == B_OK );
85352a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue("hello") == B_OK );
85452a38012Sejakowatz		CPPUNIT_ASSERT( query.PushAttr("attribute") == B_OK );
85552a38012Sejakowatz		CPPUNIT_ASSERT( query.PushOp(B_EQ) == B_OK );
85652a38012Sejakowatz#else
85752a38012Sejakowatz		CPPUNIT_ASSERT( query.PushDate("20 May 2002") == B_NOT_ALLOWED );
85852a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((int32)42) == B_NOT_ALLOWED );
85952a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((uint32)42) == B_NOT_ALLOWED );
86052a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((int64)42) == B_NOT_ALLOWED );
86152a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((uint64)42) == B_NOT_ALLOWED );
86252a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((float)42) == B_NOT_ALLOWED );
86352a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue((double)42) == B_NOT_ALLOWED );
86452a38012Sejakowatz		CPPUNIT_ASSERT( query.PushValue("hello") == B_NOT_ALLOWED );
86552a38012Sejakowatz		CPPUNIT_ASSERT( query.PushAttr("attribute") == B_NOT_ALLOWED );
86652a38012Sejakowatz		CPPUNIT_ASSERT( query.PushOp(B_EQ) == B_NOT_ALLOWED );
86752a38012Sejakowatz#endif
86852a38012Sejakowatz	}
86952a38012Sejakowatz	// SetPredicate(): bad args
87052a38012Sejakowatz// R5: crashes when passing NULL to Set/GetPredicate()
871aad997bdSTyler Dauwalder#if !TEST_R5
872aad997bdSTyler Dauwalder	NextSubTest();
87352a38012Sejakowatz	{
87452a38012Sejakowatz		Query query;
87552a38012Sejakowatz		CPPUNIT_ASSERT( query.SetPredicate(NULL) == B_BAD_VALUE );
87652a38012Sejakowatz		CPPUNIT_ASSERT( query.SetPredicate("hello") == B_OK );
87752a38012Sejakowatz		CPPUNIT_ASSERT( query.GetPredicate(NULL) == B_BAD_VALUE );
87852a38012Sejakowatz		CPPUNIT_ASSERT( query.GetPredicate(NULL, 10) == B_BAD_VALUE );
87952a38012Sejakowatz	}
88052a38012Sejakowatz#endif
88152a38012Sejakowatz}
88252a38012Sejakowatz
88352a38012Sejakowatz// ParameterTest
88452a38012Sejakowatzvoid
88552a38012SejakowatzQueryTest::ParameterTest()
88652a38012Sejakowatz{
88752a38012Sejakowatz	// tests:
88852a38012Sejakowatz	// * SetVolume, TargetDevice()
88952a38012Sejakowatz	// * SetTarget(), IsLive()
89052a38012Sejakowatz
89152a38012Sejakowatz	// SetVolume(), TargetDevice()
89252a38012Sejakowatz	// uninitialized BQuery
893aad997bdSTyler Dauwalder	NextSubTest();
89452a38012Sejakowatz	{
89552a38012Sejakowatz		BQuery query;
89652a38012Sejakowatz		CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR );
89752a38012Sejakowatz	}
89852a38012Sejakowatz	// NULL volume
89952a38012Sejakowatz// R5: crashs when passing a NULL BVolume
900aad997bdSTyler Dauwalder#if !TEST_R5
901aad997bdSTyler Dauwalder	NextSubTest();
90252a38012Sejakowatz	{
90352a38012Sejakowatz		BQuery query;
90452a38012Sejakowatz		CPPUNIT_ASSERT( query.SetVolume(NULL) == B_BAD_VALUE );
90552a38012Sejakowatz		CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR );
90652a38012Sejakowatz	}
90752a38012Sejakowatz#endif
90852a38012Sejakowatz	// invalid volume
909aad997bdSTyler Dauwalder	NextSubTest();
91052a38012Sejakowatz	{
91152a38012Sejakowatz		BQuery query;
91252a38012Sejakowatz		BVolume volume(-2);
91352a38012Sejakowatz		CPPUNIT_ASSERT( volume.InitCheck() == B_BAD_VALUE );
91452a38012Sejakowatz		CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
91552a38012Sejakowatz		CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR );
91652a38012Sejakowatz	}
91752a38012Sejakowatz	// valid volume
918aad997bdSTyler Dauwalder	NextSubTest();
91952a38012Sejakowatz	{
92052a38012Sejakowatz		BQuery query;
92152a38012Sejakowatz		dev_t device = dev_for_path("/boot");
92252a38012Sejakowatz		BVolume volume(device);
92352a38012Sejakowatz		CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
92452a38012Sejakowatz		CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
92552a38012Sejakowatz		CPPUNIT_ASSERT( query.TargetDevice() == device );
92652a38012Sejakowatz	}
92752a38012Sejakowatz
92852a38012Sejakowatz	// SetTarget(), IsLive()
92952a38012Sejakowatz	// uninitialized BQuery
930aad997bdSTyler Dauwalder	NextSubTest();
93152a38012Sejakowatz	{
93252a38012Sejakowatz		BQuery query;
93352a38012Sejakowatz		CPPUNIT_ASSERT( query.IsLive() == false );
93452a38012Sejakowatz	}
93552a38012Sejakowatz	// uninitialized BMessenger
936aad997bdSTyler Dauwalder	NextSubTest();
93752a38012Sejakowatz	{
93852a38012Sejakowatz		BQuery query;
93952a38012Sejakowatz		BMessenger messenger;
94052a38012Sejakowatz		CPPUNIT_ASSERT( messenger.IsValid() == false );
94152a38012Sejakowatz		CPPUNIT_ASSERT( query.SetTarget(messenger) == B_BAD_VALUE );
94252a38012Sejakowatz		CPPUNIT_ASSERT( query.IsLive() == false );
94352a38012Sejakowatz	}
94452a38012Sejakowatz	// valid BMessenger
945aad997bdSTyler Dauwalder	NextSubTest();
94652a38012Sejakowatz	{
94752a38012Sejakowatz		BQuery query;
94852a38012Sejakowatz		BMessenger messenger(&fApplication->Handler());
94952a38012Sejakowatz		CPPUNIT_ASSERT( messenger.IsValid() == true );
95052a38012Sejakowatz		CPPUNIT_ASSERT( query.SetTarget(messenger) == B_OK );
95152a38012Sejakowatz		CPPUNIT_ASSERT( query.IsLive() == true );
95252a38012Sejakowatz	}
95352a38012Sejakowatz
95452a38012Sejakowatz	// SetVolume/Target() fail after Fetch()
955aad997bdSTyler Dauwalder	NextSubTest();
95652a38012Sejakowatz	{
95752a38012Sejakowatz		Query query;
95852a38012Sejakowatz		CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
95952a38012Sejakowatz						== B_OK );
96052a38012Sejakowatz		BVolume volume(dev_for_path("/boot"));
96152a38012Sejakowatz		CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
96252a38012Sejakowatz		CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
96352a38012Sejakowatz		CPPUNIT_ASSERT( query.Fetch() == B_OK );
96452a38012Sejakowatz		CPPUNIT_ASSERT( query.SetVolume(&volume) == B_NOT_ALLOWED );
96552a38012Sejakowatz		BMessenger messenger(&fApplication->Handler());
96652a38012Sejakowatz		CPPUNIT_ASSERT( messenger.IsValid() == true );
96752a38012Sejakowatz		CPPUNIT_ASSERT( query.SetTarget(messenger) == B_NOT_ALLOWED );
96852a38012Sejakowatz	}
96952a38012Sejakowatz
97052a38012Sejakowatz	// Fetch() fails without a valid volume set
971aad997bdSTyler Dauwalder	NextSubTest();
97252a38012Sejakowatz	{
97352a38012Sejakowatz		Query query;
97452a38012Sejakowatz		CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
97552a38012Sejakowatz						== B_OK );
97652a38012Sejakowatz		CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT );
97752a38012Sejakowatz	}
97852a38012Sejakowatz}
97952a38012Sejakowatz
98052a38012Sejakowatz// TestFetchPredicateInit
98152a38012Sejakowatzstatic
98252a38012Sejakowatzvoid
98352a38012SejakowatzTestFetchPredicateInit(Query &query, TestSet &testSet, const char *mountPoint,
98452a38012Sejakowatz					   const char *predicate, QueryTestEntry **entries,
98552a38012Sejakowatz					   int32 entryCount)
98652a38012Sejakowatz{
98752a38012Sejakowatz	// init the query
98852a38012Sejakowatz	CPPUNIT_ASSERT( query.SetPredicate(predicate) == B_OK );
98952a38012Sejakowatz	BVolume volume(dev_for_path(mountPoint));
99052a38012Sejakowatz	CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
99152a38012Sejakowatz	CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
99252a38012Sejakowatz	CPPUNIT_ASSERT( query.Fetch() == B_OK );
99352a38012Sejakowatz	// init the test set
99452a38012Sejakowatz	testSet.clear();
99552a38012Sejakowatz	for (int32 i = 0; i < entryCount; i++)
99652a38012Sejakowatz		testSet.add(entries[i]->path);
99752a38012Sejakowatz}
99852a38012Sejakowatz
99952a38012Sejakowatz
100052a38012Sejakowatz// TestFetchPredicate
100152a38012Sejakowatzstatic
100252a38012Sejakowatzvoid
100352a38012SejakowatzTestFetchPredicate(const char *mountPoint, const char *predicate,
100452a38012Sejakowatz				   QueryTestEntry **entries, int32 entryCount)
100552a38012Sejakowatz{
100652a38012Sejakowatz	// GetNextEntry()
100752a38012Sejakowatz	{
100852a38012Sejakowatz		Query query;
100952a38012Sejakowatz		TestSet testSet;
101052a38012Sejakowatz		TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries,
101152a38012Sejakowatz							   entryCount);
101252a38012Sejakowatz		BEntry entry;
101352a38012Sejakowatz		while (query.GetNextEntry(&entry) == B_OK) {
1014c3362b0aSIngo Weinhold// Haiku supports rewinding queries, R5 does not.
1015c3362b0aSIngo Weinhold#ifdef TEST_R5
101652a38012Sejakowatz			CPPUNIT_ASSERT( query.Rewind() == B_ERROR );
1017c3362b0aSIngo Weinhold#endif
101852a38012Sejakowatz			CPPUNIT_ASSERT( query.CountEntries() == B_ERROR );
101952a38012Sejakowatz			BPath path;
102052a38012Sejakowatz			CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
102152a38012Sejakowatz			CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK );
102252a38012Sejakowatz			CPPUNIT_ASSERT( testSet.test(path.Path()) == true );
102352a38012Sejakowatz		}
102452a38012Sejakowatz		CPPUNIT_ASSERT( testSet.testDone() == true );
102552a38012Sejakowatz		CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND );
102652a38012Sejakowatz	}
102752a38012Sejakowatz	// GetNextRef()
102852a38012Sejakowatz	{
102952a38012Sejakowatz		Query query;
103052a38012Sejakowatz		TestSet testSet;
103152a38012Sejakowatz		TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries,
103252a38012Sejakowatz							   entryCount);
103352a38012Sejakowatz		entry_ref ref;
103452a38012Sejakowatz		while (query.GetNextRef(&ref) == B_OK) {
1035c3362b0aSIngo Weinhold// Haiku supports rewinding queries, R5 does not.
1036c3362b0aSIngo Weinhold#ifdef TEST_R5
103752a38012Sejakowatz			CPPUNIT_ASSERT( query.Rewind() == B_ERROR );
1038c3362b0aSIngo Weinhold#endif
103952a38012Sejakowatz			CPPUNIT_ASSERT( query.CountEntries() == B_ERROR );
104052a38012Sejakowatz			BPath path(&ref);
104152a38012Sejakowatz			CPPUNIT_ASSERT( path.InitCheck() == B_OK );
104252a38012Sejakowatz			CPPUNIT_ASSERT( testSet.test(path.Path()) == true );
104352a38012Sejakowatz		}
104452a38012Sejakowatz		CPPUNIT_ASSERT( testSet.testDone() == true );
104552a38012Sejakowatz		CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_ENTRY_NOT_FOUND );
104652a38012Sejakowatz	}
104752a38012Sejakowatz	// GetNextDirents()
104852a38012Sejakowatz	{
104952a38012Sejakowatz		Query query;
105052a38012Sejakowatz		TestSet testSet;
105152a38012Sejakowatz		TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries,
105252a38012Sejakowatz							   entryCount);
105352a38012Sejakowatz		size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10;
105452a38012Sejakowatz		char buffer[bufSize];
105552a38012Sejakowatz		dirent *ents = (dirent *)buffer;
105652a38012Sejakowatz		while (query.GetNextDirents(ents, bufSize, 1) == 1) {
1057c3362b0aSIngo Weinhold// Haiku supports rewinding queries, R5 does not.
1058c3362b0aSIngo Weinhold#ifdef TEST_R5
105952a38012Sejakowatz			CPPUNIT_ASSERT( query.Rewind() == B_ERROR );
1060c3362b0aSIngo Weinhold#endif
106152a38012Sejakowatz			CPPUNIT_ASSERT( query.CountEntries() == B_ERROR );
106252a38012Sejakowatz			entry_ref ref(ents->d_pdev, ents->d_pino, ents->d_name);
106352a38012Sejakowatz			BPath path(&ref);
106452a38012Sejakowatz			CPPUNIT_ASSERT( path.InitCheck() == B_OK );
106552a38012Sejakowatz			CPPUNIT_ASSERT( testSet.test(path.Path()) == true );
106652a38012Sejakowatz		}
106752a38012Sejakowatz		CPPUNIT_ASSERT( testSet.testDone() == true );
106852a38012Sejakowatz		CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) == 0 );
106952a38012Sejakowatz	}
107052a38012Sejakowatz	// interleaving use of the different methods
107152a38012Sejakowatz	{
107252a38012Sejakowatz		Query query;
107352a38012Sejakowatz		TestSet testSet;
107452a38012Sejakowatz		TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries,
107552a38012Sejakowatz							   entryCount);
107652a38012Sejakowatz		size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10;
107752a38012Sejakowatz		char buffer[bufSize];
107852a38012Sejakowatz		dirent *ents = (dirent *)buffer;
107952a38012Sejakowatz		entry_ref ref;
108052a38012Sejakowatz		BEntry entry;
108152a38012Sejakowatz		while (query.GetNextDirents(ents, bufSize, 1) == 1) {
1082c3362b0aSIngo Weinhold// Haiku supports rewinding queries, R5 does not.
1083c3362b0aSIngo Weinhold#ifdef TEST_R5
108452a38012Sejakowatz			CPPUNIT_ASSERT( query.Rewind() == B_ERROR );
1085c3362b0aSIngo Weinhold#endif
108652a38012Sejakowatz			CPPUNIT_ASSERT( query.CountEntries() == B_ERROR );
108752a38012Sejakowatz			entry_ref entref(ents->d_pdev, ents->d_pino, ents->d_name);
108852a38012Sejakowatz			BPath entpath(&entref);
108952a38012Sejakowatz			CPPUNIT_ASSERT( entpath.InitCheck() == B_OK );
109052a38012Sejakowatz			CPPUNIT_ASSERT( testSet.test(entpath.Path()) == true );
109152a38012Sejakowatz			if (query.GetNextRef(&ref) == B_OK) {
109252a38012Sejakowatz				BPath refpath(&ref);
109352a38012Sejakowatz				CPPUNIT_ASSERT( refpath.InitCheck() == B_OK );
109452a38012Sejakowatz				CPPUNIT_ASSERT( testSet.test(refpath.Path()) == true );
109552a38012Sejakowatz			}
109652a38012Sejakowatz			if (query.GetNextEntry(&entry) == B_OK) {
109752a38012Sejakowatz				BPath path;
109852a38012Sejakowatz				CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
109952a38012S