2011-01-28 21:52:38 +01:00
|
|
|
/* This file is part of Clementine.
|
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
|
|
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2011-04-22 20:53:33 +02:00
|
|
|
#include <Python.h>
|
|
|
|
#include <sip.h>
|
|
|
|
|
|
|
|
#include "sipAPIclementine.h"
|
2011-01-28 21:52:38 +01:00
|
|
|
#include "core/utilities.h"
|
2011-04-22 20:53:33 +02:00
|
|
|
#include "playlist/songplaylistitem.h"
|
2011-01-28 21:52:38 +01:00
|
|
|
#include "scripting/script.h"
|
|
|
|
#include "scripting/scriptmanager.h"
|
|
|
|
#include "scripting/python/pythonengine.h"
|
|
|
|
|
|
|
|
#include "gmock/gmock.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
#include "test_utils.h"
|
|
|
|
|
|
|
|
#include <QSettings>
|
|
|
|
#include <QtDebug>
|
|
|
|
|
|
|
|
#include <boost/noncopyable.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
class TemporaryScript : boost::noncopyable {
|
|
|
|
public:
|
2011-01-28 22:43:10 +01:00
|
|
|
TemporaryScript(const QString& code, const QString& directory_template = QString()) {
|
|
|
|
directory_ = Utilities::MakeTempDir(directory_template);
|
2011-01-28 21:52:38 +01:00
|
|
|
|
|
|
|
QSettings ini(directory_ + "/script.ini", QSettings::IniFormat);
|
|
|
|
ini.beginGroup("Script");
|
|
|
|
ini.setValue("language", "python");
|
|
|
|
ini.setValue("script_file", "script.py");
|
|
|
|
|
|
|
|
QFile script(directory_ + "/script.py");
|
|
|
|
script.open(QIODevice::WriteOnly);
|
2011-01-28 22:43:10 +01:00
|
|
|
script.write(code.toUtf8());
|
2011-01-28 21:52:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
~TemporaryScript() {
|
|
|
|
if (!directory_.isEmpty()) {
|
|
|
|
Utilities::RemoveRecursive(directory_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString directory_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class PythonTest : public ::testing::Test {
|
|
|
|
protected:
|
|
|
|
void SetUp() {
|
|
|
|
manager_ = new ScriptManager;
|
|
|
|
engine_ = qobject_cast<PythonEngine*>(
|
|
|
|
manager_->EngineForLanguage(ScriptInfo::Language_Python));
|
|
|
|
}
|
|
|
|
|
|
|
|
void TearDown() {
|
|
|
|
delete manager_;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScriptManager* manager_;
|
|
|
|
PythonEngine* engine_;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(PythonTest, HasPythonEngine) {
|
|
|
|
ASSERT_TRUE(engine_);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(PythonTest, InitFromDirectory) {
|
|
|
|
TemporaryScript script("pass");
|
|
|
|
|
|
|
|
ScriptInfo info;
|
|
|
|
info.InitFromDirectory(manager_, script.directory_);
|
|
|
|
|
|
|
|
EXPECT_TRUE(info.is_valid());
|
|
|
|
EXPECT_EQ(script.directory_, info.path());
|
|
|
|
EXPECT_EQ(ScriptInfo::Language_Python, info.language());
|
|
|
|
EXPECT_EQ(NULL, info.loaded());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(PythonTest, StdioIsRedirected) {
|
|
|
|
TemporaryScript script(
|
|
|
|
"import sys\n"
|
|
|
|
"print 'text on stdout'\n"
|
|
|
|
"print >>sys.stderr, 'text on stderr'\n");
|
|
|
|
ScriptInfo info;
|
|
|
|
info.InitFromDirectory(manager_, script.directory_);
|
|
|
|
|
|
|
|
engine_->CreateScript(info);
|
|
|
|
|
|
|
|
QString log = manager_->log_lines_plain().join("\n");
|
|
|
|
ASSERT_TRUE(log.contains("text on stdout"));
|
|
|
|
ASSERT_TRUE(log.contains("text on stderr"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(PythonTest, CleanupModuleDict) {
|
|
|
|
TemporaryScript script(
|
|
|
|
"class Foo:\n"
|
|
|
|
" def __init__(self):\n"
|
|
|
|
" print 'constructor'\n"
|
|
|
|
" def __del__(self):\n"
|
|
|
|
" print 'destructor'\n"
|
|
|
|
"f = Foo()\n");
|
|
|
|
ScriptInfo info;
|
|
|
|
info.InitFromDirectory(manager_, script.directory_);
|
|
|
|
|
|
|
|
Script* s = engine_->CreateScript(info);
|
2011-01-28 22:43:10 +01:00
|
|
|
ASSERT_TRUE(manager_->log_lines_plain().last().endsWith("constructor"));
|
2011-01-28 21:52:38 +01:00
|
|
|
|
|
|
|
engine_->DestroyScript(s);
|
2011-01-28 22:43:10 +01:00
|
|
|
ASSERT_TRUE(manager_->log_lines_plain().last().endsWith("destructor"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(PythonTest, ModuleConstants) {
|
|
|
|
TemporaryScript script(
|
|
|
|
"print __builtins__\n"
|
|
|
|
"print __file__\n"
|
|
|
|
"print __name__\n"
|
|
|
|
"print __package__\n"
|
|
|
|
"print __path__\n"
|
|
|
|
"print script\n");
|
|
|
|
ScriptInfo info;
|
|
|
|
info.InitFromDirectory(manager_, script.directory_);
|
|
|
|
|
|
|
|
engine_->CreateScript(info);
|
|
|
|
|
|
|
|
const QStringList log = manager_->log_lines_plain();
|
|
|
|
const int n = log.count();
|
|
|
|
ASSERT_GE(n, 6);
|
|
|
|
EXPECT_TRUE(log.at(n-6).endsWith("<module '__builtin__' (built-in)>")); // __builtins__
|
|
|
|
EXPECT_TRUE(log.at(n-5).endsWith(script.directory_ + "/script.py")); // __file__
|
|
|
|
EXPECT_TRUE(log.at(n-4).endsWith("clementinescripts." + info.id())); // __name__
|
|
|
|
EXPECT_TRUE(log.at(n-3).endsWith("None")); // __package__
|
|
|
|
EXPECT_TRUE(log.at(n-2).endsWith("['" + script.directory_ + "']")); // __path__
|
|
|
|
EXPECT_TRUE(log.at(n-1).contains("<clementine.ScriptInterface object at")); // script
|
2011-01-28 21:52:38 +01:00
|
|
|
}
|
|
|
|
|
2011-04-22 20:53:33 +02:00
|
|
|
TEST_F(PythonTest, SharedPointers) {
|
|
|
|
engine_->EnsureInitialised();
|
|
|
|
|
|
|
|
TemporaryScript script(
|
|
|
|
"import clementine\n"
|
|
|
|
"print clementine.item.Metadata().title()\n"
|
|
|
|
"a = clementine.item\n"
|
|
|
|
"print a.Metadata().title()\n"
|
|
|
|
"clementine.item = None\n"
|
|
|
|
"print a.Metadata().title()\n"
|
|
|
|
"a = None\n"
|
|
|
|
);
|
|
|
|
ScriptInfo info;
|
|
|
|
info.InitFromDirectory(manager_, script.directory_);
|
|
|
|
|
|
|
|
Song song;
|
|
|
|
song.set_title("title");
|
|
|
|
|
|
|
|
PlaylistItemPtr ptr(new SongPlaylistItem(song));
|
|
|
|
EXPECT_EQ(1, ptr.use_count());
|
|
|
|
|
|
|
|
engine_->AddObject(&ptr, sipType_PlaylistItemPtr, "item");
|
|
|
|
EXPECT_EQ(2, ptr.use_count());
|
|
|
|
|
|
|
|
engine_->CreateScript(info);
|
|
|
|
EXPECT_EQ(1, ptr.use_count());
|
|
|
|
|
|
|
|
const QStringList log = manager_->log_lines_plain();
|
|
|
|
const int n = log.count();
|
|
|
|
ASSERT_GE(n, 3);
|
|
|
|
EXPECT_TRUE(log.at(n-3).endsWith("title"));
|
|
|
|
EXPECT_TRUE(log.at(n-2).endsWith("title"));
|
|
|
|
EXPECT_TRUE(log.at(n-1).endsWith("title"));
|
|
|
|
}
|