[Aptitude-devel] r2954 - in branches/aptitude-0.3/aptitude: . src/generic/problemresolver
Daniel Burrows
dburrows@costa.debian.org
Fri, 08 Apr 2005 16:57:00 +0000
Author: dburrows
Date: Fri Apr 8 16:56:57 2005
New Revision: 2954
Modified:
branches/aptitude-0.3/aptitude/ChangeLog
branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h
branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc
branches/aptitude-0.3/aptitude/src/generic/problemresolver/test1.txt
Log:
Greatly enhance the test script system (although maybe Python bindings
would be more flexible?)
Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog (original)
+++ branches/aptitude-0.3/aptitude/ChangeLog Fri Apr 8 16:56:57 2005
@@ -1,5 +1,11 @@
2005-04-08 Daniel Burrows <dburrows@debian.org>
+ * src/generic/problemresolver/test.cc:
+
+ Overhaul the test code to make the test fully controlled
+ by its input file -- including support for specifying
+ tests to run on the universe and the expected results.
+
* src/generic/problemresolver/problemresolver.h, src/generic/problemresolver/test.cc:
Make dump_universe generic, move it to problemresolver.h, and
Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h (original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/problemresolver.h Fri Apr 8 16:56:57 2005
@@ -659,6 +659,11 @@
version_score[ver.get_id()]+=score;
}
+ /** \return the score of the version ver. */
+ int get_version_score(version &ver)
+ {
+ return version_score[ver.get_id()];
+ }
/** Try to find the "next" solution: remove partial solutions from
* the open queue and place them in the closed queue until one of
@@ -729,12 +734,40 @@
throw NoMoreSolutions();
}
+
+ void dump_scores(std::ostream &out)
+ {
+ out << "{" << std::endl;
+ for(typename PackageUniverse::package_iterator i=universe.packages_begin();
+ i!=universe.packages_end(); ++i)
+ {
+ bool any_modified=false;
+
+ for(typename PackageUniverse::package::version_iterator j=(*i).versions_begin();
+ j!=(*i).versions_end(); ++j)
+ if(version_scores[(*j).get_id()]!=0)
+ any_modified=true;
+
+ if(any_modified)
+ {
+ out << " SCORE " << (*i).get_name() << " <";
+
+ for(typename PackageUniverse::package::version_iterator j=(*i).versions_begin();
+ j!=(*i).versions_end(); ++j)
+ if(version_scores[(*j).get_id()]!=0)
+ out << " " << (*j).get_name();
+
+ out << " >" << std::endl;
+ }
+ }
+ }
};
template<class PackageUniverse>
-void dump_universe(const PackageUniverse &world, ostream &out)
+void dump_universe(const PackageUniverse &world, std::ostream &out)
{
+ out << "UNIVERSE ";
for(typename PackageUniverse::package_iterator p=world.packages_begin();
p!=world.packages_end(); ++p)
{
Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc (original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/test.cc Fri Apr 8 16:56:57 2005
@@ -147,7 +147,7 @@
version_iterator versions_end() const {return versions.end();}
/** Returns the version corresponding to the given name or aborts */
- dummy_version *version_from_name(const string &the_name);
+ dummy_version *version_from_name(const string &the_name) const;
/** Sets the current version to the given version. */
void set_current_version(dummy_version *v)
@@ -220,9 +220,9 @@
delete *i;
}
-dummy_version *dummy_package::version_from_name(const string &the_name)
+dummy_version *dummy_package::version_from_name(const string &the_name) const
{
- for(vector<dummy_version *>::iterator i=versions.begin(); i!=versions.end(); ++i)
+ for(vector<dummy_version *>::const_iterator i=versions.begin(); i!=versions.end(); ++i)
if((*i)->get_name()==the_name)
return *i;
@@ -343,6 +343,11 @@
return version(&real_package->current_version());
}
+ version version_from_name(string name) const
+ {
+ return version(real_package->version_from_name(name));
+ }
+
wrap_ptr_iter<dummy_version, version> versions_begin() const
{
return real_package->versions_begin();
@@ -528,6 +533,16 @@
}
};
+ dummy_package *find_package_internal(string pkg_name)
+ {
+ map<string, dummy_package *>::const_iterator pfound=packages_by_name.find(pkg_name);
+
+ if(pfound==packages_by_name.end())
+ throw NoSuchNameError("package", pkg_name);
+
+ return pfound->second;
+ }
+
public:
virtual ~dummy_universe()
{
@@ -569,6 +584,12 @@
packages_by_name[name]=packages.back();
}
+ /** Find a package by name. */
+ package find_package(string pkg_name)
+ {
+ return find_package_internal(pkg_name);
+ }
+
/** Add a dependency to the universe. For convenience
* this is string-based.
*/
@@ -576,12 +597,7 @@
const vector<pair<string, string> > &target_names,
bool is_conflict)
{
- map<string, dummy_package *>::const_iterator pfound=packages_by_name.find(pkg_name);
-
- if(pfound==packages_by_name.end())
- throw NoSuchNameError("package", pkg_name);
-
- dummy_package *pkg=pfound->second;
+ dummy_package *pkg=find_package_internal(pkg_name);
set<dummy_version *, compare_dummy_versions> targets;
set<dummy_package *, compare_dummy_packages> packages;
@@ -589,12 +605,10 @@
for(vector<pair<string, string> >::const_iterator i=target_names.begin();
i!=target_names.end(); ++i)
{
- pfound=packages_by_name.find(i->first);
- if(pfound == packages_by_name.end())
- throw NoSuchNameError("package", i->first);
+ dummy_package *pkg=find_package_internal(i->first);
- packages.insert(pfound->second);
- targets.insert(pfound->second->version_from_name(i->second));
+ packages.insert(pkg);
+ targets.insert(pkg->version_from_name(i->second));
}
if(!is_conflict)
@@ -686,13 +700,18 @@
// The syntax is quite simple: it consists of whitespace-separated
// words, of the form:
//
-// TEST ::= UNIVERSE
-// UNIVERSE ::= PACKAGE | DEP
-// PACKAGE ::= "PACKAGE" pkgname < vername1 ... > curver
-// DEP ::= "DEP" pkgname1 vername1 -> < pkgname2 vername2 ... >
-// | "DEP" pkgname1 vername1 !! < pkgname2 vername2 ... >
+// SCRIPT ::= "UNIVERSE" "[" UNIVERSE "]" TEST ...
+// UNIVERSE ::= (PACKAGE | DEP) ...
+// PACKAGE ::= "PACKAGE" pkgname "<" vername1 ... ">" currentver
+// DEP ::= "DEP" pkgname1 vername1 "->" "<" pkgname2 vername2 ... ">"
+// | "DEP" pkgname1 vername1 "!!" "<" pkgname2 vername2 ... ">"
//
-// The latter form is a Conflicts, and is implicitly converted to
+// TEST ::= "TEST" step_score broken_score "{" SCORE ... "}" "EXPECT" "(" SOLN ... ")"
+// SCORE ::= "SCORE" pkgname "<" vername1 score1 ... ">"
+// SOLN ::= step_count "ANY"
+// | step_count "<" pkgname1 vername1 ... ">"
+//
+// The second DEP form is a Conflicts, and is implicitly converted to
// dependency form internally.
class ParseError:public Exception
@@ -720,6 +739,7 @@
return pair<string, string>(pkgname, vername);
}
+/** Parses a universe to the closing ']'. */
dummy_universe *parse_universe(istream &in)
{
dummy_universe *rval=new dummy_universe;
@@ -729,9 +749,14 @@
{
string s;
+ if(in.eof())
+ throw ParseError("Expected ']', 'PACKAGE', or 'DEP'; got EOF");
+
in >> s >> ws;
- if(s == "PACKAGE")
+ if(s == "]")
+ break;
+ else if(s == "PACKAGE")
{
string pkgname;
@@ -754,15 +779,15 @@
{
string vername;
+ if(in.eof())
+ throw ParseError("Expected version name or '>', got EOF");
+
in >> vername >> ws;
if(vername == ">")
break;
vernames.push_back(vername);
-
- if(!in)
- throw ParseError("Expected version name or '>', got EOF");
}
if(in.eof())
@@ -828,55 +853,335 @@
rval->add_dep(source.first, source.second, targets,
is_conflict);
}
+ else
+ throw ParseError("Expected PACKAGE or DEP, got "+s);
+
+ if(in.eof())
+ throw ParseError("Expected ']' following universe declaration, got EOF.");
}
return rval;
}
-int main(int argc, char **argv)
+/** Reads the list of scores into the resolver. */
+void read_scores(istream &f,
+ dummy_universe *universe, dummy_resolver &resolver)
{
- int rval=0;
+ if(!universe)
+ throw ParseError("Internal error: NULL universe in read_scores");
- for(int i=1; i<argc; ++i)
+ f >> ws;
+
+ while(f)
{
- ifstream f(argv[i]);
+ string s;
- if(!f)
- {
- cerr << "Couldn't read from file " << argv[i] << "." << endl;
- rval=-1;
- }
+ f >> s >> ws;
- try
+ if(s == "}")
+ return;
+ else if(s == "SCORE")
{
- dummy_universe *u=parse_universe(f);
+ if(f.eof())
+ throw ParseError("Expected package name following SCORE, got "+s);
+
+ string pkgname;
+
+ f >> pkgname >> ws;
+
+ dummy_universe::package pkg=universe->find_package(pkgname);
+
+ if(f.eof())
+ throw ParseError("Expected '<' following package name, got EOF");
+
+ f >> s >> ws;
- cout << "Universe:" << endl;
- dump_universe(*u, cout);
- cout << "==============================================" << endl;
- cout << "Trying to solve...." << endl;
+ if(s != "<")
+ throw ParseError("Expected '<' following package name, got "+s);
- dummy_resolver resolver(10, 10, *u);
+ if(f.eof())
+ throw ParseError("Expected '>' or version name, got EOF");
- try
+ while(f)
{
- dummy_resolver::solution s=resolver.find_next_solution(10000);
+ string vername;
+ int score;
+
+ f >> vername >> ws;
+
+ if(vername == ">")
+ break;
+
+ dummy_universe::version ver=pkg.version_from_name(vername);
+
+ if(f.eof())
+ throw ParseError("Expected score, got EOF");
- cout << endl;
- cout << "Found solution ";
- s.dump(cout);
- cout << endl;
+ f >> score >> ws;
+
+ if(f.eof())
+ throw ParseError("Expected '>' or version name, got EOF");
+
+ if(!f)
+ throw ParseError("Error reading score of " + pkgname + " " + vername);
+
+ resolver.set_version_score(ver, score);
}
- catch(NoMoreSolutions e)
+
+ if(f.eof())
+ throw ParseError("Expected '}' or SCORE, got EOF");
+ }
+ else
+ throw ParseError("Expected 'SCORE' or '}', got "+s);
+ }
+
+ throw ParseError("Unexpected error reading score list.");
+}
+
+/** Reads the tail of a non-ANY SOLN form. */
+map<dummy_universe::package, dummy_resolver::version> read_solution(istream &f, dummy_universe *universe)
+{
+ if(!universe)
+ throw ParseError("Internal error: NULL universe passed to read_solution");
+
+ map<dummy_universe::package, dummy_resolver::version> rval;
+
+ f >> ws;
+
+ while(f)
+ {
+ string s;
+
+ if(f.eof())
+ throw ParseError("Expected '>' or package, got EOF");
+
+ f >> s >> ws;
+
+ if(s == ">")
+ return rval;
+ else
+ {
+ if(f.eof())
+ throw ParseError("Expected version, got EOF");
+
+ dummy_universe::package pkg=universe->find_package(s);
+
+ f >> s >> ws;
+
+ if(f.eof())
+ throw ParseError("Expected '>' or package name, got EOF");
+
+ if(s == ">")
+ throw ParseError("Expected version name, got '>'");
+
+ dummy_universe::version ver=pkg.version_from_name(s);
+
+ if(rval.find(pkg) != rval.end())
+ throw ParseError("Package "+pkg.get_name()+" bound twice in solution");
+
+ rval[pkg]=ver;
+ }
+ }
+
+ throw ParseError("Unexpected error reading solution list");
+}
+
+void run_test_file(istream &f)
+{
+ dummy_universe *universe=NULL;
+
+ f >> ws;
+
+ try
+ {
+ while(f)
+ {
+ string s;
+
+ if(f.eof())
+ // This is the only place where EOF is valid.
+ return;
+
+ f >> s >> ws;
+
+ if(s == "UNIVERSE")
{
- cout << "No solutions found." << endl;
+ if(f.eof())
+ throw ParseError("Expected '[' following UNIVERSE, got EOF.");
+
+ f >> s >> ws;
+
+ if(s != "[")
+ throw ParseError("Expected '[' following UNIVERSE, got " + s);
+
+ dummy_universe *new_universe=parse_universe(f);
+
+ delete universe;
+ universe=new_universe;
}
- catch(NoMoreTime e)
+ else if(s == "TEST")
{
- cout << "Could not solve the problem within 10000 steps." << endl;
+ if(!universe)
+ throw ParseError("Expected UNIVERSE before TEST");
+
+ if(f.eof())
+ throw ParseError("Expected step_score and broken_score following 'TEST', got EOF");
+
+ int step_score;
+ int broken_score;
+
+ f >> step_score >> broken_score;
+
+ if(f.eof())
+ throw ParseError("Expected '{' following broken_score, got EOF");
+
+ if(!f)
+ throw ParseError("Error reading step_score and broken_score after 'TEST'");
+
+ f >> s >> ws;
+
+ if(s != "{")
+ throw ParseError("Expected '{' following TEST, got "+s);
+
+ dummy_resolver resolver(step_score, broken_score, *universe);
+
+ read_scores(f, universe, resolver);
+
+ if(f.eof())
+ throw ParseError("Expected 'EXPECT', got EOF");
+
+ f >> s >> ws;
+
+ if(s != "EXPECT")
+ throw ParseError("Expected 'EXPECT', got "+s);
+
+ if(f.eof())
+ throw ParseError("Expected '(' following EXPECT, got EOF");
+
+ f >> s >> ws;
+
+ if(s != "(")
+ throw ParseError("Expected '(' following EXPECT, got "+s);
+
+ while(f)
+ {
+ if(f.eof())
+ throw ParseError("Expected ')' or package name, got EOF");
+
+ f >> s >> ws;
+
+ if(s == ")")
+ break;
+
+ int step_count=atoi(s.c_str());
+
+ if(step_count<=0)
+ throw ParseError("step_count must be a positive integer, not "+s);
+
+ f >> s >> ws;
+
+ if(s == "ANY")
+ {
+ try
+ {
+ dummy_resolver::solution next_soln=resolver.find_next_solution(step_count);
+
+ cout << "Next solution is ";
+ next_soln.dump(cout);
+
+ cout << " (ignored)" << endl;
+ }
+ catch(NoMoreTime)
+ {
+ cout << "Ran out of steps (ignored)" << endl;
+ }
+ catch(NoMoreSolutions)
+ {
+ cout << "Ran out of solutions (ignored)" << endl;
+ }
+ }
+ else if(s == "<")
+ {
+ try
+ {
+ map<dummy_universe::package, dummy_resolver::version> expected=read_solution(f, universe);
+
+ dummy_resolver::solution next_soln=resolver.find_next_solution(step_count);
+
+
+ cout << "Next solution is ";
+ next_soln.dump(cout);
+
+ bool equal=true;
+
+ map<dummy_universe::package, dummy_universe::version>::const_iterator expect_iter=expected.begin();
+ map<dummy_universe::package, dummy_resolver::action>::const_iterator soln_iter=next_soln.get_actions().begin();
+
+ while(equal &&
+ expect_iter != expected.end() &&
+ soln_iter != next_soln.get_actions().end())
+ {
+ if(expect_iter->first != soln_iter->first ||
+ expect_iter->second != soln_iter->second.ver)
+ equal=false;
+ }
+
+ if(equal)
+ cout << " (OK)" << endl;
+ else
+ {
+ cout << " (FAILED)" << endl;
+ cout << "Expected <";
+ for(map<dummy_universe::package, dummy_universe::version>::const_iterator i=expected.begin();
+ i!=expected.end(); ++i)
+ cout << i->first.get_name()
+ << ":="
+ << i->second.get_name();
+ cout << ">" << endl;
+ }
+ }
+ catch(NoMoreSolutions)
+ {
+ cout << "Ran out of solutions (FAILED)" << endl;
+ }
+ catch(NoMoreTime)
+ {
+ cout << "Ran out of time (FAILED)" << endl;
+ }
+ }
+ else
+ throw ParseError("Expected ANY or '<', got "+s);
+ }
}
+ else
+ throw ParseError("Expected UNIVERSE or TEST, got "+s);
+ }
+ }
+ catch(...)
+ {
+ delete universe;
+ throw;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int rval=0;
+
+ for(int i=1; i<argc; ++i)
+ {
+ ifstream f(argv[i]);
- delete u;
+ if(!f)
+ {
+ cerr << "Couldn't read from file " << argv[i] << "." << endl;
+ rval=-1;
+ }
+
+ try
+ {
+ f >> ws;
+ run_test_file(f);
}
catch(const Exception &e)
{
Modified: branches/aptitude-0.3/aptitude/src/generic/problemresolver/test1.txt
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/problemresolver/test1.txt (original)
+++ branches/aptitude-0.3/aptitude/src/generic/problemresolver/test1.txt Fri Apr 8 16:56:57 2005
@@ -1,19 +1,25 @@
-PACKAGE p1 < v1 v2 v3 > v1
-PACKAGE p2 < v1 v2 v3 > v1
-PACKAGE p3 < v1 v2 v3 > v1
-PACKAGE p4 < v1 v2 v3 > v1
+UNIVERSE [
+ PACKAGE p1 < v1 v2 v3 > v1
+ PACKAGE p2 < v1 v2 v3 > v1
+ PACKAGE p3 < v1 v2 v3 > v1
+ PACKAGE p4 < v1 v2 v3 > v1
-DEP p1 v1 -> < p2 v2 p2 v3 >
-DEP p1 v2 -> < p2 v2 p2 v3 >
-DEP p1 v3 -> < p2 v2 p2 v3 >
+ DEP p1 v1 -> < p2 v2 p2 v3 >
+ DEP p1 v2 -> < p2 v2 p2 v3 >
+ DEP p1 v3 -> < p2 v2 p2 v3 >
-DEP p2 v1 -> < p3 v1 p3 v2 p3 v3 >
-DEP p2 v2 -> < p3 v1 p3 v2 p3 v3 >
+ DEP p2 v1 -> < p3 v1 p3 v2 p3 v3 >
+ DEP p2 v2 -> < p3 v1 p3 v2 p3 v3 >
-DEP p2 v1 !! < p1 v2 p1 v3 >
+ DEP p2 v1 !! < p1 v2 p1 v3 >
-DEP p3 v1 -> < p4 v1 p4 v2 p4 v3 >
-DEP p3 v2 -> < p4 v1 p4 v2 p4 v3 >
-DEP p3 v3 -> < p4 v1 p4 v2 p4 v3 >
+ DEP p3 v1 -> < p4 v1 p4 v2 p4 v3 >
+ DEP p3 v2 -> < p4 v1 p4 v2 p4 v3 >
+ DEP p3 v3 -> < p4 v1 p4 v2 p4 v3 >
+]
+
+TEST 10 10 { } EXPECT ( 10000 ANY
+ 10000 ANY
+ 10000 ANY )
\ No newline at end of file