TEST_F(SearchQueryParserTest, HumanReadableDurationSearchwithRangeFilter) { QStringList searchColumns; searchColumns << "artist" << "album"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("duration:2:30-3:20", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setSampleRate(44100); pTrack->setDuration(80); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); EXPECT_TRUE(pQuery->match(pTrack)); pTrack->setDuration(199); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration >= 150 AND duration <= 200)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:2:30-200", searchColumns, "")); pTrack->setSampleRate(44100); pTrack->setDuration(80); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); EXPECT_TRUE(pQuery->match(pTrack)); pTrack->setDuration(199); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration >= 150 AND duration <= 200)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:150-200", searchColumns, "")); pTrack->setSampleRate(44100); pTrack->setDuration(80); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); EXPECT_TRUE(pQuery->match(pTrack)); pTrack->setDuration(199); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration >= 150 AND duration <= 200)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:2m30s-3m20s", searchColumns, "")); pTrack->setSampleRate(44100); pTrack->setDuration(80); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); EXPECT_TRUE(pQuery->match(pTrack)); pTrack->setDuration(199); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration >= 150 AND duration <= 200)")), qPrintable(pQuery->toSql())); }
void GNC::GUI::AcquisitionTableModel::DoExpand(AcquisitionNode* pNode, const std::string& modalities, const std::string& server) { if (pNode->IsSeriesNode()) { return; } wxDataViewItemArray arr; pNode->GetChildren(arr); if (arr.empty() && !pNode->uid.empty()) { GNC::GCS::Ptr<GNC::GCS::StoredQuery> pQuery(new GNC::GCS::StoredQuery()); pQuery->setPacsId(server); //insert fields that has to be returned... pQuery->addCondition(GKDCM_QueryRetrieveLevel,"SERIES"); pQuery->addConditionIfNotExists(GKDCM_StudyInstanceUID, pNode->uid); pQuery->addCondition(GKDCM_Modality, modalities); pQuery->addConditionIfNotExists(GKDCM_SeriesInstanceUID); pQuery->addConditionIfNotExists(GKDCM_SeriesDescription); pQuery->addConditionIfNotExists(GKDCM_SeriesDate); pQuery->addConditionIfNotExists(GKDCM_SeriesTime); pQuery->addConditionIfNotExists(GKDCM_NumberOfSeriesRelatedInstances); pQuery->addConditionIfNotExists(GKDCM_ReferringPhysicianName); GADAPI::ComandoPACSParams * pParams = new GADAPI::ComandoPACSParams(pQuery); m_pComandoPACS = new GADAPI::ComandoPACS(pParams); GNC::CommandController::Instance()->ProcessAsync(_Std("Exploring PACS..."),m_pComandoPACS, this); } }
TEST_F(SearchQueryParserTest, MultipleTermsMultipleColumnsNegation) { QStringList searchColumns; searchColumns << "artist" << "album"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("asdf -zxcv", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setTitle("asdf zxcv"); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setAlbum("asDF"); EXPECT_TRUE(pQuery->match(pTrack)); pTrack->setArtist("zXcV"); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setArtist(""); pTrack->setAlbum("ASDF ZXCV"); EXPECT_FALSE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString( "((artist LIKE '%asdf%') OR (album LIKE '%asdf%')) " "AND NOT ((artist LIKE '%zxcv%') OR (album LIKE '%zxcv%'))")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, EmptySearch) { QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("", QStringList(), "")); TrackPointer pTrack(new TrackInfoObject()); EXPECT_FALSE(pQuery->match(pTrack)); EXPECT_STREQ(qPrintable(QString("")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, NumericFilterOperators) { QStringList searchColumns; searchColumns << "artist" << "album"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("bpm:>127.12", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setSampleRate(44100); pTrack->setBpm(127.12); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setBpm(127.13); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(bpm > 127.12)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("bpm:>=127.12", searchColumns, "")); pTrack->setBpm(127.11); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setBpm(127.12); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(bpm >= 127.12)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("bpm:<127.12", searchColumns, "")); pTrack->setBpm(127.12); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setBpm(127.11); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(bpm < 127.12)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("bpm:<=127.12", searchColumns, "")); pTrack->setBpm(127.13); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setBpm(127.12); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(bpm <= 127.12)")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, NumericFilterEmpty) { QStringList searchColumns; searchColumns << "artist" << "album"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("bpm:", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setSampleRate(44100); pTrack->setBpm(127); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, TextFilterEmpty) { QStringList searchColumns; searchColumns << "artist" << "album"; // An empty argument should pass everything. QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("comment:", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setComment("test ASDF test"); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, ExtraFilterAppended) { QStringList searchColumns; searchColumns << "artist"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("asdf", searchColumns, "1 > 2")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setArtist("zxcv"); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setArtist("asdf"); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(1 > 2) AND (artist LIKE '%asdf%')")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, MultipleTermsOneColumn) { QStringList searchColumns; searchColumns << "artist"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("asdf zxcv", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setTitle("test zXcV test"); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setArtist("test zXcV test asDf"); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(artist LIKE '%asdf%') AND (artist LIKE '%zxcv%')")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, TextFilterQuote_NoEndQuoteTakesWholeQuery) { QStringList searchColumns; searchColumns << "artist" << "album"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("comment:\"asdf zxcv qwer", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setArtist("asdf zxcv qwer"); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setComment("test ASDF zxcv qwer test"); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(comment LIKE '%asdf zxcv qwer%')")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, OneTermMultipleColumnsNegation) { QStringList searchColumns; searchColumns << "artist" << "album"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("-asdf", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setTitle("testASDFtest"); EXPECT_TRUE(pQuery->match(pTrack)); pTrack->setAlbum("testASDFtest"); EXPECT_FALSE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("NOT ((artist LIKE '%asdf%') OR (album LIKE '%asdf%'))")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, TextFilterNegation) { QStringList searchColumns; searchColumns << "artist" << "album"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("-comment: asdf", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setArtist("asdf"); EXPECT_TRUE(pQuery->match(pTrack)); pTrack->setComment("test ASDF test"); EXPECT_FALSE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("NOT (comment LIKE '%asdf%')")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, NumericRangeFilter) { QStringList searchColumns; searchColumns << "artist" << "album"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("bpm:127.12-129", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setSampleRate(44100); pTrack->setBpm(125); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setBpm(127.12); EXPECT_TRUE(pQuery->match(pTrack)); pTrack->setBpm(129); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(bpm >= 127.12 AND bpm <= 129)")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, HumanReadableDurationSearch) { QStringList searchColumns; searchColumns << "artist" << "album"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("duration:1:30", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setSampleRate(44100); pTrack->setDuration(91); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(90); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration = 90)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:1m30s", searchColumns, "")); pTrack->setDuration(91); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(90); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration = 90)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:90", searchColumns, "")); pTrack->setDuration(91); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(90); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration = 90)")), qPrintable(pQuery->toSql())); }
TEST_F(SearchQueryParserTest, MultipleFilters) { QStringList searchColumns; searchColumns << "artist" << "title"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("bpm:127.12-129 artist:\"com truise\" Colorvision", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setSampleRate(44100); pTrack->setBpm(128); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setArtist("Com Truise"); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setTitle("Colorvision"); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(bpm >= 127.12 AND bpm <= 129) AND " "((artist LIKE '%com truise%') OR (album_artist LIKE '%com truise%')) AND " "((artist LIKE '%Colorvision%') OR (title LIKE '%Colorvision%'))")), qPrintable(pQuery->toSql())); }
error iRobot::squerylist(std::initializer_list<uint8_t> list) { return writeData(pQuery(list)); }
static void testQuery(void) { BOOL (WINAPI *pQuery)(BYTE, SnmpVarBindList *, AsnInteger32 *, AsnInteger32 *); BOOL ret, moreData, noChange; SnmpVarBindList list; AsnInteger32 error, index; UINT bogus[] = { 1,2,3,4 }; UINT mib2System[] = { 1,3,6,1,2,1,1 }; UINT mib2If[] = { 1,3,6,1,2,1,2 }; UINT mib2IfTable[] = { 1,3,6,1,2,1,2,2 }; UINT mib2IfDescr[] = { 1,3,6,1,2,1,2,2,1,2 }; UINT mib2IfAdminStatus[] = { 1,3,6,1,2,1,2,2,1,7 }; UINT mib2IfOperStatus[] = { 1,3,6,1,2,1,2,2,1,8 }; UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1,1 }; UINT mib2IpRouteTable[] = { 1,3,6,1,2,1,4,21,1,1 }; UINT mib2UdpTable[] = { 1,3,6,1,2,1,7,5,1,1 }; SnmpVarBind vars[3], vars2[3], vars3[3]; UINT entry; pQuery = (void *)GetProcAddress(inetmib1, "SnmpExtensionQuery"); if (!pQuery) { win_skip("couldn't find SnmpExtensionQuery\n"); return; } /* Crash ret = pQuery(0, NULL, NULL, NULL); ret = pQuery(0, NULL, &error, NULL); ret = pQuery(0, NULL, NULL, &index); ret = pQuery(0, &list, NULL, NULL); ret = pQuery(0, &list, &error, NULL); */ /* An empty list succeeds */ list.len = 0; error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); /* Oddly enough, this "succeeds," even though the OID is clearly * unsupported. */ vars[0].name.idLength = sizeof(bogus) / sizeof(bogus[0]); vars[0].name.ids = bogus; vars[0].value.asnType = 0; list.len = 1; list.list = vars; SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR || error == ERROR_FILE_NOT_FOUND /* Win9x */, "expected SNMP_ERRORSTATUS_NOERROR or ERROR_FILE_NOT_FOUND, got %d\n", error); if (error == SNMP_ERRORSTATUS_NOERROR) ok(index == 0, "expected index 0, got %d\n", index); else if (error == ERROR_FILE_NOT_FOUND) ok(index == 1, "expected index 1, got %d\n", index); /* The OID isn't changed either: */ ok(!strcmp("1.2.3.4", SnmpUtilOidToA(&vars[0].name)), "expected 1.2.3.4, got %s\n", SnmpUtilOidToA(&vars[0].name)); /* The table is not an accessible variable, so it fails */ vars[0].name.idLength = sizeof(mib2IfTable) / sizeof(mib2IfTable[0]); vars[0].name.ids = mib2IfTable; SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOSUCHNAME, "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error); /* The index is 1-based rather than 0-based */ ok(index == 1, "expected index 1, got %d\n", index); /* A Get fails on something that specifies a table (but not a particular * entry in it)... */ vars[0].name.idLength = sizeof(mib2IfDescr) / sizeof(mib2IfDescr[0]); vars[0].name.ids = mib2IfDescr; vars[1].name.idLength = sizeof(mib2IfAdminStatus) / sizeof(mib2IfAdminStatus[0]); vars[1].name.ids = mib2IfAdminStatus; vars[2].name.idLength = sizeof(mib2IfOperStatus) / sizeof(mib2IfOperStatus[0]); vars[2].name.ids = mib2IfOperStatus; list.len = 3; SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOSUCHNAME, "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error); ok(index == 1, "expected index 1, got %d\n", index); /* but a GetNext succeeds with the same values, because GetNext gets the * entry after the specified OID, not the entry specified by it. The * successor to the table is the first entry in the table. * The OIDs need to be allocated, because GetNext modifies them to indicate * the end of data. */ SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); SnmpUtilOidCpy(&vars2[1].name, &vars[1].name); SnmpUtilOidCpy(&vars2[2].name, &vars[2].name); list.list = vars2; moreData = TRUE; noChange = FALSE; entry = 0; do { SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); if (!ret) moreData = FALSE; else if (error) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength)) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[1].name, &vars[1].name, vars[1].name.idLength)) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[2].name, &vars[2].name, vars[2].name.idLength)) moreData = FALSE; else if (!SnmpUtilOidCmp(&vars[0].name, &vars2[0].name) || !SnmpUtilOidCmp(&vars[1].name, &vars2[1].name) || !SnmpUtilOidCmp(&vars[2].name, &vars2[2].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { UINT lastID; /* Check the OIDs. For these types of values (display strings and * integers) they should increase by 1 for each element of the table * according to RFC 1158. Windows sometimes has a weird value in the * table, so allow any value as long as it's greater than the previous * value on Windows. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 1, "expected length %d, got %d\n", vars[0].name.idLength + 1, vars2[0].name.idLength); lastID = vars2[0].name.ids[vars2[0].name.idLength - 1]; ok(lastID == entry + 1 || broken(lastID > entry), "expected %d, got %d\n", entry + 1, lastID); ok(vars2[1].name.idLength == vars[1].name.idLength + 1, "expected length %d, got %d\n", vars[1].name.idLength + 1, vars2[1].name.idLength); lastID = vars2[1].name.ids[vars2[1].name.idLength - 1]; ok(lastID == entry + 1 || broken(lastID > entry), "expected %d, got %d\n", entry + 1, lastID); ok(vars2[2].name.idLength == vars[2].name.idLength + 1, "expected length %d, got %d\n", vars[2].name.idLength + 1, vars2[2].name.idLength); lastID = vars2[2].name.ids[vars2[2].name.idLength - 1]; ok(lastID == entry + 1 || broken(lastID > entry), "expected %d, got %d\n", entry + 1, lastID); entry = lastID; /* Check the types while we're at it */ ok(vars2[0].value.asnType == ASN_OCTETSTRING, "expected ASN_OCTETSTRING, got %02x\n", vars2[0].value.asnType); ok(vars2[1].value.asnType == ASN_INTEGER, "expected ASN_INTEGER, got %02x\n", vars2[1].value.asnType); ok(vars2[2].value.asnType == ASN_INTEGER, "expected ASN_INTEGER, got %02x\n", vars2[2].value.asnType); } else if (noChange) skip("no change in OID, no MIB2 IF table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); SnmpUtilVarBindFree(&vars2[1]); SnmpUtilVarBindFree(&vars2[2]); /* Even though SnmpExtensionInit says this DLL supports the MIB2 system * variables, on recent systems (at least Win2k) the first variable it * returns a value for is the first interface. */ vars[0].name.idLength = sizeof(mib2System) / sizeof(mib2System[0]); vars[0].name.ids = mib2System; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; noChange = FALSE; ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); vars3[0].name.idLength = sizeof(mib2If) / sizeof(mib2If[0]); vars3[0].name.ids = mib2If; ok(!SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength) || !SnmpUtilOidNCmp(&vars2[0].name, &vars3[0].name, vars3[0].name.idLength), "expected 1.3.6.1.2.1.1 or 1.3.6.1.2.1.2, got %s\n", SnmpUtilOidToA(&vars2[0].name)); SnmpUtilVarBindFree(&vars2[0]); /* Check the type and OIDs of the IP address table */ vars[0].name.idLength = sizeof(mib2IpAddr) / sizeof(mib2IpAddr[0]); vars[0].name.ids = mib2IpAddr; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; do { ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); if (!ret) moreData = FALSE; else if (error) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength)) moreData = FALSE; else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { /* Make sure the size of the OID is right. * FIXME: don't know if IPv6 addrs are shared with this table. * Don't think so, but I'm not certain. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 4, "expected length %d, got %d\n", vars[0].name.idLength + 4, vars2[0].name.idLength); /* Make sure the type is right */ ok(vars2[0].value.asnType == ASN_IPADDRESS, "expected type ASN_IPADDRESS, got %02x\n", vars2[0].value.asnType); if (vars2[0].value.asnType == ASN_IPADDRESS) { UINT i; /* This looks uglier than it is: the base OID for the IP * address, 1.3.6.1.2.1.4.20.1.1, is appended with the IP * address of the entry. So e.g. the loopback address is * identified in MIB2 as 1.3.6.1.2.1.4.20.1.1.127.0.0.1 */ for (i = 0; i < vars2[0].value.asnValue.address.length; i++) { ok(vars2[0].value.asnValue.address.stream[i] == vars2[0].name.ids[vars2[0].name.idLength - 4 + i], "expected ident byte %d to be %d, got %d\n", i, vars2[0].value.asnValue.address.stream[i], vars2[0].name.ids[vars2[0].name.idLength - 4 + i]); } } } else if (noChange) skip("no change in OID, no MIB2 IP address table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); /* Check the type and OIDs of the IP route table */ vars[0].name.idLength = DEFINE_SIZEOF(mib2IpRouteTable); vars[0].name.ids = mib2IpRouteTable; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; noChange = FALSE; do { ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); if (!ret) moreData = FALSE; else if (error) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength)) moreData = FALSE; else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { /* Make sure the size of the OID is right. * FIXME: don't know if IPv6 addrs are shared with this table. * Don't think so, but I'm not certain. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 4, "expected length %d, got %d\n", vars[0].name.idLength + 4, vars2[0].name.idLength); /* Make sure the type is right */ ok(vars2[0].value.asnType == ASN_IPADDRESS, "expected type ASN_IPADDRESS, got %02x\n", vars2[0].value.asnType); if (vars2[0].value.asnType == ASN_IPADDRESS) { UINT i; /* The base OID for the route table, 1.3.6.1.2.1.4.21.1.1, is * appended with the dest IP address of the entry. So e.g. a * route entry for 224.0.0.0 is identified in MIB2 as * 1.3.6.1.2.1.4.21.1.1.224.0.0.0 */ for (i = 0; i < vars2[0].value.asnValue.address.length; i++) { ok(vars2[0].value.asnValue.address.stream[i] == vars2[0].name.ids[vars2[0].name.idLength - 4 + i], "expected ident byte %d to be %d, got %d\n", i, vars2[0].value.asnValue.address.stream[i], vars2[0].name.ids[vars2[0].name.idLength - 4 + i]); } } } else if (noChange) skip("no change in OID, no MIB2 IP route table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); /* Check the type and OIDs of the UDP table */ vars[0].name.idLength = DEFINE_SIZEOF(mib2UdpTable); vars[0].name.ids = mib2UdpTable; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; noChange = FALSE; do { ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); /* FIXME: error and index aren't checked here because the UDP table is * the last OID currently supported by Wine, so the last GetNext fails. * todo_wine is also not effective because it will succeed for all but * the last GetNext. Remove the if (0) if any later OID is supported * by Wine. */ if (0) { ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); } if (!ret) moreData = FALSE; else if (error) moreData = FALSE; else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength)) moreData = FALSE; else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { /* Make sure the size of the OID is right. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 5, "expected length %d, got %d\n", vars[0].name.idLength + 5, vars2[0].name.idLength); /* Make sure the type is right */ ok(vars2[0].value.asnType == ASN_IPADDRESS, "expected type ASN_IPADDRESS, got %02x\n", vars2[0].value.asnType); if (vars2[0].value.asnType == ASN_IPADDRESS) { UINT i; /* Again with the ugly: the base OID for the UDP table, * 1.3.6.1.2.1.7.5.1, is appended with the local IP address and * port number of the entry. So e.g. an entry for * 192.168.1.1:4000 is identified in MIB2 as * 1.3.6.1.2.1.7.5.1.192.168.1.1.4000 */ for (i = 0; i < vars2[0].value.asnValue.address.length; i++) { ok(vars2[0].value.asnValue.address.stream[i] == vars2[0].name.ids[vars2[0].name.idLength - 5 + i], "expected ident byte %d to be %d, got %d\n", i, vars2[0].value.asnValue.address.stream[i], vars2[0].name.ids[vars2[0].name.idLength - 5 + i]); } } } else if (noChange) skip("no change in OID, no MIB2 UDP table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); }
void BaseTrackCache::filterAndSort(const QSet<TrackId>& trackIds, const QString& searchQuery, const QString& extraFilter, const QString& orderByClause, const QList<SortColumn>& sortColumns, const int columnOffset, QHash<TrackId, int>* trackToIndex) { // Skip processing if there are no tracks to filter or sort. if (trackIds.size() == 0) { return; } if (!m_bIndexBuilt) { buildIndex(); } QStringList idStrings; // TODO(rryan) consider making this the data passed in and a separate // QVector for output QSet<TrackId> dirtyTracks; for (const auto& trackId: trackIds) { idStrings << trackId.toString(); if (m_dirtyTracks.contains(trackId)) { dirtyTracks.insert(trackId); } } std::unique_ptr<QueryNode> pQuery(parseQuery( searchQuery, extraFilter, idStrings)); QString filter = pQuery->toSql(); if (!filter.isEmpty()) { filter.prepend("WHERE "); } QString queryString = QString("SELECT %1 FROM %2 %3 %4") .arg(m_idColumn, m_tableName, filter, orderByClause); if (sDebug) { qDebug() << this << "select() executing:" << queryString; } QSqlQuery query(m_database); // This causes a memory savings since QSqlCachedResult (what QtSQLite uses) // won't allocate a giant in-memory table that we won't use at all. query.setForwardOnly(true); query.prepare(queryString); if (!query.exec()) { LOG_FAILED_QUERY(query); } int idColumn = query.record().indexOf(m_idColumn); int rows = query.size(); if (sDebug) { qDebug() << "Rows returned:" << rows; } m_trackOrder.resize(0); // keeps alocated memory trackToIndex->clear(); if (rows > 0) { trackToIndex->reserve(rows); m_trackOrder.reserve(rows); } while (query.next()) { TrackId trackId(query.value(idColumn)); (*trackToIndex)[trackId] = m_trackOrder.size(); m_trackOrder.append(trackId); } // At this point, the original set of tracks have been divided into two // pieces: those that should be in the result set and those that should // not. Unfortunately, due to TrackDAO caching, there may be tracks in // either category that are there incorrectly. We must look at all the dirty // tracks (within the original set, if specified) and evaluate whether they // would match or not match the given filter criteria. Once we correct the // membership of tracks in either set, we must then insertion-sort the // missing tracks into the resulting index list. if (dirtyTracks.size() == 0) { return; } for (TrackId trackId: dirtyTracks) { // Only get the track if it is in the cache. TrackPointer pTrack = lookupCachedTrack(trackId); if (!pTrack) { continue; } // The track should be in the result set if the search is empty or the // track matches the search. bool shouldBeInResultSet = searchQuery.isEmpty() || pQuery->match(pTrack); // If the track is in this result set. bool isInResultSet = trackToIndex->contains(trackId); if (shouldBeInResultSet) { // Track should be in result set... // Remove the track from the results first (we have to do this or it // will sort wrong). if (isInResultSet) { int index = (*trackToIndex)[trackId]; m_trackOrder.remove(index); // Don't update trackToIndex, since we do it below. } // Figure out where it is supposed to sort. The table is sorted by // the sort column, so we can binary search. int insertRow = findSortInsertionPoint( pTrack, sortColumns, columnOffset, m_trackOrder); if (sDebug) { qDebug() << this << "Insertion sort says it should be inserted at:" << insertRow; } // The track should sort at insertRow m_trackOrder.insert(insertRow, trackId); trackToIndex->clear(); // Fix the index. TODO(rryan) find a non-stupid way to do this. for (int i = 0; i < m_trackOrder.size(); ++i) { (*trackToIndex)[m_trackOrder[i]] = i; } } else if (isInResultSet) { // Track should not be in this result set, but it is. We need to // remove it. int index = (*trackToIndex)[trackId]; m_trackOrder.remove(index); trackToIndex->clear(); // Fix the index. TODO(rryan) find a non-stupid way to do this. for (int i = 0; i < m_trackOrder.size(); ++i) { (*trackToIndex)[m_trackOrder[i]] = i; } } } }
TEST_F(SearchQueryParserTest, HumanReadableDurationSearchwithOperators) { QStringList searchColumns; searchColumns << "artist" << "album"; QScopedPointer<QueryNode> pQuery( m_parser.parseQuery("duration:>1:30", searchColumns, "")); TrackPointer pTrack(new TrackInfoObject()); pTrack->setSampleRate(44100); pTrack->setDuration(89); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(91); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration > 90)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:>=90", searchColumns, "")); pTrack->setDuration(89); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(90); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration >= 90)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:>=1:30", searchColumns, "")); pTrack->setDuration(89); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(90); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration >= 90)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:<2:30", searchColumns, "")); pTrack->setDuration(151); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(89); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration < 150)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:<=2:30", searchColumns, "")); pTrack->setDuration(191); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration <= 150)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:<=150", searchColumns, "")); pTrack->setDuration(191); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration <= 150)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:<=2m30s", searchColumns, "")); pTrack->setDuration(191); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration <= 150)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:<=2m", searchColumns, "")); pTrack->setDuration(191); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(110); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration <= 120)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:<=2:", searchColumns, "")); pTrack->setDuration(191); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(110); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration <= 120)")), qPrintable(pQuery->toSql())); pQuery.reset(m_parser.parseQuery("duration:>=1:3", searchColumns, "")); pTrack->setDuration(60); EXPECT_FALSE(pQuery->match(pTrack)); pTrack->setDuration(150); EXPECT_TRUE(pQuery->match(pTrack)); EXPECT_STREQ( qPrintable(QString("(duration >= 63)")), qPrintable(pQuery->toSql())); }