mirror of https://github.com/KLayout/klayout.git
WIP: Salt class and unit tests
This commit is contained in:
parent
134534adca
commit
695a5d3169
|
|
@ -21,11 +21,110 @@
|
|||
*/
|
||||
|
||||
#include "laySalt.h"
|
||||
#include "tlString.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
Salt::Salt ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Salt::Salt (const Salt &other)
|
||||
: QObject ()
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
Salt &Salt::operator= (const Salt &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_root = other.m_root;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
Salt::add_location (const std::string &path)
|
||||
{
|
||||
// do nothing if the collection is already there
|
||||
QFileInfo fi (tl::to_qstring (path));
|
||||
for (lay::SaltGrains::collection_iterator g = m_root.begin_collections (); g != m_root.end_collections (); ++g) {
|
||||
if (QFileInfo (tl::to_qstring (g->path ())) == fi) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lay::SaltGrains gg = lay::SaltGrains::from_path (path);
|
||||
m_root.add_collection (gg);
|
||||
mp_flat_grains.clear ();
|
||||
emit collections_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
Salt::remove_location (const std::string &path)
|
||||
{
|
||||
QFileInfo fi (tl::to_qstring (path));
|
||||
for (lay::SaltGrains::collection_iterator g = m_root.begin_collections (); g != m_root.end_collections (); ++g) {
|
||||
if (QFileInfo (tl::to_qstring (g->path ())) == fi) {
|
||||
m_root.remove_collection (g, false);
|
||||
mp_flat_grains.clear ();
|
||||
emit collections_changed ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Salt::refresh ()
|
||||
{
|
||||
lay::SaltGrains new_root;
|
||||
for (lay::SaltGrains::collection_iterator g = m_root.begin_collections (); g != m_root.end_collections (); ++g) {
|
||||
new_root.add_collection (lay::SaltGrains::from_path (g->path ()));
|
||||
}
|
||||
if (new_root != m_root) {
|
||||
m_root = new_root;
|
||||
mp_flat_grains.clear ();
|
||||
emit collections_changed ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Salt::add_collection_to_flat (SaltGrains &gg)
|
||||
{
|
||||
for (lay::SaltGrains::grain_iterator g = gg.begin_grains (); g != gg.end_grains (); ++g) {
|
||||
// TODO: get rid of the const cast - would require a non-const grain iterator
|
||||
mp_flat_grains.push_back (const_cast <SaltGrain *> (g.operator-> ()));
|
||||
}
|
||||
for (lay::SaltGrains::collection_iterator g = gg.begin_collections (); g != gg.end_collections (); ++g) {
|
||||
// TODO: get rid of the const cast - would require a non-const grain collection iterator
|
||||
add_collection_to_flat (const_cast <SaltGrains &> (*g));
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct NameCompare
|
||||
{
|
||||
bool operator () (lay::SaltGrain *a, lay::SaltGrain *b) const
|
||||
{
|
||||
// TODO: UTF-8 support?
|
||||
return a->name () < b->name ();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Salt::ensure_flat_present ()
|
||||
{
|
||||
if (mp_flat_grains.empty ()) {
|
||||
add_collection_to_flat (m_root);
|
||||
std::sort (mp_flat_grains.begin (), mp_flat_grains.end (), NameCompare ());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,11 +23,110 @@
|
|||
#ifndef HDR_laySalt
|
||||
#define HDR_laySalt
|
||||
|
||||
#include "layCommon.h"
|
||||
#include "laySaltGrain.h"
|
||||
#include "laySaltGrains.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The global salt (package manager) object
|
||||
* This object can be configured to represent a couple of locations.
|
||||
* It will provide a collection of grains for these locations.
|
||||
*/
|
||||
class LAY_PUBLIC Salt
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef SaltGrains::collection_iterator iterator;
|
||||
typedef std::vector<SaltGrain *>::const_iterator flat_iterator;
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
Salt ();
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
*/
|
||||
Salt (const Salt &other);
|
||||
|
||||
/**
|
||||
* @brief assignment
|
||||
*/
|
||||
Salt &operator= (const Salt &other);
|
||||
|
||||
/**
|
||||
* @brief Adds the given location to the ones the package manager uses
|
||||
* Adding a location will scan the folder and make the contents available
|
||||
* as a new collection.
|
||||
*/
|
||||
void add_location (const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief Removes a given location
|
||||
* This will remove the collection from the package locations.
|
||||
*/
|
||||
void remove_location (const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief Refreshes the collections
|
||||
* This method rescans all registered locations.
|
||||
*/
|
||||
void refresh ();
|
||||
|
||||
/**
|
||||
* @brief Iterates the collections (begin)
|
||||
*/
|
||||
iterator begin () const
|
||||
{
|
||||
return m_root.begin_collections ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates the collections (end)
|
||||
*/
|
||||
iterator end () const
|
||||
{
|
||||
return m_root.end_collections ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A flat iterator of (sorted) grains (begin)
|
||||
*/
|
||||
flat_iterator begin_flat ()
|
||||
{
|
||||
ensure_flat_present ();
|
||||
return mp_flat_grains.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A flat iterator of (sorted) grains (end)
|
||||
*/
|
||||
flat_iterator end_flat ()
|
||||
{
|
||||
ensure_flat_present ();
|
||||
return mp_flat_grains.end ();
|
||||
}
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief A signal triggered when one of the collections changed
|
||||
*/
|
||||
void collections_changed ();
|
||||
|
||||
private:
|
||||
SaltGrains m_root;
|
||||
std::vector<SaltGrain *> mp_flat_grains;
|
||||
|
||||
void ensure_flat_present ();
|
||||
void add_collection_to_flat (lay::SaltGrains &gg);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ SaltGrains::remove_collection (collection_iterator iter, bool with_files)
|
|||
// NOTE: this is kind of inefficient, but in order to maintain the const iterator semantics this approach is required
|
||||
for (collections_type::iterator i = m_collections.begin (); i != m_collections.end (); ++i) {
|
||||
if (i == iter) {
|
||||
if (with_files && !tl::rm_dir_recursive (tl::to_qstring (path ()))) {
|
||||
if (with_files && !tl::rm_dir_recursive (tl::to_qstring (i->path ()))) {
|
||||
return false;
|
||||
}
|
||||
m_collections.erase (i);
|
||||
|
|
@ -98,7 +98,7 @@ SaltGrains::remove_grain (grain_iterator iter, bool with_files)
|
|||
// NOTE: this is kind of inefficient, but in order to maintain the const iterator semantics this approach is required
|
||||
for (grains_type::iterator i = m_grains.begin (); i != m_grains.end (); ++i) {
|
||||
if (i == iter) {
|
||||
if (with_files && !tl::rm_dir_recursive (tl::to_qstring (path ()))) {
|
||||
if (with_files && !tl::rm_dir_recursive (tl::to_qstring (i->path ()))) {
|
||||
return false;
|
||||
}
|
||||
m_grains.erase (i);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#ifndef HDR_laySaltGrains
|
||||
#define HDR_laySaltGrains
|
||||
|
||||
#include "layCommon.h"
|
||||
#include "laySaltGrain.h"
|
||||
|
||||
#include <list>
|
||||
|
|
|
|||
|
|
@ -23,10 +23,52 @@
|
|||
|
||||
#include "laySaltGrain.h"
|
||||
#include "laySaltGrains.h"
|
||||
#include "laySalt.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "utHead.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QSignalSpy>
|
||||
|
||||
static std::string grains_to_string (const lay::SaltGrains &gg)
|
||||
{
|
||||
std::string res;
|
||||
res += "[";
|
||||
bool first = true;
|
||||
for (lay::SaltGrains::grain_iterator g = gg.begin_grains (); g != gg.end_grains (); ++g) {
|
||||
if (! first) {
|
||||
res += ",";
|
||||
}
|
||||
first = false;
|
||||
res += g->name ();
|
||||
}
|
||||
for (lay::SaltGrains::collection_iterator gc = gg.begin_collections (); gc != gg.end_collections (); ++gc) {
|
||||
if (! first) {
|
||||
res += ",";
|
||||
}
|
||||
first = false;
|
||||
res += gc->name ();
|
||||
res += grains_to_string (*gc);
|
||||
}
|
||||
res += "]";
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string salt_to_string (lay::Salt &salt)
|
||||
{
|
||||
std::string res;
|
||||
res += "[";
|
||||
bool first = true;
|
||||
for (lay::Salt::flat_iterator i = salt.begin_flat (); i != salt.end_flat (); ++i) {
|
||||
if (! first) {
|
||||
res += ",";
|
||||
}
|
||||
first = false;
|
||||
res += (*i)->name ();
|
||||
}
|
||||
res += "]";
|
||||
return res;
|
||||
}
|
||||
|
||||
TEST (1)
|
||||
{
|
||||
|
|
@ -111,30 +153,6 @@ TEST (2)
|
|||
}
|
||||
|
||||
|
||||
static std::string grains_to_string (const lay::SaltGrains &gg)
|
||||
{
|
||||
std::string res;
|
||||
res += "[";
|
||||
bool first = true;
|
||||
for (lay::SaltGrains::grain_iterator g = gg.begin_grains (); g != gg.end_grains (); ++g) {
|
||||
if (! first) {
|
||||
res += ",";
|
||||
}
|
||||
first = false;
|
||||
res += g->name ();
|
||||
}
|
||||
for (lay::SaltGrains::collection_iterator gc = gg.begin_collections (); gc != gg.end_collections (); ++gc) {
|
||||
if (! first) {
|
||||
res += ",";
|
||||
}
|
||||
first = false;
|
||||
res += gc->name ();
|
||||
res += grains_to_string (*gc);
|
||||
}
|
||||
res += "]";
|
||||
return res;
|
||||
}
|
||||
|
||||
TEST (3)
|
||||
{
|
||||
const QString grain_spec_file = QString::fromUtf8 ("grain.xml");
|
||||
|
|
@ -184,4 +202,107 @@ TEST (3)
|
|||
EXPECT_EQ (gg.is_empty (), false);
|
||||
EXPECT_EQ (grains_to_string (gg), "[a,b,c[c/u,c/c[c/c/v]]]");
|
||||
EXPECT_EQ (gg.begin_collections ()->path (), tl::to_string (dir_c.absolutePath ()));
|
||||
|
||||
gg.remove_grain (gg.begin_grains (), false);
|
||||
EXPECT_EQ (grains_to_string (gg), "[b,c[c/u,c/c[c/c/v]]]");
|
||||
|
||||
gg = lay::SaltGrains::from_path (tl::to_string (tmp_dir.path ()));
|
||||
EXPECT_EQ (grains_to_string (gg), "[a,b,c[c/u,c/c[c/c/v]]]");
|
||||
gg.remove_grain (gg.begin_grains (), true);
|
||||
|
||||
gg = lay::SaltGrains::from_path (tl::to_string (tmp_dir.path ()));
|
||||
EXPECT_EQ (grains_to_string (gg), "[b,c[c/u,c/c[c/c/v]]]");
|
||||
|
||||
gg.remove_collection (gg.begin_collections (), false);
|
||||
EXPECT_EQ (grains_to_string (gg), "[b]");
|
||||
|
||||
gg = lay::SaltGrains::from_path (tl::to_string (tmp_dir.path ()));
|
||||
EXPECT_EQ (grains_to_string (gg), "[b,c[c/u,c/c[c/c/v]]]");
|
||||
|
||||
gg.remove_collection (gg.begin_collections (), true);
|
||||
EXPECT_EQ (grains_to_string (gg), "[b]");
|
||||
gg = lay::SaltGrains::from_path (tl::to_string (tmp_dir.path ()));
|
||||
EXPECT_EQ (grains_to_string (gg), "[b]");
|
||||
}
|
||||
|
||||
TEST (4)
|
||||
{
|
||||
const QString grain_spec_file = QString::fromUtf8 ("grain.xml");
|
||||
|
||||
// That's just preparation ...
|
||||
|
||||
lay::SaltGrain g;
|
||||
g.set_name ("x");
|
||||
|
||||
QDir tmp_dir (QFileInfo (tl::to_qstring (tmp_file ())).absolutePath ());
|
||||
QDir dir_a (tmp_dir.filePath (QString::fromUtf8 ("a")));
|
||||
QDir dir_b (tmp_dir.filePath (QString::fromUtf8 ("b")));
|
||||
QDir dir_c (tmp_dir.filePath (QString::fromUtf8 ("c")));
|
||||
QDir dir_cu (dir_c.filePath (QString::fromUtf8 ("u")));
|
||||
QDir dir_cc (dir_c.filePath (QString::fromUtf8 ("c")));
|
||||
QDir dir_ccv (dir_cc.filePath (QString::fromUtf8 ("v")));
|
||||
|
||||
tl_assert (tl::rm_dir_recursive (tmp_dir.path ()));
|
||||
|
||||
lay::SaltGrains gg;
|
||||
gg = lay::SaltGrains::from_path (tl::to_string (tmp_dir.path ()));
|
||||
EXPECT_EQ (gg.is_empty (), true);
|
||||
EXPECT_EQ (grains_to_string (gg), "[]");
|
||||
|
||||
tmp_dir.mkdir (dir_a.dirName ());
|
||||
tmp_dir.mkdir (dir_b.dirName ());
|
||||
tmp_dir.mkdir (dir_c.dirName ());
|
||||
dir_c.mkdir (dir_cu.dirName ());
|
||||
dir_c.mkdir (dir_cc.dirName ());
|
||||
dir_cc.mkdir (dir_ccv.dirName ());
|
||||
|
||||
gg = lay::SaltGrains::from_path (tl::to_string (tmp_dir.path ()));
|
||||
EXPECT_EQ (gg.is_empty (), true);
|
||||
EXPECT_EQ (grains_to_string (gg), "[]");
|
||||
EXPECT_EQ (gg.path (), tl::to_string (tmp_dir.path ()));
|
||||
|
||||
g.save (tl::to_string (dir_a.absoluteFilePath (grain_spec_file)));
|
||||
g.save (tl::to_string (dir_b.absoluteFilePath (grain_spec_file)));
|
||||
g.save (tl::to_string (dir_cu.absoluteFilePath (grain_spec_file)));
|
||||
g.save (tl::to_string (dir_ccv.absoluteFilePath (grain_spec_file)));
|
||||
|
||||
// That's the main test part
|
||||
|
||||
lay::Salt salt;
|
||||
QSignalSpy spy (&salt, SIGNAL (collections_changed ()));
|
||||
EXPECT_EQ (salt_to_string (salt), "[]");
|
||||
|
||||
spy.clear ();
|
||||
salt.add_location (tl::to_string (tmp_dir.path ()));
|
||||
EXPECT_EQ (spy.count (), 1);
|
||||
EXPECT_EQ (salt_to_string (salt), "[a,b,c/c/v,c/u]");
|
||||
|
||||
spy.clear ();
|
||||
salt.add_location (tl::to_string (tmp_dir.path ()));
|
||||
EXPECT_EQ (spy.count (), 0);
|
||||
EXPECT_EQ (salt_to_string (salt), "[a,b,c/c/v,c/u]");
|
||||
|
||||
spy.clear ();
|
||||
salt.add_location (tl::to_string (dir_c.path ()));
|
||||
EXPECT_EQ (spy.count (), 1);
|
||||
EXPECT_EQ (salt_to_string (salt), "[a,b,c/c/v,c/u,c/v,u]");
|
||||
|
||||
lay::Salt salt_copy = salt;
|
||||
(const_cast<lay::SaltGrains &> (*salt_copy.begin ())).remove_grain (salt_copy.begin ()->begin_grains (), true);
|
||||
|
||||
spy.clear ();
|
||||
salt.refresh ();
|
||||
EXPECT_EQ (spy.count (), 1);
|
||||
EXPECT_EQ (salt_to_string (salt), "[b,c/c/v,c/u,c/v,u]");
|
||||
|
||||
spy.clear ();
|
||||
salt.remove_location (tl::to_string (dir_c.path ()));
|
||||
EXPECT_EQ (spy.count (), 1);
|
||||
EXPECT_EQ (salt_to_string (salt), "[b,c/c/v,c/u]");
|
||||
|
||||
spy.clear ();
|
||||
// location already removed
|
||||
salt.remove_location (tl::to_string (dir_c.path ()));
|
||||
EXPECT_EQ (spy.count (), 0);
|
||||
EXPECT_EQ (salt_to_string (salt), "[b,c/c/v,c/u]");
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ SOURCES = \
|
|||
tlXMLParser.cc \
|
||||
gsiTest.cc \
|
||||
tlFileSystemWatcher.cc \
|
||||
laySaltGrain.cc
|
||||
laySalt.cc
|
||||
|
||||
# main components:
|
||||
SOURCES += \
|
||||
|
|
|
|||
Loading…
Reference in New Issue