Enhancement - Attribute modifiers

- Implemented half the modifiers.  The easy half.
- Implemented unit tests that don't all pass yet, and are incomplete.
This commit is contained in:
Paul Beckingham 2009-06-05 01:49:53 -04:00
parent 2aa43fe4fe
commit 0ec3b4b6af
3 changed files with 150 additions and 33 deletions

View file

@ -27,7 +27,8 @@
#include <sstream> #include <sstream>
#include <stdlib.h> #include <stdlib.h>
#include <text.h> #include "text.h"
#include "util.h"
#include "Att.h" #include "Att.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -159,41 +160,78 @@ bool Att::validMod (const std::string& mod) const
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// "this" is the attribute that has modifiers. "other" is the attribute from a
// Record that does not have modifiers, but may have a value.
bool Att::match (const Att& other) const bool Att::match (const Att& other) const
{ {
// No modifier means automatic pass. // Assume a match, and short-circuit on mismatch.
/* foreach (mod, mMods)
if (*this == "") // i18n: no {
return true; // is = equal.
*/ if (*mod == "is")
if (mValue != other.mValue)
return false;
// TODO before // isnt = not equal.
// TODO after if (*mod == "isnt")
// TODO not if (mValue == other.mValue)
// TODO none return false;
// TODO any
// TODO synth
// TODO under
// TODO over
// TODO first
// TODO last
// TODO this
// TODO next
/* // any = any value, but not empty value.
if (*this == "is") // i18n: TODO if (*mod == "any")
return *this == other ? true : false; if (other.mValue == "")
return false;
if (*this == "isnt") // i18n: TODO // none = must have empty value.
return *this != other ? true : false; if (*mod == "none")
*/ if (other.mValue != "")
return false;
// TODO has // startswith = first characters must match.
// TODO hasnt if (*mod == "startswith")
// TODO startswith {
// TODO endswith if (other.mValue.length () < mValue.length ())
return false;
return false; if (mValue != other.mValue.substr (0, mValue.length ()))
return false;
}
// endswith = last characters must match.
if (*mod == "endswith")
{
if (other.mValue.length () < mValue.length ())
return false;
if (mValue != other.mValue.substr (
other.mValue.length () - mValue.length (),
std::string::npos))
return false;
}
// has = contains as a substring.
if (*mod == "has")
if (other.mValue.find (mValue) == std::string::npos)
return false;
// hasnt = does not contain as a substring.
if (*mod == "hasnt")
if (other.mValue.find (mValue) != std::string::npos)
return false;
// TODO before
// TODO after
// TODO not <-- could be a problem
// TODO synth
// TODO under
// TODO over
// TODO first
// TODO last
// TODO this
// TODO next
}
return true;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -38,9 +38,17 @@ bool Filter::pass (const Record& record) const
// If record doesn't have the attribute, fail. If it does have the attribute // If record doesn't have the attribute, fail. If it does have the attribute
// but it doesn't match, fail. // but it doesn't match, fail.
foreach (att, (*this)) foreach (att, (*this))
if ((r = record.find (att->name ())) == record.end () || {
! att->match (r->second)) // If the record doesn't have the attribute, match against a default one.
// This is because "att" may contain a modifier like "name.not:X".
if ((r = record.find (att->name ())) == record.end ())
{
if (! att->match (Att ()))
return false; return false;
}
else if (! att->match (r->second))
return false;
}
return true; return true;
} }

View file

@ -34,7 +34,7 @@ Context context;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv) int main (int argc, char** argv)
{ {
UnitTest test (6); UnitTest test (14);
// Create a filter consisting of two Att criteria. // Create a filter consisting of two Att criteria.
Filter f; Filter f;
@ -63,7 +63,78 @@ int main (int argc, char** argv)
partial.set ("name1", "value1"); partial.set ("name1", "value1");
test.notok (f.pass (no0), "no match against partial T2"); test.notok (f.pass (no0), "no match against partial T2");
// TODO Modifiers. // Modifiers.
T2 mods;
mods.set ("name", "value");
Att a ("name", "value");
a.addMod ("is");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "name:value -> name.is:value = match");
// TODO test inverse.
a = Att ("name", "value");
a.addMod ("isnt");
f.clear ();
f.push_back (a);
test.notok (f.pass (mods), "name:value -> name.isnt:value = no match");
// TODO test inverse.
a = Att ("name", "val");
a.addMod ("startswith");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "name:value -> name.startswith:val = match");
// TODO test inverse.
a = Att ("name", "lue");
a.addMod ("endswith");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "name:value -> name.endswith:lue = match");
// TODO test inverse.
a = Att ("name", "value");
a.addMod ("has");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "name:value -> name.has:alu = match");
// TODO test inverse.
a = Att ("name", "value");
a.addMod ("hasnt");
f.clear ();
f.push_back (a);
test.notok (f.pass (mods), "name:value -> name.hasnt:alu = no match");
// TODO test inverse.
a = Att ("name", "");
a.addMod ("any");
f.clear ();
f.push_back (a);
test.ok (f.pass (mods), "name:value -> name.any: = match");
// TODO test inverse.
a = Att ("name", "");
a.addMod ("none");
f.clear ();
f.push_back (a);
test.notok (f.pass (mods), "name:value -> name.none: = no match");
// TODO test inverse.
/*
"before"
"after"
"not"
"synth"
"under"
"over"
"first"
"last"
"this"
"next"
*/
return 0; return 0;
} }