242a6db230
the rest of the test classes. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@407 a95241bf-73f2-0310-859d-f6bbb57e9c96
1467 lines
40 KiB
C++
1467 lines
40 KiB
C++
// QueryTest.cpp
|
||
|
||
#include <ctype.h>
|
||
#include <fs_info.h>
|
||
#include <stdio.h>
|
||
#include <string>
|
||
#include <unistd.h>
|
||
|
||
#include "QueryTest.h"
|
||
|
||
#include <Application.h>
|
||
#include <Message.h>
|
||
#include <MessageQueue.h>
|
||
#include <Messenger.h>
|
||
#include <NodeMonitor.h>
|
||
#include <OS.h>
|
||
#include <Path.h>
|
||
#include <Query.h>
|
||
#include <String.h>
|
||
#include <Volume.h>
|
||
#include <TestApp.h>
|
||
#include <TestUtils.h>
|
||
|
||
// Query
|
||
|
||
class Query : public BQuery {
|
||
public:
|
||
#if TEST_R5
|
||
status_t PushValue(int32 value) { PushInt32(value); return B_OK; }
|
||
status_t PushValue(uint32 value) { PushUInt32(value); return B_OK; }
|
||
status_t PushValue(int64 value) { PushInt64(value); return B_OK; }
|
||
status_t PushValue(uint64 value) { PushUInt64(value); return B_OK; }
|
||
status_t PushValue(float value) { PushFloat(value); return B_OK; }
|
||
status_t PushValue(double value) { PushDouble(value); return B_OK; }
|
||
status_t PushValue(const BString value, bool caseInsensitive = false)
|
||
{
|
||
PushString(value.String(), caseInsensitive); return B_OK;
|
||
}
|
||
status_t PushAttr(const char *attribute)
|
||
{
|
||
BQuery::PushAttr(attribute);
|
||
return B_OK;
|
||
}
|
||
status_t PushOp(query_op op)
|
||
{
|
||
BQuery::PushOp(op);
|
||
return B_OK;
|
||
}
|
||
#else
|
||
status_t PushValue(int32 value) { return PushInt32(value); }
|
||
status_t PushValue(uint32 value) { return PushUInt32(value); }
|
||
status_t PushValue(int64 value) { return PushInt64(value); }
|
||
status_t PushValue(uint64 value) { return PushUInt64(value); }
|
||
status_t PushValue(float value) { return PushFloat(value); }
|
||
status_t PushValue(double value) { return PushDouble(value); }
|
||
status_t PushValue(const BString value, bool caseInsensitive = false)
|
||
{
|
||
return PushString(value.String(), caseInsensitive);
|
||
}
|
||
#endif
|
||
};
|
||
|
||
|
||
// PredicateNode
|
||
|
||
class PredicateNode {
|
||
public:
|
||
virtual ~PredicateNode() {}
|
||
|
||
virtual status_t push(Query &query) const = 0;
|
||
virtual BString toString() const = 0;
|
||
};
|
||
|
||
|
||
// ValueNode
|
||
|
||
template<typename ValueType>
|
||
class ValueNode : public PredicateNode {
|
||
public:
|
||
ValueNode(ValueType v) : value(v) {}
|
||
|
||
virtual ~ValueNode() {}
|
||
|
||
virtual status_t push(Query &query) const
|
||
{
|
||
return query.PushValue(value);
|
||
}
|
||
|
||
virtual BString toString() const
|
||
{
|
||
return BString() << value;
|
||
}
|
||
|
||
ValueType value;
|
||
};
|
||
|
||
// float specialization
|
||
BString
|
||
ValueNode<float>::toString() const
|
||
{
|
||
char buffer[32];
|
||
sprintf(buffer, "0x%08lx", *(int32*)&value);
|
||
return BString() << buffer;
|
||
}
|
||
|
||
// double specialization
|
||
BString
|
||
ValueNode<double>::toString() const
|
||
{
|
||
char buffer[32];
|
||
sprintf(buffer, "0x%016Lx", *(int64*)&value);
|
||
return BString() << buffer;
|
||
}
|
||
|
||
// StringNode
|
||
|
||
class StringNode : public PredicateNode {
|
||
public:
|
||
StringNode(BString v, bool caseInsensitive = false)
|
||
: value(v), caseInsensitive(caseInsensitive)
|
||
{
|
||
}
|
||
|
||
virtual ~StringNode() {}
|
||
|
||
virtual status_t push(Query &query) const
|
||
{
|
||
return query.PushValue(value, caseInsensitive);
|
||
}
|
||
|
||
virtual BString toString() const
|
||
{
|
||
BString escaped;
|
||
if (caseInsensitive) {
|
||
const char *str = value.String();
|
||
int32 len = value.Length();
|
||
for (int32 i = 0; i < len; i++) {
|
||
char c = str[i];
|
||
if (isalpha(c)) {
|
||
int lower = tolower(c);
|
||
int upper = toupper(c);
|
||
if (lower < 0 || upper < 0)
|
||
escaped << c;
|
||
else
|
||
escaped << "[" << (char)lower << (char)upper << "]";
|
||
} else
|
||
escaped << c;
|
||
}
|
||
} else
|
||
escaped = value;
|
||
escaped.CharacterEscape("\"\\'", '\\');
|
||
return BString("\"") << escaped << "\"";
|
||
}
|
||
|
||
BString value;
|
||
bool caseInsensitive;
|
||
};
|
||
|
||
|
||
// DateNode
|
||
|
||
class DateNode : public PredicateNode {
|
||
public:
|
||
DateNode(BString v) : value(v) {}
|
||
|
||
virtual ~DateNode() {}
|
||
|
||
virtual status_t push(Query &query) const
|
||
{
|
||
return query.PushDate(value.String());
|
||
}
|
||
|
||
virtual BString toString() const
|
||
{
|
||
BString escaped(value);
|
||
escaped.CharacterEscape("%\"\\'", '\\');
|
||
return BString("%") << escaped << "%";
|
||
}
|
||
|
||
BString value;
|
||
};
|
||
|
||
|
||
// AttributeNode
|
||
|
||
class AttributeNode : public PredicateNode {
|
||
public:
|
||
AttributeNode(BString v) : value(v) {}
|
||
|
||
virtual ~AttributeNode() {}
|
||
|
||
virtual status_t push(Query &query) const
|
||
{
|
||
return query.PushAttr(value.String());
|
||
}
|
||
|
||
virtual BString toString() const
|
||
{
|
||
return value;
|
||
}
|
||
|
||
BString value;
|
||
};
|
||
|
||
|
||
// short hands
|
||
typedef ValueNode<int32> Int32Node;
|
||
typedef ValueNode<uint32> UInt32Node;
|
||
typedef ValueNode<int64> Int64Node;
|
||
typedef ValueNode<uint64> UInt64Node;
|
||
typedef ValueNode<float> FloatNode;
|
||
typedef ValueNode<double> DoubleNode;
|
||
|
||
|
||
// ListNode
|
||
|
||
class ListNode : public PredicateNode {
|
||
public:
|
||
ListNode(PredicateNode *child1 = NULL, PredicateNode *child2 = NULL,
|
||
PredicateNode *child3 = NULL, PredicateNode *child4 = NULL,
|
||
PredicateNode *child5 = NULL, PredicateNode *child6 = NULL)
|
||
: children()
|
||
{
|
||
addChild(child1);
|
||
addChild(child2);
|
||
addChild(child3);
|
||
addChild(child4);
|
||
addChild(child5);
|
||
addChild(child6);
|
||
}
|
||
|
||
virtual ~ListNode()
|
||
{
|
||
for (int32 i = 0; PredicateNode *child = childAt(i); i++)
|
||
delete child;
|
||
}
|
||
|
||
virtual status_t push(Query &query) const
|
||
{
|
||
status_t error = B_OK;
|
||
for (int32 i = 0; PredicateNode *child = childAt(i); i++) {
|
||
error = child->push(query);
|
||
if (error != B_OK)
|
||
break;
|
||
}
|
||
return error;
|
||
}
|
||
|
||
virtual BString toString() const
|
||
{
|
||
return BString("INVALID");
|
||
}
|
||
|
||
ListNode &addChild(PredicateNode *child)
|
||
{
|
||
if (child)
|
||
children.AddItem(child);
|
||
return *this;
|
||
}
|
||
|
||
PredicateNode *childAt(int32 index) const
|
||
{
|
||
return (PredicateNode*)children.ItemAt(index);
|
||
}
|
||
|
||
BList children;
|
||
};
|
||
|
||
// OpNode
|
||
|
||
class OpNode : public ListNode {
|
||
public:
|
||
OpNode(query_op op, PredicateNode *left, PredicateNode *right = NULL)
|
||
: ListNode(left, right), op(op) {}
|
||
|
||
virtual ~OpNode() { }
|
||
|
||
virtual status_t push(Query &query) const
|
||
{
|
||
status_t error = ListNode::push(query);
|
||
if (error == B_OK)
|
||
error = query.PushOp(op);
|
||
return error;
|
||
}
|
||
|
||
virtual BString toString() const
|
||
{
|
||
PredicateNode *left = childAt(0);
|
||
PredicateNode *right = childAt(1);
|
||
if (!left)
|
||
return "INVALID ARGS";
|
||
BString result;
|
||
BString leftString = left->toString();
|
||
BString rightString;
|
||
if (right)
|
||
rightString = right->toString();
|
||
switch (op) {
|
||
case B_INVALID_OP:
|
||
result = "INVALID";
|
||
break;
|
||
case B_EQ:
|
||
result << "(" << leftString << "==" << rightString << ")";
|
||
break;
|
||
case B_GT:
|
||
result << "(" << leftString << ">" << rightString << ")";
|
||
break;
|
||
case B_GE:
|
||
result << "(" << leftString << ">=" << rightString << ")";
|
||
break;
|
||
case B_LT:
|
||
result << "(" << leftString << "<" << rightString << ")";
|
||
break;
|
||
case B_LE:
|
||
result << "(" << leftString << "<=" << rightString << ")";
|
||
break;
|
||
case B_NE:
|
||
result << "(" << leftString << "!=" << rightString << ")";
|
||
break;
|
||
case B_CONTAINS:
|
||
{
|
||
StringNode *strNode = dynamic_cast<StringNode*>(right);
|
||
if (strNode) {
|
||
rightString = StringNode(BString("*") << strNode->value
|
||
<< "*").toString();
|
||
}
|
||
result << "(" << leftString << "==" << rightString << ")";
|
||
break;
|
||
}
|
||
case B_BEGINS_WITH:
|
||
{
|
||
StringNode *strNode = dynamic_cast<StringNode*>(right);
|
||
if (strNode) {
|
||
rightString = StringNode(BString(strNode->value) << "*")
|
||
.toString();
|
||
}
|
||
result << "(" << leftString << "==" << rightString << ")";
|
||
break;
|
||
}
|
||
case B_ENDS_WITH:
|
||
{
|
||
StringNode *strNode = dynamic_cast<StringNode*>(right);
|
||
if (strNode) {
|
||
rightString = StringNode(BString("*") << strNode->value)
|
||
.toString();
|
||
}
|
||
result << "(" << leftString << "==" << rightString << ")";
|
||
break;
|
||
}
|
||
case B_AND:
|
||
result << "(" << leftString << "&&" << rightString << ")";
|
||
break;
|
||
case B_OR:
|
||
result << "(" << leftString << "||" << rightString << ")";
|
||
break;
|
||
case B_NOT:
|
||
result << "(" << "!" << leftString << ")";
|
||
break;
|
||
case _B_RESERVED_OP_:
|
||
result = "RESERVED";
|
||
break;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
query_op op;
|
||
};
|
||
|
||
|
||
// QueryTestEntry
|
||
class QueryTestEntry {
|
||
public:
|
||
QueryTestEntry(string path, node_flavor kind,
|
||
const QueryTestEntry *linkTarget = NULL)
|
||
: path(path),
|
||
cpath(NULL),
|
||
kind(kind),
|
||
linkToPath(),
|
||
clinkToPath(NULL),
|
||
directory(-1),
|
||
node(-1),
|
||
name()
|
||
{
|
||
cpath = this->path.c_str();
|
||
if (linkTarget)
|
||
linkToPath = linkTarget->path;
|
||
clinkToPath = this->linkToPath.c_str();
|
||
}
|
||
|
||
string operator+(string leaf) const
|
||
{
|
||
return path + "/" + leaf;
|
||
}
|
||
|
||
string path;
|
||
const char *cpath;
|
||
node_flavor kind;
|
||
string linkToPath;
|
||
const char *clinkToPath;
|
||
ino_t directory;
|
||
ino_t node;
|
||
string name;
|
||
};
|
||
|
||
static const char *testVolumeImage = "/tmp/query-test-image";
|
||
static const char *testMountPoint = "/non-existing-mount-point";
|
||
|
||
// the test entry hierarchy:
|
||
// mountPoint
|
||
// + dir1
|
||
// + subdir11
|
||
// + subdir12
|
||
// + file11
|
||
// + file12
|
||
// + link11
|
||
// + dir2
|
||
// + subdir21
|
||
// + subdir22
|
||
// + subdir23
|
||
// + file21
|
||
// + file22
|
||
// + link21
|
||
// + dir3
|
||
// + subdir31
|
||
// + subdir32
|
||
// + file31
|
||
// + file32
|
||
// + link31
|
||
// + file1
|
||
// + file2
|
||
// + file3
|
||
// + link1
|
||
// + link2
|
||
// + link3
|
||
static QueryTestEntry mountPoint(testMountPoint, B_DIRECTORY_NODE);
|
||
static QueryTestEntry dir1(mountPoint + "dir1", B_DIRECTORY_NODE);
|
||
static QueryTestEntry subdir11(dir1 + "subdir11", B_DIRECTORY_NODE);
|
||
static QueryTestEntry subdir12(dir1 + "subdir12", B_DIRECTORY_NODE);
|
||
static QueryTestEntry file11(dir1 + "file11", B_FILE_NODE);
|
||
static QueryTestEntry file12(dir1 + "file12", B_FILE_NODE);
|
||
static QueryTestEntry link11(dir1 + "link11", B_SYMLINK_NODE, &file11);
|
||
static QueryTestEntry dir2(mountPoint + "dir2", B_DIRECTORY_NODE);
|
||
static QueryTestEntry subdir21(dir2 + "subdir21", B_DIRECTORY_NODE);
|
||
static QueryTestEntry subdir22(dir2 + "subdir22", B_DIRECTORY_NODE);
|
||
static QueryTestEntry subdir23(dir2 + "subdir23", B_DIRECTORY_NODE);
|
||
static QueryTestEntry file21(dir2 + "file21", B_FILE_NODE);
|
||
static QueryTestEntry file22(dir2 + "file22", B_FILE_NODE);
|
||
static QueryTestEntry link21(dir2 + "link21", B_SYMLINK_NODE, &file12);
|
||
static QueryTestEntry dir3(mountPoint + "dir3", B_DIRECTORY_NODE);
|
||
static QueryTestEntry subdir31(dir3 + "subdir31", B_DIRECTORY_NODE);
|
||
static QueryTestEntry subdir32(dir3 + "subdir32", B_DIRECTORY_NODE);
|
||
static QueryTestEntry file31(dir3 + "file31", B_FILE_NODE);
|
||
static QueryTestEntry file32(dir3 + "file32", B_FILE_NODE);
|
||
static QueryTestEntry link31(dir3 + "link31", B_SYMLINK_NODE, &file22);
|
||
static QueryTestEntry file1(mountPoint + "file1", B_FILE_NODE);
|
||
static QueryTestEntry file2(mountPoint + "file2", B_FILE_NODE);
|
||
static QueryTestEntry file3(mountPoint + "file3", B_FILE_NODE);
|
||
static QueryTestEntry link1(mountPoint + "link1", B_SYMLINK_NODE, &file1);
|
||
static QueryTestEntry link2(mountPoint + "link2", B_SYMLINK_NODE, &file2);
|
||
static QueryTestEntry link3(mountPoint + "link3", B_SYMLINK_NODE, &file3);
|
||
|
||
static QueryTestEntry *allTestEntries[] = {
|
||
&dir1, &subdir11, &subdir12, &file11, &file12, &link11,
|
||
&dir2, &subdir21, &subdir22, &subdir23, &file21, &file22, &link21,
|
||
&dir3, &subdir31, &subdir32, &file31, &file32, &link31,
|
||
&file1, &file2, &file3, &link1, &link2, &link3
|
||
};
|
||
static const int32 allTestEntryCount
|
||
= sizeof(allTestEntries) / sizeof(QueryTestEntry*);
|
||
|
||
// create_test_entries
|
||
void
|
||
create_test_entries(QueryTestEntry **testEntries, int32 count)
|
||
{
|
||
// create the command line
|
||
string cmdLine("true");
|
||
for (int32 i = 0; i < count; i++) {
|
||
const QueryTestEntry *entry = testEntries[i];
|
||
switch (entry->kind) {
|
||
case B_DIRECTORY_NODE:
|
||
cmdLine += " ; mkdir " + entry->path;
|
||
break;
|
||
case B_FILE_NODE:
|
||
cmdLine += " ; touch " + entry->path;
|
||
break;
|
||
case B_SYMLINK_NODE:
|
||
cmdLine += " ; ln -s " + entry->linkToPath + " " + entry->path;
|
||
break;
|
||
case B_ANY_NODE:
|
||
default:
|
||
printf("WARNING: invalid node kind\n");
|
||
break;
|
||
}
|
||
}
|
||
BasicTest::execCommand(cmdLine);
|
||
}
|
||
|
||
// delete_test_entries
|
||
void
|
||
delete_test_entries(QueryTestEntry **testEntries, int32 count)
|
||
{
|
||
// create the command line
|
||
string cmdLine("true");
|
||
for (int32 i = 0; i < count; i++) {
|
||
const QueryTestEntry *entry = testEntries[i];
|
||
switch (entry->kind) {
|
||
case B_DIRECTORY_NODE:
|
||
case B_FILE_NODE:
|
||
case B_SYMLINK_NODE:
|
||
cmdLine += " ; rm -rf " + entry->path;
|
||
break;
|
||
case B_ANY_NODE:
|
||
default:
|
||
printf("WARNING: invalid node kind\n");
|
||
break;
|
||
}
|
||
}
|
||
BasicTest::execCommand(cmdLine);
|
||
}
|
||
|
||
|
||
|
||
|
||
// QueryTest
|
||
|
||
// Suite
|
||
CppUnit::Test*
|
||
QueryTest::Suite() {
|
||
CppUnit::TestSuite *suite = new CppUnit::TestSuite();
|
||
typedef CppUnit::TestCaller<QueryTest> TC;
|
||
|
||
suite->addTest( new TC("BQuery::Predicate Test",
|
||
&QueryTest::PredicateTest) );
|
||
suite->addTest( new TC("BQuery::Parameter Test",
|
||
&QueryTest::ParameterTest) );
|
||
suite->addTest( new TC("BQuery::Fetch Test", &QueryTest::FetchTest) );
|
||
suite->addTest( new TC("BQuery::Live Test", &QueryTest::LiveTest) );
|
||
|
||
return suite;
|
||
}
|
||
|
||
// setUp
|
||
void
|
||
QueryTest::setUp()
|
||
{
|
||
BasicTest::setUp();
|
||
fApplication = new BTestApp("application/x-vnd.obos.query-test");
|
||
if (fApplication->Init() != B_OK) {
|
||
fprintf(stderr, "Failed to initialize application.\n");
|
||
delete fApplication;
|
||
fApplication = NULL;
|
||
}
|
||
fVolumeCreated = false;
|
||
}
|
||
|
||
// tearDown
|
||
void
|
||
QueryTest::tearDown()
|
||
{
|
||
BasicTest::tearDown();
|
||
if (fApplication) {
|
||
fApplication->Terminate();
|
||
delete fApplication;
|
||
fApplication = NULL;
|
||
}
|
||
if (fVolumeCreated) {
|
||
deleteVolume(testVolumeImage, testMountPoint);
|
||
fVolumeCreated = false;
|
||
}
|
||
}
|
||
|
||
// TestPredicate
|
||
static
|
||
void
|
||
TestPredicate(const PredicateNode &predicateNode, status_t pushResult = B_OK,
|
||
status_t getResult = B_OK)
|
||
{
|
||
BString predicateString = predicateNode.toString().String();
|
||
//printf("predicate: `%s'\n", predicateString.String());
|
||
// GetPredicate(BString *)
|
||
{
|
||
Query query;
|
||
// CPPUNIT_ASSERT( predicateNode.push(query) == pushResult );
|
||
status_t error = predicateNode.push(query);
|
||
if (error != pushResult) {
|
||
printf("predicate: `%s'\n", predicateString.String());
|
||
printf("error: %lx vs %lx\n", error, pushResult);
|
||
}
|
||
CPPUNIT_ASSERT( error == pushResult );
|
||
if (pushResult == B_OK) {
|
||
BString predicate;
|
||
// CPPUNIT_ASSERT( query.GetPredicate(&predicate) == getResult );
|
||
error = query.GetPredicate(&predicate);
|
||
if (error != getResult) {
|
||
printf("predicate: `%s'\n", predicateString.String());
|
||
printf("error: %lx vs %lx\n", error, getResult);
|
||
}
|
||
CPPUNIT_ASSERT( error == getResult );
|
||
if (getResult == B_OK) {
|
||
CPPUNIT_ASSERT( (int32)query.PredicateLength()
|
||
== predicateString.Length() + 1 );
|
||
CPPUNIT_ASSERT( predicateString == predicate );
|
||
}
|
||
}
|
||
}
|
||
// GetPredicate(char *, size_t)
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( predicateNode.push(query) == pushResult );
|
||
if (pushResult == B_OK) {
|
||
char buffer[1024];
|
||
CPPUNIT_ASSERT( query.GetPredicate(buffer, sizeof(buffer))
|
||
== getResult );
|
||
if (getResult == B_OK)
|
||
CPPUNIT_ASSERT( predicateString == buffer );
|
||
}
|
||
}
|
||
// PredicateLength()
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( predicateNode.push(query) == pushResult );
|
||
if (pushResult == B_OK) {
|
||
size_t expectedLength
|
||
= (getResult == B_OK ? predicateString.Length() + 1 : 0);
|
||
CPPUNIT_ASSERT( query.PredicateLength() == expectedLength );
|
||
}
|
||
}
|
||
// SetPredicate()
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate(predicateString.String()) == B_OK );
|
||
CPPUNIT_ASSERT( (int32)query.PredicateLength()
|
||
== predicateString.Length() + 1 );
|
||
BString predicate;
|
||
CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK );
|
||
CPPUNIT_ASSERT( predicateString == predicate );
|
||
}
|
||
}
|
||
|
||
// TestOperator
|
||
static
|
||
void
|
||
TestOperator(query_op op)
|
||
{
|
||
// well formed
|
||
TestPredicate(OpNode(op,
|
||
new AttributeNode("attribute"),
|
||
new Int32Node(42)
|
||
));
|
||
TestPredicate(OpNode(op,
|
||
new AttributeNode("attribute"),
|
||
new StringNode("some string")
|
||
));
|
||
TestPredicate(OpNode(op,
|
||
new AttributeNode("attribute"),
|
||
new DateNode("22 May 2002")
|
||
));
|
||
// ill formed
|
||
TestPredicate(OpNode(op, new AttributeNode("attribute"), NULL), B_OK,
|
||
B_NO_INIT);
|
||
// R5: crashs when pushing B_CONTAINS/B_BEGINS/ENDS_WITH on an empty stack
|
||
#if TEST_R5
|
||
if (op < B_CONTAINS || op > B_ENDS_WITH)
|
||
#endif
|
||
TestPredicate(OpNode(op, NULL, NULL), B_OK, B_NO_INIT);
|
||
TestPredicate(OpNode(op,
|
||
new AttributeNode("attribute"),
|
||
new DateNode("22 May 2002")
|
||
).addChild(new Int32Node(42)), B_OK, B_NO_INIT);
|
||
}
|
||
|
||
// PredicateTest
|
||
void
|
||
QueryTest::PredicateTest()
|
||
{
|
||
// tests:
|
||
// * Push*()
|
||
// * Set/GetPredicate(), PredicateLength()
|
||
// empty predicate
|
||
NextSubTest();
|
||
char buffer[1024];
|
||
{
|
||
Query query;
|
||
BString predicate;
|
||
CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_NO_INIT );
|
||
}
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.GetPredicate(buffer, sizeof(buffer))
|
||
== B_NO_INIT );
|
||
}
|
||
// one element predicates
|
||
NextSubTest();
|
||
TestPredicate(Int32Node(42));
|
||
TestPredicate(UInt32Node(42));
|
||
TestPredicate(Int64Node(42));
|
||
// R5: buggy PushUInt64() implementation.
|
||
#if !TEST_R5
|
||
TestPredicate(UInt64Node(42));
|
||
#endif
|
||
TestPredicate(FloatNode(42));
|
||
TestPredicate(DoubleNode(42));
|
||
TestPredicate(StringNode("some \" chars ' to \\ be ( escaped ) or "
|
||
"% not!"));
|
||
TestPredicate(StringNode("some \" chars ' to \\ be ( escaped ) or "
|
||
"% not!", true));
|
||
TestPredicate(DateNode("+15 min"));
|
||
TestPredicate(DateNode("22 May 2002"));
|
||
TestPredicate(DateNode("tomorrow"));
|
||
TestPredicate(DateNode("17:57"));
|
||
TestPredicate(DateNode("invalid date"), B_BAD_VALUE);
|
||
TestPredicate(AttributeNode("some attribute"));
|
||
// operators
|
||
NextSubTest();
|
||
TestOperator(B_EQ);
|
||
TestOperator(B_GT);
|
||
TestOperator(B_GE);
|
||
TestOperator(B_LT);
|
||
TestOperator(B_LE);
|
||
TestOperator(B_NE);
|
||
TestOperator(B_CONTAINS);
|
||
TestOperator(B_BEGINS_WITH);
|
||
TestOperator(B_ENDS_WITH);
|
||
TestOperator(B_AND);
|
||
TestOperator(B_OR);
|
||
{
|
||
// B_NOT
|
||
TestPredicate(OpNode(B_NOT, new AttributeNode("attribute")));
|
||
TestPredicate(OpNode(B_NOT, new Int32Node(42)));
|
||
TestPredicate(OpNode(B_NOT, new StringNode("some string")));
|
||
TestPredicate(OpNode(B_NOT, new StringNode("some string", true)));
|
||
TestPredicate(OpNode(B_NOT, new DateNode("22 May 2002")));
|
||
TestPredicate(OpNode(B_NOT, NULL), B_OK, B_NO_INIT);
|
||
}
|
||
// well formed, legal predicate
|
||
NextSubTest();
|
||
TestPredicate(OpNode(B_AND,
|
||
new OpNode(B_CONTAINS,
|
||
new AttributeNode("attribute"),
|
||
new StringNode("hello")
|
||
),
|
||
new OpNode(B_OR,
|
||
new OpNode(B_NOT,
|
||
new OpNode(B_EQ,
|
||
new AttributeNode("attribute2"),
|
||
new UInt32Node(7)
|
||
),
|
||
NULL
|
||
),
|
||
new OpNode(B_GE,
|
||
new AttributeNode("attribute3"),
|
||
new DateNode("20 May 2002")
|
||
)
|
||
)
|
||
));
|
||
// well formed, illegal predicate
|
||
NextSubTest();
|
||
TestPredicate(OpNode(B_EQ,
|
||
new StringNode("hello"),
|
||
new OpNode(B_LE,
|
||
new OpNode(B_NOT,
|
||
new Int32Node(17),
|
||
NULL
|
||
),
|
||
new DateNode("20 May 2002")
|
||
)
|
||
));
|
||
// ill formed predicates
|
||
// Some have already been tested in TestOperator, so we only test a few
|
||
// special ones.
|
||
NextSubTest();
|
||
TestPredicate(ListNode(new Int32Node(42), new StringNode("hello!")),
|
||
B_OK, B_NO_INIT);
|
||
TestPredicate(OpNode(B_EQ,
|
||
new StringNode("hello"),
|
||
new OpNode(B_NOT, NULL)
|
||
), B_OK, B_NO_INIT);
|
||
// precedence Push*() over SetPredicate()
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
OpNode predicate1(B_CONTAINS,
|
||
new AttributeNode("attribute"),
|
||
new StringNode("hello")
|
||
);
|
||
StringNode predicate2("I'm the loser. :´-(");
|
||
CPPUNIT_ASSERT( predicate1.push(query) == B_OK );
|
||
CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String())
|
||
== B_OK );
|
||
BString predicate;
|
||
CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK );
|
||
CPPUNIT_ASSERT( predicate == predicate1.toString() );
|
||
}
|
||
// GetPredicate() clears the stack
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
OpNode predicate1(B_CONTAINS,
|
||
new AttributeNode("attribute"),
|
||
new StringNode("hello")
|
||
);
|
||
StringNode predicate2("I'm the winner. :-)");
|
||
CPPUNIT_ASSERT( predicate1.push(query) == B_OK );
|
||
BString predicate;
|
||
CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK );
|
||
CPPUNIT_ASSERT( predicate == predicate1.toString() );
|
||
CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String())
|
||
== B_OK );
|
||
CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK );
|
||
CPPUNIT_ASSERT( predicate == predicate2.toString() );
|
||
}
|
||
// PredicateLength() clears the stack
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
OpNode predicate1(B_CONTAINS,
|
||
new AttributeNode("attribute"),
|
||
new StringNode("hello")
|
||
);
|
||
StringNode predicate2("I'm the winner. :-)");
|
||
CPPUNIT_ASSERT( predicate1.push(query) == B_OK );
|
||
CPPUNIT_ASSERT( (int32)query.PredicateLength()
|
||
== predicate1.toString().Length() + 1 );
|
||
CPPUNIT_ASSERT( query.SetPredicate(predicate2.toString().String())
|
||
== B_OK );
|
||
BString predicate;
|
||
CPPUNIT_ASSERT( query.GetPredicate(&predicate) == B_OK );
|
||
CPPUNIT_ASSERT( predicate == predicate2.toString() );
|
||
}
|
||
// SetPredicate(), Push*() fail after Fetch()
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
|
||
== B_OK );
|
||
BVolume volume(dev_for_path("/boot"));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExistEither\"")
|
||
== B_NOT_ALLOWED );
|
||
// R5: Push*()ing a new predicate does work, though it doesn't make any sense
|
||
#if TEST_R5
|
||
CPPUNIT_ASSERT( query.PushDate("20 May 2002") == B_OK );
|
||
CPPUNIT_ASSERT( query.PushValue((int32)42) == B_OK );
|
||
CPPUNIT_ASSERT( query.PushValue((uint32)42) == B_OK );
|
||
CPPUNIT_ASSERT( query.PushValue((int64)42) == B_OK );
|
||
CPPUNIT_ASSERT( query.PushValue((uint64)42) == B_OK );
|
||
CPPUNIT_ASSERT( query.PushValue((float)42) == B_OK );
|
||
CPPUNIT_ASSERT( query.PushValue((double)42) == B_OK );
|
||
CPPUNIT_ASSERT( query.PushValue("hello") == B_OK );
|
||
CPPUNIT_ASSERT( query.PushAttr("attribute") == B_OK );
|
||
CPPUNIT_ASSERT( query.PushOp(B_EQ) == B_OK );
|
||
#else
|
||
CPPUNIT_ASSERT( query.PushDate("20 May 2002") == B_NOT_ALLOWED );
|
||
CPPUNIT_ASSERT( query.PushValue((int32)42) == B_NOT_ALLOWED );
|
||
CPPUNIT_ASSERT( query.PushValue((uint32)42) == B_NOT_ALLOWED );
|
||
CPPUNIT_ASSERT( query.PushValue((int64)42) == B_NOT_ALLOWED );
|
||
CPPUNIT_ASSERT( query.PushValue((uint64)42) == B_NOT_ALLOWED );
|
||
CPPUNIT_ASSERT( query.PushValue((float)42) == B_NOT_ALLOWED );
|
||
CPPUNIT_ASSERT( query.PushValue((double)42) == B_NOT_ALLOWED );
|
||
CPPUNIT_ASSERT( query.PushValue("hello") == B_NOT_ALLOWED );
|
||
CPPUNIT_ASSERT( query.PushAttr("attribute") == B_NOT_ALLOWED );
|
||
CPPUNIT_ASSERT( query.PushOp(B_EQ) == B_NOT_ALLOWED );
|
||
#endif
|
||
}
|
||
// SetPredicate(): bad args
|
||
// R5: crashes when passing NULL to Set/GetPredicate()
|
||
#if !TEST_R5
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate(NULL) == B_BAD_VALUE );
|
||
CPPUNIT_ASSERT( query.SetPredicate("hello") == B_OK );
|
||
CPPUNIT_ASSERT( query.GetPredicate(NULL) == B_BAD_VALUE );
|
||
CPPUNIT_ASSERT( query.GetPredicate(NULL, 10) == B_BAD_VALUE );
|
||
}
|
||
#endif
|
||
}
|
||
|
||
// ParameterTest
|
||
void
|
||
QueryTest::ParameterTest()
|
||
{
|
||
// tests:
|
||
// * SetVolume, TargetDevice()
|
||
// * SetTarget(), IsLive()
|
||
|
||
// SetVolume(), TargetDevice()
|
||
// uninitialized BQuery
|
||
NextSubTest();
|
||
{
|
||
BQuery query;
|
||
CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR );
|
||
}
|
||
// NULL volume
|
||
// R5: crashs when passing a NULL BVolume
|
||
#if !TEST_R5
|
||
NextSubTest();
|
||
{
|
||
BQuery query;
|
||
CPPUNIT_ASSERT( query.SetVolume(NULL) == B_BAD_VALUE );
|
||
CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR );
|
||
}
|
||
#endif
|
||
// invalid volume
|
||
NextSubTest();
|
||
{
|
||
BQuery query;
|
||
BVolume volume(-2);
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_BAD_VALUE );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.TargetDevice() == B_ERROR );
|
||
}
|
||
// valid volume
|
||
NextSubTest();
|
||
{
|
||
BQuery query;
|
||
dev_t device = dev_for_path("/boot");
|
||
BVolume volume(device);
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.TargetDevice() == device );
|
||
}
|
||
|
||
// SetTarget(), IsLive()
|
||
// uninitialized BQuery
|
||
NextSubTest();
|
||
{
|
||
BQuery query;
|
||
CPPUNIT_ASSERT( query.IsLive() == false );
|
||
}
|
||
// uninitialized BMessenger
|
||
NextSubTest();
|
||
{
|
||
BQuery query;
|
||
BMessenger messenger;
|
||
CPPUNIT_ASSERT( messenger.IsValid() == false );
|
||
CPPUNIT_ASSERT( query.SetTarget(messenger) == B_BAD_VALUE );
|
||
CPPUNIT_ASSERT( query.IsLive() == false );
|
||
}
|
||
// valid BMessenger
|
||
NextSubTest();
|
||
{
|
||
BQuery query;
|
||
BMessenger messenger(&fApplication->Handler());
|
||
CPPUNIT_ASSERT( messenger.IsValid() == true );
|
||
CPPUNIT_ASSERT( query.SetTarget(messenger) == B_OK );
|
||
CPPUNIT_ASSERT( query.IsLive() == true );
|
||
}
|
||
|
||
// SetVolume/Target() fail after Fetch()
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
|
||
== B_OK );
|
||
BVolume volume(dev_for_path("/boot"));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_NOT_ALLOWED );
|
||
BMessenger messenger(&fApplication->Handler());
|
||
CPPUNIT_ASSERT( messenger.IsValid() == true );
|
||
CPPUNIT_ASSERT( query.SetTarget(messenger) == B_NOT_ALLOWED );
|
||
}
|
||
|
||
// Fetch() fails without a valid volume set
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
|
||
== B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT );
|
||
}
|
||
}
|
||
|
||
// TestFetchPredicateInit
|
||
static
|
||
void
|
||
TestFetchPredicateInit(Query &query, TestSet &testSet, const char *mountPoint,
|
||
const char *predicate, QueryTestEntry **entries,
|
||
int32 entryCount)
|
||
{
|
||
// init the query
|
||
CPPUNIT_ASSERT( query.SetPredicate(predicate) == B_OK );
|
||
BVolume volume(dev_for_path(mountPoint));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_OK );
|
||
// init the test set
|
||
testSet.clear();
|
||
for (int32 i = 0; i < entryCount; i++)
|
||
testSet.add(entries[i]->path);
|
||
}
|
||
|
||
|
||
// TestFetchPredicate
|
||
static
|
||
void
|
||
TestFetchPredicate(const char *mountPoint, const char *predicate,
|
||
QueryTestEntry **entries, int32 entryCount)
|
||
{
|
||
// GetNextEntry()
|
||
{
|
||
Query query;
|
||
TestSet testSet;
|
||
TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries,
|
||
entryCount);
|
||
BEntry entry;
|
||
while (query.GetNextEntry(&entry) == B_OK) {
|
||
CPPUNIT_ASSERT( query.Rewind() == B_ERROR );
|
||
CPPUNIT_ASSERT( query.CountEntries() == B_ERROR );
|
||
BPath path;
|
||
CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK );
|
||
CPPUNIT_ASSERT( testSet.test(path.Path()) == true );
|
||
}
|
||
CPPUNIT_ASSERT( testSet.testDone() == true );
|
||
CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND );
|
||
}
|
||
// GetNextRef()
|
||
{
|
||
Query query;
|
||
TestSet testSet;
|
||
TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries,
|
||
entryCount);
|
||
entry_ref ref;
|
||
while (query.GetNextRef(&ref) == B_OK) {
|
||
CPPUNIT_ASSERT( query.Rewind() == B_ERROR );
|
||
CPPUNIT_ASSERT( query.CountEntries() == B_ERROR );
|
||
BPath path(&ref);
|
||
CPPUNIT_ASSERT( path.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( testSet.test(path.Path()) == true );
|
||
}
|
||
CPPUNIT_ASSERT( testSet.testDone() == true );
|
||
CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_ENTRY_NOT_FOUND );
|
||
}
|
||
// GetNextDirents()
|
||
{
|
||
Query query;
|
||
TestSet testSet;
|
||
TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries,
|
||
entryCount);
|
||
size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10;
|
||
char buffer[bufSize];
|
||
dirent *ents = (dirent *)buffer;
|
||
while (query.GetNextDirents(ents, bufSize, 1) == 1) {
|
||
CPPUNIT_ASSERT( query.Rewind() == B_ERROR );
|
||
CPPUNIT_ASSERT( query.CountEntries() == B_ERROR );
|
||
entry_ref ref(ents->d_pdev, ents->d_pino, ents->d_name);
|
||
BPath path(&ref);
|
||
CPPUNIT_ASSERT( path.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( testSet.test(path.Path()) == true );
|
||
}
|
||
CPPUNIT_ASSERT( testSet.testDone() == true );
|
||
CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) == 0 );
|
||
}
|
||
// interleaving use of the different methods
|
||
{
|
||
Query query;
|
||
TestSet testSet;
|
||
TestFetchPredicateInit(query, testSet, mountPoint, predicate, entries,
|
||
entryCount);
|
||
size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10;
|
||
char buffer[bufSize];
|
||
dirent *ents = (dirent *)buffer;
|
||
entry_ref ref;
|
||
BEntry entry;
|
||
while (query.GetNextDirents(ents, bufSize, 1) == 1) {
|
||
CPPUNIT_ASSERT( query.Rewind() == B_ERROR );
|
||
CPPUNIT_ASSERT( query.CountEntries() == B_ERROR );
|
||
entry_ref entref(ents->d_pdev, ents->d_pino, ents->d_name);
|
||
BPath entpath(&entref);
|
||
CPPUNIT_ASSERT( entpath.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( testSet.test(entpath.Path()) == true );
|
||
if (query.GetNextRef(&ref) == B_OK) {
|
||
BPath refpath(&ref);
|
||
CPPUNIT_ASSERT( refpath.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( testSet.test(refpath.Path()) == true );
|
||
}
|
||
if (query.GetNextEntry(&entry) == B_OK) {
|
||
BPath path;
|
||
CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK );
|
||
CPPUNIT_ASSERT( testSet.test(path.Path()) == true );
|
||
}
|
||
}
|
||
CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND );
|
||
CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_ENTRY_NOT_FOUND );
|
||
CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) == 0 );
|
||
}
|
||
}
|
||
|
||
// FetchTest
|
||
void
|
||
QueryTest::FetchTest()
|
||
{
|
||
// tests:
|
||
// * Clear()/Fetch()
|
||
// * BEntryList interface
|
||
|
||
// Fetch()
|
||
// uninitialized BQuery
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT );
|
||
}
|
||
// incompletely initialized BQuery (no predicate)
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
BVolume volume(dev_for_path("/boot"));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT );
|
||
}
|
||
// incompletely initialized BQuery (no volume)
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
|
||
== B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT );
|
||
}
|
||
// incompletely initialized BQuery (invalid predicate)
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"&&")
|
||
== B_OK );
|
||
BVolume volume(dev_for_path("/boot"));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_BAD_VALUE );
|
||
}
|
||
// initialized BQuery, Fetch() twice
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
|
||
== B_OK );
|
||
BVolume volume(dev_for_path("/boot"));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_NOT_ALLOWED );
|
||
}
|
||
// initialized BQuery, successful Fetch(), different predicates
|
||
createVolume(testVolumeImage, testMountPoint, 2);
|
||
fVolumeCreated = true;
|
||
create_test_entries(allTestEntries, allTestEntryCount);
|
||
// ... all files
|
||
NextSubTest();
|
||
{
|
||
QueryTestEntry *entries[] = {
|
||
&file11, &file12, &file21, &file22, &file31, &file32, &file1,
|
||
&file2, &file3
|
||
};
|
||
const int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*);
|
||
TestFetchPredicate(testMountPoint, "name=\"file*\"", entries,
|
||
entryCount);
|
||
}
|
||
// ... all entries containing a "l"
|
||
NextSubTest();
|
||
{
|
||
QueryTestEntry *entries[] = {
|
||
&file11, &file12, &link11, &file21, &file22, &link21, &file31,
|
||
&file32, &link31, &file1, &file2, &file3, &link1, &link2, &link3
|
||
};
|
||
const int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*);
|
||
TestFetchPredicate(testMountPoint, "name=\"*l*\"", entries,
|
||
entryCount);
|
||
}
|
||
// ... all entries ending on "2"
|
||
NextSubTest();
|
||
{
|
||
QueryTestEntry *entries[] = {
|
||
&subdir12, &file12, &dir2, &subdir22, &file22, &subdir32, &file32,
|
||
&file2, &link2
|
||
};
|
||
const int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*);
|
||
TestFetchPredicate(testMountPoint, "name=\"*2\"", entries,
|
||
entryCount);
|
||
}
|
||
|
||
// Clear()
|
||
// uninitialized BQuery
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.Clear() == B_OK );
|
||
}
|
||
// initialized BQuery, Fetch(), Clear(), Fetch()
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
|
||
== B_OK );
|
||
BVolume volume(dev_for_path("/boot"));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_OK );
|
||
CPPUNIT_ASSERT( query.Clear() == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_NO_INIT );
|
||
}
|
||
// initialized BQuery, Fetch(), Clear(), re-init, Fetch()
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
|
||
== B_OK );
|
||
BVolume volume(dev_for_path("/boot"));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_OK );
|
||
CPPUNIT_ASSERT( query.Clear() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
|
||
== B_OK );
|
||
CPPUNIT_ASSERT( volume.SetTo(dev_for_path("/boot")) == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_OK );
|
||
}
|
||
|
||
// BEntryList interface:
|
||
// empty queries
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
|
||
== B_OK );
|
||
BVolume volume(dev_for_path("/boot"));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_OK );
|
||
BEntry entry;
|
||
entry_ref ref;
|
||
size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10;
|
||
char buffer[bufSize];
|
||
dirent *ents = (dirent *)buffer;
|
||
CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND );
|
||
CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_ENTRY_NOT_FOUND );
|
||
CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1) == 0 );
|
||
}
|
||
// uninitialized queries
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
BEntry entry;
|
||
entry_ref ref;
|
||
size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10;
|
||
char buffer[bufSize];
|
||
dirent *ents = (dirent *)buffer;
|
||
CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_FILE_ERROR );
|
||
CPPUNIT_ASSERT( query.GetNextRef(&ref) == B_FILE_ERROR );
|
||
CPPUNIT_ASSERT( query.GetNextDirents(ents, bufSize, 1)
|
||
== B_FILE_ERROR );
|
||
}
|
||
// bad args
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"ThisShouldNotExist\"")
|
||
== B_OK );
|
||
BVolume volume(dev_for_path("/boot"));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_OK );
|
||
size_t bufSize = (sizeof(dirent) + B_FILE_NAME_LENGTH) * 10;
|
||
// R5: crashs when passing a NULL BEntry or entry_ref
|
||
#if !TEST_R5
|
||
CPPUNIT_ASSERT( query.GetNextEntry(NULL) == B_BAD_VALUE );
|
||
CPPUNIT_ASSERT( query.GetNextRef(NULL) == B_BAD_VALUE );
|
||
#endif
|
||
CPPUNIT_ASSERT( equals(query.GetNextDirents(NULL, bufSize, 1),
|
||
B_BAD_ADDRESS, B_BAD_VALUE) );
|
||
}
|
||
}
|
||
|
||
// AddLiveEntries
|
||
void
|
||
QueryTest::AddLiveEntries(QueryTestEntry **entries, int32 entryCount,
|
||
QueryTestEntry **queryEntries, int32 queryEntryCount)
|
||
{
|
||
create_test_entries(entries, entryCount);
|
||
for (int32 i = 0; i < entryCount; i++) {
|
||
QueryTestEntry *entry = entries[i];
|
||
BNode node(entry->cpath);
|
||
CPPUNIT_ASSERT( node.InitCheck() == B_OK );
|
||
node_ref nref;
|
||
CPPUNIT_ASSERT( node.GetNodeRef(&nref) == B_OK );
|
||
entry->node = nref.node;
|
||
entry_ref ref;
|
||
CPPUNIT_ASSERT( get_ref_for_path(entry->cpath, &ref) == B_OK );
|
||
entry->directory = ref.directory;
|
||
entry->name = ref.name;
|
||
}
|
||
CheckUpdateMessages(B_ENTRY_CREATED, queryEntries, queryEntryCount);
|
||
}
|
||
|
||
// RemoveLiveEntries
|
||
void
|
||
QueryTest::RemoveLiveEntries(QueryTestEntry **entries, int32 entryCount,
|
||
QueryTestEntry **queryEntries,
|
||
int32 queryEntryCount)
|
||
{
|
||
delete_test_entries(entries, entryCount);
|
||
CheckUpdateMessages(B_ENTRY_REMOVED, queryEntries, queryEntryCount);
|
||
for (int32 i = 0; i < entryCount; i++) {
|
||
QueryTestEntry *entry = entries[i];
|
||
entry->directory = -1;
|
||
entry->node = -1;
|
||
entry->name = "";
|
||
}
|
||
}
|
||
|
||
// CheckUpdateMessages
|
||
void
|
||
QueryTest::CheckUpdateMessages(uint32 opcode, QueryTestEntry **entries,
|
||
int32 entryCount)
|
||
{
|
||
|
||
// wait for the messages
|
||
snooze(100000);
|
||
if (fApplication) {
|
||
BMessageQueue &queue = fApplication->Handler().Queue();
|
||
CPPUNIT_ASSERT( queue.Lock() );
|
||
try {
|
||
int32 entryNum = 0;
|
||
while (BMessage *_message = queue.NextMessage()) {
|
||
BMessage message(*_message);
|
||
delete _message;
|
||
CPPUNIT_ASSERT( entryNum < entryCount );
|
||
QueryTestEntry *entry = entries[entryNum];
|
||
CPPUNIT_ASSERT( message.what == B_QUERY_UPDATE );
|
||
uint32 msgOpcode;
|
||
CPPUNIT_ASSERT( message.FindInt32("opcode", (int32*)&msgOpcode)
|
||
== B_OK );
|
||
CPPUNIT_ASSERT( msgOpcode == opcode );
|
||
dev_t device;
|
||
CPPUNIT_ASSERT( message.FindInt32("device", &device)
|
||
== B_OK );
|
||
CPPUNIT_ASSERT( device == dev_for_path(testMountPoint) );
|
||
ino_t directory;
|
||
CPPUNIT_ASSERT( message.FindInt64("directory", &directory)
|
||
== B_OK );
|
||
CPPUNIT_ASSERT( directory == entry->directory );
|
||
ino_t node;
|
||
CPPUNIT_ASSERT( message.FindInt64("node", &node)
|
||
== B_OK );
|
||
CPPUNIT_ASSERT( node == entry->node );
|
||
if (opcode == B_ENTRY_CREATED) {
|
||
const char *name;
|
||
CPPUNIT_ASSERT( message.FindString("name", &name)
|
||
== B_OK );
|
||
CPPUNIT_ASSERT( entry->name == name );
|
||
}
|
||
entryNum++;
|
||
}
|
||
CPPUNIT_ASSERT( entryNum == entryCount );
|
||
} catch (CppUnit::Exception exception) {
|
||
queue.Unlock();
|
||
throw exception;
|
||
}
|
||
queue.Unlock();
|
||
}
|
||
}
|
||
|
||
// LiveTest
|
||
void
|
||
QueryTest::LiveTest()
|
||
{
|
||
// tests:
|
||
// * live queries
|
||
CPPUNIT_ASSERT( fApplication != NULL );
|
||
createVolume(testVolumeImage, testMountPoint, 2);
|
||
fVolumeCreated = true;
|
||
create_test_entries(allTestEntries, allTestEntryCount);
|
||
BMessenger target(&fApplication->Handler());
|
||
|
||
// empty query, add some files, remove some files
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
CPPUNIT_ASSERT( query.SetPredicate("name=\"*Argh\"")
|
||
== B_OK );
|
||
BVolume volume(dev_for_path(testMountPoint));
|
||
CPPUNIT_ASSERT( volume.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( query.SetVolume(&volume) == B_OK );
|
||
CPPUNIT_ASSERT( query.SetTarget(target) == B_OK );
|
||
CPPUNIT_ASSERT( query.Fetch() == B_OK );
|
||
BEntry entry;
|
||
CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND );
|
||
// the test entries
|
||
QueryTestEntry testDir1(dir1 + "testDirArgh", B_DIRECTORY_NODE);
|
||
QueryTestEntry testDir2(dir1 + "testDir2", B_DIRECTORY_NODE);
|
||
QueryTestEntry testFile1(subdir21 + "testFileArgh", B_FILE_NODE);
|
||
QueryTestEntry testFile2(subdir21 + "testFile2", B_FILE_NODE);
|
||
QueryTestEntry testLink1(subdir32 + "testLinkArgh", B_SYMLINK_NODE,
|
||
&file11);
|
||
QueryTestEntry testLink2(subdir32 + "testLink2", B_SYMLINK_NODE,
|
||
&file11);
|
||
QueryTestEntry *entries[] = {
|
||
&testDir1, &testDir2, &testFile1, &testFile2,
|
||
&testLink1, &testLink2
|
||
};
|
||
int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*);
|
||
QueryTestEntry *queryEntries[] = {
|
||
&testDir1, &testFile1, &testLink1
|
||
};
|
||
int32 queryEntryCount = sizeof(queryEntries) / sizeof(QueryTestEntry*);
|
||
AddLiveEntries(entries, entryCount, queryEntries, queryEntryCount);
|
||
RemoveLiveEntries(entries, entryCount, queryEntries, queryEntryCount);
|
||
}
|
||
// non-empty query, add some files, remove some files
|
||
NextSubTest();
|
||
{
|
||
Query query;
|
||
TestSet testSet;
|
||
CPPUNIT_ASSERT( query.SetTarget(target) == B_OK );
|
||
QueryTestEntry *initialEntries[] = {
|
||
&file11, &file12, &file21, &file22, &file31, &file32, &file1,
|
||
&file2, &file3
|
||
};
|
||
int32 initialEntryCount
|
||
= sizeof(initialEntries) / sizeof(QueryTestEntry*);
|
||
TestFetchPredicateInit(query, testSet, testMountPoint,
|
||
"name=\"*ile*\"", initialEntries,
|
||
initialEntryCount);
|
||
BEntry entry;
|
||
while (query.GetNextEntry(&entry) == B_OK) {
|
||
BPath path;
|
||
CPPUNIT_ASSERT( entry.InitCheck() == B_OK );
|
||
CPPUNIT_ASSERT( entry.GetPath(&path) == B_OK );
|
||
CPPUNIT_ASSERT( testSet.test(path.Path()) == true );
|
||
}
|
||
CPPUNIT_ASSERT( testSet.testDone() == true );
|
||
CPPUNIT_ASSERT( query.GetNextEntry(&entry) == B_ENTRY_NOT_FOUND );
|
||
// the test entries
|
||
QueryTestEntry testDir1(dir1 + "testDir1", B_DIRECTORY_NODE);
|
||
QueryTestEntry testDir2(dir1 + "testDir2", B_DIRECTORY_NODE);
|
||
QueryTestEntry testFile1(subdir21 + "testFile1", B_FILE_NODE);
|
||
QueryTestEntry testFile2(subdir21 + "testFile2", B_FILE_NODE);
|
||
QueryTestEntry testLink1(subdir32 + "testLink1", B_SYMLINK_NODE,
|
||
&file11);
|
||
QueryTestEntry testLink2(subdir32 + "testLink2", B_SYMLINK_NODE,
|
||
&file11);
|
||
QueryTestEntry testFile3(subdir32 + "testFile3", B_FILE_NODE);
|
||
QueryTestEntry *entries[] = {
|
||
&testDir1, &testDir2, &testFile1, &testFile2,
|
||
&testLink1, &testLink2, &testFile3
|
||
};
|
||
int32 entryCount = sizeof(entries) / sizeof(QueryTestEntry*);
|
||
QueryTestEntry *queryEntries[] = {
|
||
&testFile1, &testFile2, &testFile3
|
||
};
|
||
int32 queryEntryCount = sizeof(queryEntries) / sizeof(QueryTestEntry*);
|
||
AddLiveEntries(entries, entryCount, queryEntries, queryEntryCount);
|
||
RemoveLiveEntries(entries, entryCount, queryEntries, queryEntryCount);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|