merge in the new file handle approach, try it and let me know where it breaks

This commit is contained in:
John Bintz 2011-11-10 11:32:54 -05:00
commit c7ce823409
49 changed files with 815 additions and 1282 deletions

View File

@ -3,6 +3,8 @@
# watch('file/path') { `command(s)` } # watch('file/path') { `command(s)` }
# #
guard 'coffeescript', :input => 'vendor/assets/coffeescripts', :output => 'vendor/assets/javascripts'
guard 'shell' do guard 'shell' do
watch(%r{ext/jasmine-webkit-specrunner/.*\.(cpp|h|pro|pri)}) { |m| watch(%r{ext/jasmine-webkit-specrunner/.*\.(cpp|h|pro|pri)}) { |m|
if !m[0]['moc_'] if !m[0]['moc_']
@ -27,9 +29,8 @@ end
def compile def compile
#system %{cd ext/jasmine-webkit-specrunner && ruby test.rb && ruby extconf.rb} #system %{cd ext/jasmine-webkit-specrunner && ruby test.rb && ruby extconf.rb}
system %{cd ext/jasmine-webkit-specrunner && ruby test.rb && ruby extconf.rb} system %{cd ext/jasmine-webkit-specrunner && ruby extconf.rb}
end end
compile compile
guard 'coffeescript', :input => 'jasmine'

View File

@ -18,7 +18,6 @@ begin
files_list = Jasmine::FilesList.new(:config => runner.jasmine_config) files_list = Jasmine::FilesList.new(:config => runner.jasmine_config)
files_list.files.each { |file| puts file } files_list.files.each { |file| puts file }
else else
puts "Running Jasmine specs...".color(:white)
exit runner.run exit runner.run
end end
rescue CoffeeScript::CompilationError rescue CoffeeScript::CompilationError

View File

@ -1,5 +0,0 @@
#!/bin/bash
bundle exec rake
if [ $? -ne 0 ]; then exit 1; fi

View File

@ -1,6 +0,0 @@
#!/bin/bash
for i in $PWD/dev-bin/hooks/*; do
ln -sf $i .git/hooks/${i##*/}
done

View File

@ -1,149 +0,0 @@
#include "ConsoleOutput.h"
ConsoleOutput::ConsoleOutput() : QObject(),
showColors(false),
consoleLogUsed(false) {
outputIO = &std::cout;
}
void ConsoleOutput::passed(const QString &specDetail) {
green();
*outputIO << '.';
clear();
outputIO->flush();
consoleLogUsed = false;
successes.push(specDetail);
}
void ConsoleOutput::failed(const QString &specDetail) {
red();
*outputIO << 'F';
clear();
outputIO->flush();
consoleLogUsed = false;
failures.push(specDetail);
}
void ConsoleOutput::green() {
if (showColors) std::cout << "\033[0;32m";
}
void ConsoleOutput::clear() {
if (showColors) std::cout << "\033[m";
}
void ConsoleOutput::red() {
if (showColors) std::cout << "\033[0;31m";
}
void ConsoleOutput::yellow()
{
if (showColors) std::cout << "\033[0;33m";
}
void ConsoleOutput::errorLog(const QString &msg, int lineNumber, const QString &sourceID) {
red();
*outputIO << "[error] ";
clear();
*outputIO << qPrintable(sourceID) << ":" << lineNumber << " : " << qPrintable(msg);
*outputIO << std::endl;
}
void ConsoleOutput::internalLog(const QString &note, const QString &msg) {
red();
*outputIO << "[" << qPrintable(note) << "] ";
clear();
*outputIO << qPrintable(msg);
*outputIO << std::endl;
}
void ConsoleOutput::consoleLog(const QString &msg) {
if (!consoleLogUsed) {
*outputIO << std::endl;
consoleLogUsed = true;
}
green();
*outputIO << "[console] ";
if (msg.contains("\n"))
*outputIO << std::endl;
clear();
*outputIO << qPrintable(msg);
*outputIO << std::endl;
}
void ConsoleOutput::logSpecFilename(const QString &name) {
*outputIO << std::endl << std::endl;
red();
*outputIO << qPrintable(name) << std::endl;
clear();
}
void ConsoleOutput::logSpecResult(const QString &result) {
QStringList lines = result.split("\n");
QStringListIterator linesIterator(lines);
red();
while (linesIterator.hasNext()) {
QString line = linesIterator.next();
if (!linesIterator.hasNext())
yellow();
*outputIO << " " << qPrintable(line) << std::endl;
}
clear();
}
void ConsoleOutput::reportFailure(const QString &totalTests, const QString &failedTests, const QString &duration) {
red();
*outputIO << std::endl << "FAIL: ";
formatTestResults(totalTests, failedTests, duration);
*outputIO << std::endl;
clear();
}
void ConsoleOutput::reportSuccess(const QString &totalTests, const QString &failedTests, const QString &duration) {
green();
*outputIO << std::endl << "PASS: ";
formatTestResults(totalTests, failedTests, duration);
*outputIO << std::endl;
clear();
}
void ConsoleOutput::reportSuccessWithJSErrors(const QString &totalTests, const QString &failedTests, const QString &duration) {
yellow();
*outputIO << std::endl << "PASS with JS errors: ";
formatTestResults(totalTests, failedTests, duration);
*outputIO << std::endl;
clear();
}
void ConsoleOutput::formatTestResults(const QString &totalTests, const QString &failedTests, const QString &duration) {
*outputIO << qPrintable(totalTests) << " ";
if (totalTests == "1") {
*outputIO << "test";
} else {
*outputIO << "tests";
}
*outputIO << ", ";
*outputIO << qPrintable(failedTests) << " ";
if (failedTests == "1") {
*outputIO << "failure";
} else {
*outputIO << "failures";
}
*outputIO << ", ";
*outputIO << qPrintable(duration) << " ";
if (duration == "1") {
*outputIO << "sec.";
} else {
*outputIO << "secs.";
}
}

View File

@ -1,39 +0,0 @@
#ifndef JHW_CONSOLE_OUTPUT
#define JHW_CONSOLE_OUTPUT
#include <QObject>
#include <iostream>
#include <QStack>
#include <QStringList>
class ConsoleOutput : public QObject {
public:
ConsoleOutput();
void passed(const QString &specDetail);
void failed(const QString &specDetail);
void errorLog(const QString &msg, int lineNumber, const QString &sourceID);
void internalLog(const QString &note, const QString &msg);
void consoleLog(const QString &msg);
void logSpecFilename(const QString &name);
void logSpecResult(const QString &result);
void reportFailure(const QString &totalTests, const QString &failedTests, const QString &duration);
void reportSuccess(const QString &totalTests, const QString &failedTests, const QString &duration);
void reportSuccessWithJSErrors(const QString &totalTests, const QString &failedTests, const QString &duration);
std::ostream *outputIO;
QStack<QString> successes;
QStack<QString> failures;
bool showColors;
bool consoleLogUsed;
private:
void green();
void clear();
void red();
void yellow();
void formatTestResults(const QString &totalTests, const QString &failedTests, const QString &duration);
};
#endif

View File

@ -1,129 +0,0 @@
#include <QtTest/QtTest>
#include "ConsoleOutput.h"
#include "ConsoleOutput_test.h"
using namespace std;
ConsoleOutputTest::ConsoleOutputTest() : QObject() {}
void ConsoleOutputTest::testPassed() {
stringstream buffer;
ConsoleOutput output;
output.consoleLogUsed = true;
output.outputIO = &buffer;
output.passed("test");
QVERIFY(buffer.str() == ".");
QVERIFY(output.successes.size() == 1);
QVERIFY(output.failures.size() == 0);
QVERIFY(output.consoleLogUsed == false);
}
void ConsoleOutputTest::testFailed() {
stringstream buffer;
ConsoleOutput output;
output.consoleLogUsed = true;
output.outputIO = &buffer;
output.failed("test");
QVERIFY(buffer.str() == "F");
QVERIFY(output.successes.size() == 0);
QVERIFY(output.failures.size() == 1);
QVERIFY(output.consoleLogUsed == false);
}
void ConsoleOutputTest::testErrorLog() {
stringstream buffer;
ConsoleOutput output;
output.outputIO = &buffer;
output.errorLog("message", 1, "source");
QVERIFY(buffer.str() == "[error] source:1 : message\n");
}
void ConsoleOutputTest::testInternalLog() {
stringstream buffer;
ConsoleOutput output;
output.outputIO = &buffer;
output.internalLog("note", "message");
QVERIFY(buffer.str() == "[note] message\n");
}
void ConsoleOutputTest::testConsoleLog() {
stringstream buffer;
ConsoleOutput output;
output.consoleLogUsed = false;
output.outputIO = &buffer;
output.consoleLog("log");
QVERIFY(buffer.str() == "\n[console] log\n");
}
void ConsoleOutputTest::testConsoleLogUsed() {
stringstream buffer;
ConsoleOutput output;
output.consoleLogUsed = true;
output.outputIO = &buffer;
output.consoleLog("log");
QVERIFY(buffer.str() == "[console] log\n");
}
void ConsoleOutputTest::testLogSpecFilename() {
stringstream buffer;
ConsoleOutput output;
output.outputIO = &buffer;
output.logSpecFilename("whatever");
QVERIFY(buffer.str() == "\n\nwhatever\n");
}
void ConsoleOutputTest::testLogSpecResult() {
stringstream buffer;
ConsoleOutput output;
output.outputIO = &buffer;
output.logSpecResult("whatever");
QVERIFY(buffer.str() == " whatever\n");
}
void ConsoleOutputTest::testReportResultsFailedSingular() {
stringstream buffer;
ConsoleOutput output;
output.outputIO = &buffer;
output.reportFailure("1", "1", "1");
QVERIFY(buffer.str() == "\nFAIL: 1 test, 1 failure, 1 sec.\n");
}
void ConsoleOutputTest::testReportResultsFailedPlural() {
stringstream buffer;
ConsoleOutput output;
output.outputIO = &buffer;
output.reportFailure("2", "2", "2");
QVERIFY(buffer.str() == "\nFAIL: 2 tests, 2 failures, 2 secs.\n");
}
void ConsoleOutputTest::testReportResultsSucceeded() {
stringstream buffer;
ConsoleOutput output;
output.outputIO = &buffer;
output.reportSuccess("2", "2", "2");
QVERIFY(buffer.str() == "\nPASS: 2 tests, 2 failures, 2 secs.\n");
}
void ConsoleOutputTest::testReportResultsSucceededWithJSErrors() {
stringstream buffer;
ConsoleOutput output;
output.outputIO = &buffer;
output.reportSuccessWithJSErrors("2", "2", "2");
QVERIFY(buffer.str() == "\nPASS with JS errors: 2 tests, 2 failures, 2 secs.\n");
}
QTEST_MAIN(ConsoleOutputTest);

View File

@ -1,32 +0,0 @@
#ifndef JHW_TEST_CONSOLE_OUTPUT
#define JHW_TEST_CONSOLE_OUTPUT
#include <QtTest/QtTest>
#include <iostream>
#include <sstream>
#include <string>
#include "ConsoleOutput.h"
class ConsoleOutputTest : public QObject {
Q_OBJECT
public:
ConsoleOutputTest();
private slots:
void testPassed();
void testFailed();
void testErrorLog();
void testInternalLog();
void testConsoleLog();
void testConsoleLogUsed();
void testLogSpecFilename();
void testLogSpecResult();
void testReportResultsFailedSingular();
void testReportResultsFailedPlural();
void testReportResultsSucceeded();
void testReportResultsSucceededWithJSErrors();
};
#endif

View File

@ -1,7 +0,0 @@
include(common.pri)
include(test.pri)
SOURCES += ConsoleOutput_test.cpp
HEADERS += ConsoleOutput_test.h

View File

@ -4,26 +4,13 @@
#include "Page.h" #include "Page.h"
Page::Page() : QWebPage(), confirmResult(true) {} Page::Page() : QWebPage() {}
void Page::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID) { void Page::javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID) {
emit consoleLog(message, lineNumber, sourceID); emit handleError(message, lineNumber, sourceID);
} }
bool Page::javaScriptConfirm(QWebFrame*, const QString&) { void Page::javaScriptAlert(QWebFrame *, const QString &) {}
if (confirmResult) { bool Page::javaScriptConfirm(QWebFrame *, const QString &) {
emit internalLog("TODO", "jasmine-headless-webkit can't handle confirm() yet! You should mock window.confirm for now. Returning true.");
return true;
} else {
confirmResult = true;
return false; return false;
} }
}
void Page::javaScriptAlert(QWebFrame*, const QString &msg) {
emit internalLog("alert", msg);
}
void Page::oneFalseConfirm() {
confirmResult = false;
}

View File

@ -4,20 +4,16 @@
#include <QtGui> #include <QtGui>
#include <QtWebKit> #include <QtWebKit>
class Page: public QWebPage { class Page: public QWebPage {
Q_OBJECT Q_OBJECT
public: public:
Page(); Page();
void oneFalseConfirm();
signals:
void consoleLog(const QString &msg, int lineNumber, const QString &sourceID);
void internalLog(const QString &note, const QString &msg);
protected: protected:
void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID); void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID);
bool javaScriptConfirm(QWebFrame *frame, const QString &msg); void javaScriptAlert(QWebFrame *, const QString &);
void javaScriptAlert(QWebFrame *frame, const QString &msg); bool javaScriptConfirm(QWebFrame *, const QString &);
private: signals:
bool confirmResult; void handleError(const QString & message, int lineNumber, const QString & sourceID);
}; };
#endif #endif

View File

@ -1,43 +0,0 @@
#include <QtTest/QtTest>
#include "Page.h"
#include "Page_test.h"
PageTest::PageTest() : QObject(), internalLogCalled(false) {
}
void PageTest::internalLog(const QString &, const QString &) {
internalLogCalled = true;
}
void PageTest::consoleLog(const QString &, int, const QString &) {
consoleLogCalled = true;
}
void PageTest::testJavaScriptConfirmWithLog() {
connect(&page, SIGNAL(internalLog(QString, QString)), this, SLOT(internalLog(QString, QString)));
internalLogCalled = false;
page.mainFrame()->setHtml("<script>confirm('test')</script>");
QVERIFY(internalLogCalled);
}
void PageTest::testJavaScriptConfirmWithoutLog() {
connect(&page, SIGNAL(internalLog(QString, QString)), this, SLOT(internalLog(QString, QString)));
internalLogCalled = false;
page.oneFalseConfirm();
page.mainFrame()->setHtml("<script>confirm('test')</script>");
QVERIFY(!internalLogCalled);
}
void PageTest::testJavaScriptConsoleMessage() {
connect(&page, SIGNAL(consoleLog(QString, int, QString)), this, SLOT(consoleLog(QString, int, QString)));
consoleLogCalled = false;
page.mainFrame()->setHtml("<script>cats();</script>");
QVERIFY(consoleLogCalled);
}
QTEST_MAIN(PageTest);

View File

@ -1,27 +0,0 @@
#ifndef JHW_TEST_PAGE
#define JHW_TEST_PAGE
#include <QtTest/QtTest>
#include "Page.h"
class PageTest : public QObject {
Q_OBJECT
public:
PageTest();
private:
bool internalLogCalled;
bool consoleLogCalled;
Page page;
private slots:
void internalLog(const QString &note, const QString &msg);
void consoleLog(const QString &message, int lineNumber, const QString &source);
void testJavaScriptConfirmWithLog();
void testJavaScriptConfirmWithoutLog();
void testJavaScriptConsoleMessage();
};
#endif

View File

@ -1,6 +0,0 @@
include(common.pri)
include(test.pri)
SOURCES += Page_test.cpp
HEADERS += Page_test.h

View File

@ -1,54 +0,0 @@
#include "ReportFileOutput.h"
using namespace std;
ReportFileOutput::ReportFileOutput() : QObject() {
reset();
}
void ReportFileOutput::reset() {
buffer = new stringstream();
outputIO = buffer;
}
void ReportFileOutput::passed(const QString &specDetail) {
*outputIO << "PASS||" << qPrintable(specDetail) << std::endl;
successes.push(specDetail);
}
void ReportFileOutput::failed(const QString &specDetail) {
*outputIO << "FAIL||" << qPrintable(specDetail) << std::endl;
failures.push(specDetail);
}
void ReportFileOutput::errorLog(const QString &msg, int lineNumber, const QString &sourceID) {
*outputIO << "ERROR||" << qPrintable(msg) << "||" << qPrintable(sourceID) << ":" << lineNumber << std::endl;
}
void ReportFileOutput::consoleLog(const QString &msg) {
*outputIO << "CONSOLE||" << qPrintable(msg) << std::endl;
}
void ReportFileOutput::internalLog(const QString &, const QString &) {}
void ReportFileOutput::logSpecFilename(const QString &) {}
void ReportFileOutput::logSpecResult(const QString &) {}
void ReportFileOutput::reportFailure(const QString &totalTests, const QString &failedTests, const QString &duration) {
reportTotals(totalTests, failedTests, duration, false);
}
void ReportFileOutput::reportSuccess(const QString &totalTests, const QString &failedTests, const QString &duration) {
reportTotals(totalTests, failedTests, duration, false);
}
void ReportFileOutput::reportSuccessWithJSErrors(const QString &totalTests, const QString &failedTests, const QString &duration) {
reportTotals(totalTests, failedTests, duration, true);
}
void ReportFileOutput::reportTotals(const QString &totalTests, const QString &failedTests, const QString &duration, bool hasJavaScriptError) {
*outputIO << "TOTAL||" << qPrintable(totalTests) << "||" << qPrintable(failedTests) << "||" << qPrintable(duration) << "||";
*outputIO << (hasJavaScriptError ? "T" : "F");
*outputIO << std::endl;
}

View File

@ -1,37 +0,0 @@
#ifndef JHW_REPORT_FILE_OUTPUT
#define JHW_REPORT_FILE_OUTPUT
#include <QObject>
#include <iostream>
#include <QStack>
#include <sstream>
using namespace std;
class ReportFileOutput : public QObject {
public:
ReportFileOutput();
void passed(const QString &specDetail);
void failed(const QString &specDetail);
void errorLog(const QString &msg, int lineNumber, const QString &sourceID);
void internalLog(const QString &note, const QString &msg);
void consoleLog(const QString &msg);
void logSpecFilename(const QString &name);
void logSpecResult(const QString &result);
void reportFailure(const QString &totalTests, const QString &failedTests, const QString &duration);
void reportSuccess(const QString &totalTests, const QString &failedTests, const QString &duration);
void reportSuccessWithJSErrors(const QString &totalTests, const QString &failedTests, const QString &duration);
void reset();
stringstream *buffer;
stringstream *outputIO;
QStack<QString> successes;
QStack<QString> failures;
private:
void reportTotals(const QString &totalTests, const QString &failedTests, const QString &duration, bool hasJavaScriptError);
};
#endif

View File

@ -1,88 +0,0 @@
#include <QtTest/QtTest>
#include "ReportFileOutput.h"
#include "ReportFileOutput_test.h"
using namespace std;
ReportFileOutputTest::ReportFileOutputTest() : QObject() {}
void ReportFileOutputTest::testPassed() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.passed("test||done||file.js:23");
QVERIFY(buffer.str() == "PASS||test||done||file.js:23\n");
QVERIFY(output.successes.size() == 1);
QVERIFY(output.failures.size() == 0);
}
void ReportFileOutputTest::testFailed() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.failed("test||done||file.js:23");
QVERIFY(buffer.str() == "FAIL||test||done||file.js:23\n");
QVERIFY(output.successes.size() == 0);
QVERIFY(output.failures.size() == 1);
}
void ReportFileOutputTest::testErrorLog() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.errorLog("JS Error", 23, "file.js");
QVERIFY(buffer.str() == "ERROR||JS Error||file.js:23\n");
}
void ReportFileOutputTest::testConsoleLog() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.consoleLog("Console");
QVERIFY(buffer.str() == "CONSOLE||Console\n");
}
void ReportFileOutputTest::testStubMethods() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.internalLog("Internal", "Log");
output.logSpecFilename("Filename");
output.logSpecResult("REsult");
}
void ReportFileOutputTest::testReportFailure() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.reportFailure("5", "2", "1.5");
QVERIFY(buffer.str() == "TOTAL||5||2||1.5||F\n");
}
void ReportFileOutputTest::testReportSuccess() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.reportSuccess("5", "0", "1.5");
QVERIFY(buffer.str() == "TOTAL||5||0||1.5||F\n");
}
void ReportFileOutputTest::testReportSuccessWithJSErrors() {
stringstream buffer;
ReportFileOutput output;
output.outputIO = &buffer;
output.reportSuccessWithJSErrors("5", "0", "1.5");
QVERIFY(buffer.str() == "TOTAL||5||0||1.5||T\n");
}
QTEST_MAIN(ReportFileOutputTest);

View File

@ -1,26 +0,0 @@
#ifndef JHW_TEST_REPORT_FILE_OUTPUT
#define JHW_TEST_REPORT_FILE_OUTPUT
#include <QtTest/QtTest>
#include <iostream>
#include <sstream>
#include <string>
#include "ReportFileOutput.h"
class ReportFileOutputTest : public QObject {
Q_OBJECT
public:
ReportFileOutputTest();
private slots:
void testPassed();
void testFailed();
void testErrorLog();
void testConsoleLog();
void testStubMethods();
void testReportFailure();
void testReportSuccess();
void testReportSuccessWithJSErrors();
};
#endif

View File

@ -1,7 +0,0 @@
include(common.pri)
include(test.pri)
SOURCES += ReportFileOutput_test.cpp
HEADERS += ReportFileOutput_test.h

View File

@ -3,181 +3,153 @@
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
#include <iostream> #include <iostream>
#include <sstream>
#include <QQueue> #include <QQueue>
#include "Runner.h" #include "Runner.h"
#include "Page.h"
using namespace std; using namespace std;
Runner::Runner() : QObject() Runner::Runner() : QObject()
, m_runs(0) , runs(0)
, hasErrors(false) , hasErrors(false)
, _hasSpecFailure(false)
, usedConsole(false) , usedConsole(false)
, isFinished(false) , isFinished(false)
, didFail(false) , useColors(false)
{ {
m_page.settings()->enablePersistentStorage(); page.settings()->enablePersistentStorage();
m_ticker.setInterval(TIMER_TICK); ticker.setInterval(TIMER_TICK);
connect(&m_ticker, SIGNAL(timeout()), this, SLOT(timerEvent())); connect(&ticker, SIGNAL(timeout()), this, SLOT(timerEvent()));
connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(watch(bool))); connect(&page, SIGNAL(loadFinished(bool)), this, SLOT(watch(bool)));
connect(&m_page, SIGNAL(consoleLog(QString, int, QString)), this, SLOT(errorLog(QString, int, QString))); connect(&page, SIGNAL(handleError(const QString &, int, const QString &)), this, SLOT(handleError(const QString &, int, const QString &)));
connect(&m_page, SIGNAL(internalLog(QString, QString)), this, SLOT(internalLog(QString, QString))); connect(page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(addJHW()));
connect(m_page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(addJHW()));
} }
void Runner::addFile(const QString &spec) { void Runner::addFile(const QString &spec) {
runnerFiles.enqueue(spec); runnerFiles.enqueue(spec);
} }
void Runner::go() void Runner::go() {
{ ticker.stop();
m_ticker.stop(); page.setPreferredContentsSize(QSize(1024, 600));
m_page.setPreferredContentsSize(QSize(1024, 600));
addJHW(); addJHW();
loadSpec();
m_ticker.start(); loadSpec();
} }
void Runner::addJHW() void Runner::addJHW() {
{ page.mainFrame()->addToJavaScriptWindowObject("JHW", this);
m_page.mainFrame()->addToJavaScriptWindowObject("JHW", this); }
void Runner::handleError(const QString &message, int lineNumber, const QString &sourceID) {
QString messageEscaped = QString(message);
QString sourceIDEscaped = QString(sourceID);
messageEscaped.replace(QString("\""), QString("\\\""));
sourceIDEscaped.replace(QString("\""), QString("\\\""));
std::stringstream ss;
ss << lineNumber;
QString command("JHW._handleError(\"" + messageEscaped + "\", " + QString(ss.str().c_str()) + ", \"" + sourceIDEscaped + "\"); false;");
page.mainFrame()->evaluateJavaScript(command);
hasErrors = true;
} }
void Runner::loadSpec() void Runner::loadSpec()
{ {
m_page.mainFrame()->load(runnerFiles.dequeue()); if (reportFileName.isEmpty()) {
m_ticker.start(); outputFile = 0;
ts = 0;
} else {
outputFile = new QFile(reportFileName);
outputFile->open(QIODevice::WriteOnly);
ts = new QTextStream(outputFile);
}
page.mainFrame()->load(runnerFiles.dequeue());
ticker.start();
} }
void Runner::watch(bool ok) void Runner::watch(bool ok) {
{
if (!ok) { if (!ok) {
std::cerr << "Can't load " << qPrintable(m_page.mainFrame()->url().toString()) << ", the file may be broken." << std::endl; std::cerr << "Can't load " << qPrintable(page.mainFrame()->url().toString()) << ", the file may be broken." << std::endl;
std::cerr << "Out of curiosity, did your tests try to submit a form and you haven't prevented that?" << std::endl; std::cerr << "Out of curiosity, did your tests try to submit a form and you haven't prevented that?" << std::endl;
std::cerr << "Try running your tests in your browser with the Jasmine server and see what happens." << std::endl; std::cerr << "Try running your tests in your browser with the Jasmine server and see what happens." << std::endl;
QApplication::instance()->exit(1); QApplication::instance()->exit(1);
return; return;
} }
} page.mainFrame()->evaluateJavaScript(QString("JHW._setColors(") + (useColors ? QString("true") : QString("false")) + QString("); false;"));
bool Runner::hasElement(const char *select)
{
return !m_page.mainFrame()->findFirstElement(select).isNull();
} }
void Runner::setColors(bool colors) { void Runner::setColors(bool colors) {
consoleOutput.showColors = colors; useColors = colors;
}
void Runner::hasUsedConsole() {
usedConsole = true;
}
void Runner::hasError() {
hasErrors = true;
}
void Runner::hasSpecFailure() {
_hasSpecFailure = true;
} }
void Runner::reportFile(const QString &file) { void Runner::reportFile(const QString &file) {
reportFileName = file; reportFileName = file;
} }
bool Runner::hasError() {
return hasErrors;
}
void Runner::timerPause() { void Runner::timerPause() {
m_ticker.stop(); ticker.stop();
} }
void Runner::timerDone() { void Runner::timerDone() {
m_ticker.start(); ticker.start();
} }
void Runner::specPassed(const QString &specDetail) { void Runner::print(const QString &fh, const QString &content) {
consoleOutput.passed(specDetail); if (fh == "stdout") {
reportFileOutput.passed(specDetail); std::cout << qPrintable(content);
} std::cout.flush();
void Runner::specFailed(const QString &specDetail) {
consoleOutput.failed(specDetail);
reportFileOutput.failed(specDetail);
didFail = true;
failedSpecs.push(specDetail);
}
void Runner::errorLog(const QString &msg, int lineNumber, const QString &sourceID)
{
consoleOutput.errorLog(msg, lineNumber, sourceID);
reportFileOutput.errorLog(msg, lineNumber, sourceID);
hasErrors = true;
m_runs = 0;
m_ticker.start();
}
void Runner::internalLog(const QString &note, const QString &msg) {
consoleOutput.internalLog(note, msg);
reportFileOutput.internalLog(note, msg);
}
void Runner::log(const QString &msg)
{
usedConsole = true;
consoleOutput.consoleLog(msg);
reportFileOutput.consoleLog(msg);
}
void Runner::leavePageAttempt(const QString &msg)
{
consoleOutput.internalLog("error", msg);
m_page.oneFalseConfirm();
hasErrors = true;
}
void Runner::printName(const QString &name)
{
consoleOutput.logSpecFilename(name);
}
void Runner::printResult(const QString &result)
{
consoleOutput.logSpecResult(result);
}
void Runner::finishSuite(const QString &duration, const QString &total, const QString& failed)
{
if (didFail) {
consoleOutput.reportFailure(total, failed, duration);
reportFileOutput.reportFailure(total, failed, duration);
} else {
if (hasErrors) {
consoleOutput.reportSuccessWithJSErrors(total, failed, duration);
reportFileOutput.reportSuccessWithJSErrors(total, failed, duration);
} else {
consoleOutput.reportSuccess(total, failed, duration);
reportFileOutput.reportSuccess(total, failed, duration);
}
} }
if (!reportFileName.isEmpty()) { if (fh == "stderr") {
QFile outputFile(reportFileName); std::cerr << qPrintable(content);
outputFile.open(QIODevice::WriteOnly); std::cerr.flush();
QTextStream ts(&outputFile);
ts << reportFileOutput.outputIO->str().c_str();
outputFile.close();
} }
if (fh == "report" && outputFile) {
*ts << qPrintable(content);
ts->flush();
}
}
void Runner::finishSuite() {
isFinished = true; isFinished = true;
} }
void Runner::timerEvent() void Runner::timerEvent() {
{ ++runs;
++m_runs;
if (hasErrors && m_runs > 2) if (hasErrors && runs > 2)
QApplication::instance()->exit(1); QApplication::instance()->exit(1);
if (isFinished) { if (isFinished) {
if (outputFile) {
outputFile->close();
}
int exitCode = 0; int exitCode = 0;
if (didFail || hasErrors) { if (_hasSpecFailure || hasErrors) {
exitCode = 1; exitCode = 1;
} else { } else {
if (usedConsole) { if (usedConsole) {
@ -203,8 +175,8 @@ void Runner::timerEvent()
} }
} }
if (m_runs > MAX_LOOPS) { if (runs > MAX_LOOPS) {
std::cout << "WARNING: too many runs and the test is still not finished!" << std::endl; std::cerr << "WARNING: too many runs and the test is still not finished!" << std::endl;
QApplication::instance()->exit(1); QApplication::instance()->exit(1);
} }
} }

View File

@ -10,57 +10,53 @@
#include <QQueue> #include <QQueue>
#include "Page.h" #include "Page.h"
#include "ConsoleOutput.h"
#include "ReportFileOutput.h"
using namespace std; using namespace std;
class Runner: public QObject { class Runner: public QObject {
Q_OBJECT Q_OBJECT
public: public:
enum { TIMER_TICK = 200, MAX_LOOPS = 25 }; enum { TIMER_TICK = 200, MAX_LOOPS = 50 };
Runner(); Runner();
void setColors(bool colors); void setColors(bool colors);
void reportFile(const QString &file); void reportFile(const QString &file);
void addFile(const QString &spec); void addFile(const QString &spec);
void go(); void go();
public slots: public slots:
void log(const QString &msg);
bool hasError();
void leavePageAttempt(const QString &msg);
void timerPause(); void timerPause();
void timerDone(); void timerDone();
void specPassed(const QString &specDetail); void hasUsedConsole();
void specFailed(const QString &specDetail); void hasError();
void printName(const QString &name); void hasSpecFailure();
void printResult(const QString &result); void print(const QString &fh, const QString &content);
void finishSuite(const QString &duration, const QString &total, const QString& failed); void finishSuite();
private slots: private slots:
void watch(bool ok); void watch(bool ok);
void errorLog(const QString &msg, int lineNumber, const QString &sourceID);
void internalLog(const QString &note, const QString &msg);
void addJHW(); void addJHW();
void timerEvent(); void timerEvent();
protected: void handleError(const QString & message, int lineNumber, const QString & sourceID);
bool hasElement(const char *select);
private: private:
Page m_page; Page page;
QTimer m_ticker; QTimer ticker;
int m_runs; int runs;
bool hasErrors; bool hasErrors;
bool _hasSpecFailure;
bool usedConsole; bool usedConsole;
bool isFinished; bool isFinished;
bool didFail; bool useColors;
QQueue<QString> runnerFiles;
QStack<QString> failedSpecs;
ConsoleOutput consoleOutput; QQueue<QString> runnerFiles;
ReportFileOutput reportFileOutput;
QString reportFileName; QString reportFileName;
void loadSpec(); void loadSpec();
QFile *outputFile;
QTextStream *ts;
}; };
#endif #endif

View File

@ -4,6 +4,6 @@ QMAKE_INFO_PLIST = Info.plist
QMAKESPEC = macx-g++ QMAKESPEC = macx-g++
QT += network webkit QT += network webkit
SOURCES = Page.cpp Runner.cpp ConsoleOutput.cpp ReportFileOutput.cpp SOURCES = Page.cpp Runner.cpp
HEADERS = Page.h Runner.h ConsoleOutput.h ReportFileOutput.h HEADERS = Page.h Runner.h

View File

@ -21,7 +21,6 @@
THE SOFTWARE. THE SOFTWARE.
*/ */
#include "Page.h"
#include "Runner.h" #include "Runner.h"
#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) #if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)

View File

@ -2,3 +2,4 @@ include(common.pri)
SOURCES += specrunner.cpp SOURCES += specrunner.cpp
TARGET = jasmine-webkit-specrunner TARGET = jasmine-webkit-specrunner

View File

@ -1,3 +0,0 @@
TARGET = jhw-test
QT += testlib

View File

@ -1,31 +0,0 @@
#!/usr/bin/env ruby
require 'fileutils'
system %{make clean}
$: << File.expand_path("../../../lib", __FILE__)
require 'qt/qmake'
result = 0
Dir['*_test.pro'].each do |test|
FileUtils.rm_f('jhw-test')
Qt::Qmake.make!('jasmine-headless-webkit', test)
if File.file?('jhw-test')
system %{./jhw-test}
if $?.exitstatus != 0
result = 1
break
end
else
result = 1
break
end
end
Qt::Qmake.make!('jasmine-headless-webkit', 'specrunner.pro')
exit result

View File

@ -1,231 +0,0 @@
(function() {
var getSplitName, pauseAndRun;
if (!(typeof jasmine !== "undefined" && jasmine !== null)) {
throw new Error("jasmine not laoded!");
}
if (window.JHW) {
getSplitName = function(parts) {
parts.push(String(this.description).replace(/[\n\r]/g, ' '));
return parts;
};
jasmine.Suite.prototype.getSuiteSplitName = function() {
return this.getSplitName(this.parentSuite ? this.parentSuite.getSuiteSplitName() : []);
};
jasmine.Spec.prototype.getSpecSplitName = function() {
return this.getSplitName(this.suite.getSuiteSplitName());
};
jasmine.Suite.prototype.getSplitName = getSplitName;
jasmine.Spec.prototype.getSplitName = getSplitName;
jasmine.Spec.prototype.getJHWSpecInformation = function() {
var parts, specLineInfo;
parts = this.getSpecSplitName();
specLineInfo = HeadlessReporterResult.findSpecLine(parts);
if (specLineInfo.file) {
parts.push("" + specLineInfo.file + ":" + specLineInfo.lineNumber);
} else {
parts.push('');
}
return parts.join("||");
};
jasmine.Spec.prototype.fail = function(e) {
var expectationResult, filename, realFilename;
if (e && e.sourceURL && window.CoffeeScriptToFilename) {
filename = e.sourceURL.split('/').pop();
if (realFilename = window.CoffeeScriptToFilename[filename]) {
e = {
name: e.name,
message: e.message,
lineNumber: "~" + String(e.line),
sourceURL: realFilename
};
}
}
expectationResult = new jasmine.ExpectationResult({
passed: false,
message: e ? jasmine.util.formatException(e) : 'Exception',
trace: {
stack: e.stack
}
});
return this.results_.addResult(expectationResult);
};
jasmine.NestedResults.isValidSpecLine = function(line) {
return line.match(/^\s*expect/) !== null || line.match(/^\s*return\s*expect/) !== null;
};
jasmine.NestedResults.parseFunction = function(func) {
var line, lineCount, lines, _i, _len, _ref;
lines = [];
lineCount = 0;
_ref = func.split("\n");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
if (jasmine.NestedResults.isValidSpecLine(line)) {
line = line.replace(/^\s*/, '').replace(/\s*$/, '').replace(/^return\s*/, '');
lines.push([line, lineCount]);
}
lineCount += 1;
}
return lines;
};
jasmine.NestedResults.parseAndStore = function(func) {
if (!jasmine.NestedResults.ParsedFunctions[func]) {
jasmine.NestedResults.ParsedFunctions[func] = jasmine.NestedResults.parseFunction(func);
}
return jasmine.NestedResults.ParsedFunctions[func];
};
jasmine.NestedResults.ParsedFunctions = [];
if (!jasmine.WaitsBlock.prototype._execute) {
jasmine.WaitsBlock.prototype._execute = jasmine.WaitsBlock.prototype.execute;
jasmine.WaitsForBlock.prototype._execute = jasmine.WaitsForBlock.prototype.execute;
pauseAndRun = function(onComplete) {
JHW.timerPause();
return this._execute(function() {
JHW.timerDone();
return onComplete();
});
};
jasmine.WaitsBlock.prototype.execute = pauseAndRun;
jasmine.WaitsForBlock.prototype.execute = pauseAndRun;
jasmine.NestedResults.prototype.addResult_ = jasmine.NestedResults.prototype.addResult;
jasmine.NestedResults.prototype.addResult = function(result) {
result.expectations = [];
result.expectations = jasmine.NestedResults.parseAndStore(arguments.callee.caller.caller.caller.toString());
return this.addResult_(result);
};
}
window.HeadlessReporterResult = (function() {
function HeadlessReporterResult(name, splitName) {
this.name = name;
this.splitName = splitName;
this.results = [];
}
HeadlessReporterResult.prototype.addResult = function(message) {
return this.results.push(message);
};
HeadlessReporterResult.prototype.print = function() {
var bestChoice, output, result, _i, _len, _ref, _results;
output = this.name;
bestChoice = HeadlessReporterResult.findSpecLine(this.splitName);
if (bestChoice.file) {
output += " (" + bestChoice.file + ":" + bestChoice.lineNumber + ")";
}
JHW.printName(output);
_ref = this.results;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
result = _ref[_i];
output = result.message;
if (result.lineNumber) {
output += " (line ~" + (bestChoice.lineNumber + result.lineNumber) + ")\n " + result.line;
}
_results.push(JHW.printResult(output));
}
return _results;
};
HeadlessReporterResult.findSpecLine = function(splitName) {
var bestChoice, file, index, lastLine, line, lineNumber, lines, newLineNumberInfo, _i, _len, _ref;
bestChoice = {
accuracy: 0,
file: null,
lineNumber: null
};
_ref = HeadlessReporterResult.specLineNumbers;
for (file in _ref) {
lines = _ref[file];
index = 0;
lineNumber = 0;
while (newLineNumberInfo = lines[splitName[index]]) {
if (newLineNumberInfo.length === 0) {
lineNumber = newLineNumberInfo[0];
} else {
lastLine = null;
for (_i = 0, _len = newLineNumberInfo.length; _i < _len; _i++) {
line = newLineNumberInfo[_i];
lastLine = line;
if (line > lineNumber) {
break;
}
}
lineNumber = lastLine;
}
index++;
}
if (index > bestChoice.accuracy) {
bestChoice = {
accuracy: index,
file: file,
lineNumber: lineNumber
};
}
}
return bestChoice;
};
return HeadlessReporterResult;
})();
jasmine.HeadlessReporter = (function() {
function HeadlessReporter(callback) {
this.callback = callback != null ? callback : null;
this.results = [];
this.failedCount = 0;
this.length = 0;
}
HeadlessReporter.prototype.reportRunnerResults = function(runner) {
var result, _i, _len, _ref;
if (this.hasError()) {
return;
}
_ref = this.results;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
result = _ref[_i];
result.print();
}
if (this.callback) {
this.callback();
}
return JHW.finishSuite((new Date() - this.startTime) / 1000.0, this.length, this.failedCount);
};
HeadlessReporter.prototype.reportRunnerStarting = function(runner) {
return this.startTime = new Date();
};
HeadlessReporter.prototype.reportSpecResults = function(spec) {
var failureResult, foundLine, result, results, testCount, _i, _len, _ref;
if (this.hasError()) {
return;
}
results = spec.results();
this.length++;
if (results.passed()) {
return JHW.specPassed(spec.getJHWSpecInformation());
} else {
JHW.specFailed(spec.getJHWSpecInformation());
this.failedCount++;
failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName());
testCount = 1;
_ref = results.getItems();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
result = _ref[_i];
if (result.type === 'expect' && !result.passed_) {
if (foundLine = result.expectations[testCount - 1]) {
result.line = foundLine[0], result.lineNumber = foundLine[1];
}
failureResult.addResult(result);
}
testCount += 1;
}
return this.results.push(failureResult);
}
};
HeadlessReporter.prototype.reportSpecStarting = function(spec) {
if (this.hasError()) {
spec.finish();
return spec.suite.finish();
}
};
HeadlessReporter.prototype.reportSuiteResults = function(suite) {};
HeadlessReporter.prototype.hasError = function() {
return JHW.hasError();
};
return HeadlessReporter;
})();
}
}).call(this);

View File

@ -6,14 +6,30 @@ module Jasmine
class FilesList class FilesList
attr_reader :files, :spec_files, :filtered_files, :spec_outside_scope attr_reader :files, :spec_files, :filtered_files, :spec_outside_scope
class << self
def find_vendored_asset_paths(*names)
require 'rubygems'
raise StandardError.new("A newer version of Rubygems is required to use vendored assets. Please upgrade.") if !Gem::Specification.respond_to?(:map)
all_spec_files.find_all do |file|
names.any? { |name| file["/#{name}.js"] }
end
end
def all_spec_files
@all_spec_files ||= Gem::Specification.map { |spec| spec.files.find_all { |file|
file["vendor/assets/javascripts"]
}.compact.collect { |file| File.join(spec.gem_dir, file) } }.flatten
end
end
DEFAULT_FILES = [ DEFAULT_FILES = [
File.join(Jasmine::Core.path, "jasmine.js"), File.join(Jasmine::Core.path, "jasmine.js"),
File.join(Jasmine::Core.path, "jasmine-html.js"), File.join(Jasmine::Core.path, "jasmine-html.js"),
File.join(Jasmine::Core.path, "jasmine.css"), File.join(Jasmine::Core.path, "jasmine.css")
Jasmine::Headless.root.join('jasmine/jasmine.headless-reporter.js').to_s, ] + %w{jasmine-extensions intense headless_reporter_result jasmine.HeadlessConsoleReporter jsDump beautify-html}.collect { |name|
Jasmine::Headless.root.join('js-lib/jsDump.js').to_s, Jasmine::Headless.root.join("vendor/assets/javascripts/#{name}.js").to_s
Jasmine::Headless.root.join('js-lib/beautify-html.js').to_s }
]
PLEASE_WAIT_IM_WORKING_TIME = 2 PLEASE_WAIT_IM_WORKING_TIME = 2
@ -72,13 +88,10 @@ module Jasmine
cache = Jasmine::Headless::CoffeeScriptCache.new(file) cache = Jasmine::Headless::CoffeeScriptCache.new(file)
source = cache.handle source = cache.handle
if cache.cached? if cache.cached?
%{ %{<script type="text/javascript" src="#{cache.cache_file}"></script>
<script type="text/javascript" src="#{cache.cache_file}"></script>S
<script type="text/javascript"> <script type="text/javascript">
window.CoffeeScriptToFilename = window.CoffeeScriptToFilename || {}; window.CSTF['#{File.split(cache.cache_file).last}'] = '#{file}';
window.CoffeeScriptToFilename['#{File.split(cache.cache_file).last}'] = '#{file}'; </script>}
</script>
}
else else
%{<script type="text/javascript">#{source}</script>} %{<script type="text/javascript">#{source}</script>}
end end
@ -158,19 +171,6 @@ module Jasmine
def expanded_dir(path) def expanded_dir(path)
Dir[path].collect { |file| File.expand_path(file) } Dir[path].collect { |file| File.expand_path(file) }
end end
def self.find_vendored_asset_path(name)
require 'rubygems'
raise StandardError.new("A newer version of Rubygems is required to use vendored assets. Please upgrade.") if !Gem::Specification.respond_to?(:map)
all_spec_files.find_all { |file| file["vendor/assets/javascripts/#{name}.js"] }
end
def self.all_spec_files
@all_spec_files ||= Gem::Specification.map { |spec| spec.files.find_all { |file|
file["vendor/assets/javascripts"]
}.compact.collect { |file| File.join(spec.gem_dir, file) } }.flatten
end
end end
end end

View File

@ -16,7 +16,7 @@ module Jasmine::Headless
class << self class << self
def root def root
@root ||= Pathname.new(File.expand_path('../../..', __FILE__)) @root ||= Pathname(File.expand_path('../../..', __FILE__))
end end
end end
end end

View File

@ -1,5 +1,5 @@
module Jasmine module Jasmine
module Headless module Headless
VERSION = "0.7.3.1" VERSION = "0.8.0"
end end
end end

View File

@ -39,11 +39,7 @@ module Qt
system command(project_file) system command(project_file)
system %{make #{make_options}} system %{make}
end
def make_options
""
end end
# #

View File

@ -3,47 +3,7 @@
<head> <head>
<meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/> <meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
<title>Jasmine Test Runner - Generated by jasmine-headless-webkit</title> <title>Jasmine Test Runner - Generated by jasmine-headless-webkit</title>
<script type="text/javascript"> <script type="text/javascript" src="<%= Jasmine::Headless.root.join('vendor/assets/javascripts/prolog.js') %>"></script>
if (window.JHW) {
window.console = { log: function(data) {
if (typeof(jQuery) !== 'undefined' && data instanceof jQuery) {
JHW.log(style_html($("<div />").append(data).html(), { indent_size: 2 }));
} else {
var usejsDump = true;
try {
if (typeof data.toJSON == 'function') {
JHW.log("JSON: " + JSON.stringify(data, null, 2));
usejsDump = false;
}
} catch (e) {}
if (usejsDump) {
var dump = jsDump.doParse(data);
if (dump.indexOf("\\n") == -1) {
JHW.log(dump);
} else {
JHW.log("jsDump: " + dump);
}
}
}
}, pp: function(data) {
JHW.log(jasmine ? jasmine.pp(data) : JSON.stringify(data));
}, peek: function(data) {
console.log(data);
return data;
} };
window.onbeforeunload = function(e) {
JHW.leavePageAttempt('The code tried to leave the test page. Check for unhandled form submits and link clicks.');
if (e = e || window.event) {
e.returnValue = "leaving";
}
return "leaving";
};
}
</script>
<%= files.join("\n") %> <%= files.join("\n") %>
<script type="text/javascript"> <script type="text/javascript">
if (window.JHW) { HeadlessReporterResult.specLineNumbers = <%= MultiJson.encode(spec_lines) %>; } if (window.JHW) { HeadlessReporterResult.specLineNumbers = <%= MultiJson.encode(spec_lines) %>; }
@ -51,14 +11,17 @@
</head> </head>
<body> <body>
<script type="text/javascript"> <script type="text/javascript">
jasmine.getEnv().console = {
log: function(msg) { JHW.stdout.puts(msg) }
}
window._onload = window.onload window._onload = window.onload
window.onload = function() { window.onload = function() {
if (window._onload) { window._onload() } if (window._onload) { window._onload() }
if (window.JHW) { if (window.JHW) {
jasmine.getEnv().addReporter(new jasmine.HeadlessReporter(function() { jasmine.getEnv().addReporter(new jasmine.HeadlessConsoleReporter());
window.onbeforeunload = null;
}));
} else { } else {
jasmine.getEnv().addReporter(new jasmine.HtmlReporter()); jasmine.getEnv().addReporter(new jasmine.HtmlReporter());
} }

View File

@ -0,0 +1,14 @@
describe 'HeadlessReporterResult', ->
result = null
name = "name"
splitName = "splitName"
message = 'message'
beforeEach ->
result = new HeadlessReporterResult(name, splitName)
describe '#addResult', ->
it 'should add a message', ->
result.addResult(message)
expect(result.results).toEqual([ message ])

View File

@ -12,11 +12,11 @@ describe 'HeadlessReporterResult', ->
expect(HeadlessReporterResult.findSpecLine([ 'name', 'of', 'test' ]).lineNumber).toEqual(3) expect(HeadlessReporterResult.findSpecLine([ 'name', 'of', 'test' ]).lineNumber).toEqual(3)
expect(HeadlessReporterResult.findSpecLine([ 'other', 'of', 'test' ]).lineNumber).toEqual(10) expect(HeadlessReporterResult.findSpecLine([ 'other', 'of', 'test' ]).lineNumber).toEqual(10)
describe 'jasmine.HeadlessReporter', -> describe 'jasmine.HeadlessConsoleReporter', ->
reporter = null reporter = null
beforeEach -> beforeEach ->
reporter = new jasmine.HeadlessReporter() reporter = new jasmine.HeadlessConsoleReporter()
it 'should stop running specs if there are errors reported', -> it 'should stop running specs if there are errors reported', ->
# otherwise it gets really confusing! # otherwise it gets really confusing!

View File

@ -1,4 +1,4 @@
src_files: [ 'jasmine/*.coffee' ] src_files: [ 'vendor/assets/coffeescripts/*.coffee' ]
spec_files: [ 'spec/javascripts/*_spec.coffee' ] spec_files: [ 'spec/javascripts/*_spec.coffee' ]
src_dir: . src_dir: .
spec_dir: . spec_dir: .

View File

@ -14,9 +14,12 @@ describe Jasmine::FilesList do
File.join(Jasmine::Core.path, "jasmine.js"), File.join(Jasmine::Core.path, "jasmine.js"),
File.join(Jasmine::Core.path, "jasmine-html.js"), File.join(Jasmine::Core.path, "jasmine-html.js"),
File.join(Jasmine::Core.path, "jasmine.css"), File.join(Jasmine::Core.path, "jasmine.css"),
File.expand_path('jasmine/jasmine.headless-reporter.js'), File.expand_path('vendor/assets/javascripts/jasmine-extensions.js'),
File.expand_path('js-lib/jsDump.js'), File.expand_path('vendor/assets/javascripts/intense.js'),
File.expand_path('js-lib/beautify-html.js'), File.expand_path('vendor/assets/javascripts/headless_reporter_result.js'),
File.expand_path('vendor/assets/javascripts/jasmine.HeadlessConsoleReporter.js'),
File.expand_path('vendor/assets/javascripts/jsDump.js'),
File.expand_path('vendor/assets/javascripts/beautify-html.js'),
] ]
end end
end end

View File

@ -138,11 +138,5 @@ describe Qt::Qmake do
end end
end end
end end
describe '.make_options' do
subject { Qt::Qmake.make_options }
it { should == "" }
end
end end

View File

@ -0,0 +1,46 @@
# Try to get the line number of a failed spec
class window.HeadlessReporterResult
constructor: (@name, @splitName) ->
@results = []
addResult: (message) ->
@results.push(message)
print: ->
output = @name.foreground('red')
bestChoice = HeadlessReporterResult.findSpecLine(@splitName)
output += " (#{bestChoice.file}:#{bestChoice.lineNumber})".foreground('blue') if bestChoice.file
JHW.stdout.puts "\n\n#{output}"
for result in @results
output = result.message.foreground('red')
if result.lineNumber
output += " (line ~#{bestChoice.lineNumber + result.lineNumber})".foreground('red').bright()
JHW.stdout.puts(" " + output)
if result.line?
JHW.stdout.puts(" #{result.line}".foreground('yellow'))
@findSpecLine: (splitName) ->
bestChoice = { accuracy: 0, file: null, lineNumber: null }
for file, lines of HeadlessReporterResult.specLineNumbers
index = 0
lineNumber = 0
while newLineNumberInfo = lines[splitName[index]]
if newLineNumberInfo.length == 0
lineNumber = newLineNumberInfo[0]
else
lastLine = null
for line in newLineNumberInfo
lastLine = line
break if line > lineNumber
lineNumber = lastLine
index++
if index > bestChoice.accuracy
bestChoice = { accuracy: index, file: file, lineNumber: lineNumber }
bestChoice

View File

@ -0,0 +1,27 @@
window.Intense = {
colors:
black: 0
red: 1
green: 2
yellow: 3
blue: 4
magenta: 5
cyan: 6
white: 7
methods:
foreground: (color) ->
if Intense.useColors
"\033[3#{Intense.colors[color]}m#{this}\033[0m"
else
this
bright: ->
if Intense.useColors
"\033[1m#{this}\033[0m"
else
this
useColors: true
}
for method, code of Intense.methods
String.prototype[method] = code

View File

@ -2,7 +2,7 @@ if !jasmine?
throw new Error("jasmine not laoded!") throw new Error("jasmine not laoded!")
if window.JHW if window.JHW
# Jasmine extensions # Jasmine extensions
getSplitName = (parts) -> getSplitName = (parts) ->
parts.push(String(@description).replace(/[\n\r]/g, ' ')) parts.push(String(@description).replace(/[\n\r]/g, ' '))
parts parts
@ -84,92 +84,3 @@ if window.JHW
result.expectations = jasmine.NestedResults.parseAndStore(arguments.callee.caller.caller.caller.toString()) result.expectations = jasmine.NestedResults.parseAndStore(arguments.callee.caller.caller.caller.toString())
this.addResult_(result) this.addResult_(result)
# Try to get the line number of a failed spec
class window.HeadlessReporterResult
constructor: (@name, @splitName) ->
@results = []
addResult: (message) ->
@results.push(message)
print: ->
output = @name
bestChoice = HeadlessReporterResult.findSpecLine(@splitName)
output += " (#{bestChoice.file}:#{bestChoice.lineNumber})" if bestChoice.file
JHW.printName(output)
for result in @results
output = result.message
if result.lineNumber
output += " (line ~#{bestChoice.lineNumber + result.lineNumber})\n #{result.line}"
JHW.printResult(output)
@findSpecLine: (splitName) ->
bestChoice = { accuracy: 0, file: null, lineNumber: null }
for file, lines of HeadlessReporterResult.specLineNumbers
index = 0
lineNumber = 0
while newLineNumberInfo = lines[splitName[index]]
if newLineNumberInfo.length == 0
lineNumber = newLineNumberInfo[0]
else
lastLine = null
for line in newLineNumberInfo
lastLine = line
break if line > lineNumber
lineNumber = lastLine
index++
if index > bestChoice.accuracy
bestChoice = { accuracy: index, file: file, lineNumber: lineNumber }
bestChoice
# The reporter itself.
class jasmine.HeadlessReporter
constructor: (@callback = null) ->
@results = []
@failedCount = 0
@length = 0
reportRunnerResults: (runner) ->
return if this.hasError()
for result in @results
result.print()
this.callback() if @callback
JHW.finishSuite((new Date() - @startTime) / 1000.0, @length, @failedCount)
reportRunnerStarting: (runner) ->
@startTime = new Date()
reportSpecResults: (spec) ->
return if this.hasError()
results = spec.results()
@length++
if results.passed()
JHW.specPassed(spec.getJHWSpecInformation())
else
JHW.specFailed(spec.getJHWSpecInformation())
@failedCount++
failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName())
testCount = 1
for result in results.getItems()
if result.type == 'expect' and !result.passed_
if foundLine = result.expectations[testCount - 1]
[ result.line, result.lineNumber ] = foundLine
failureResult.addResult(result)
testCount += 1
@results.push(failureResult)
reportSpecStarting: (spec) ->
if this.hasError()
spec.finish()
spec.suite.finish()
reportSuiteResults: (suite) ->
hasError: ->
JHW.hasError()

View File

@ -0,0 +1,85 @@
if !jasmine?
throw new Error("jasmine not loaded!")
class jasmine.HeadlessConsoleReporter
constructor: (@callback = null) ->
@results = []
@failedCount = 0
@length = 0
reportRunnerResults: (runner) ->
return if this.hasError()
runtime = (new Date() - @startTime) / 1000.0
JHW.stdout.print("\n")
resultLine = this._formatResultLine(runtime)
if @failedCount == 0
JHW.stdout.puts("PASS: #{resultLine}".foreground('green'))
else
JHW.stdout.puts("FAIL: #{resultLine}".foreground('red'))
JHW.hasSpecFailure()
output = "TOTAL||#{@length}||#{@failedCount}||#{runtime}||#{if JHW._hasErrors then "T" else "F"}"
JHW.report.puts(output)
result.print() for result in @results
if window.JHW
window.onbeforeunload = null
JHW.finishSuite()
reportRunnerStarting: (runner) ->
@startTime = new Date()
JHW.stdout.puts("\nRunning Jasmine specs...".bright())
reportSpecResults: (spec) ->
return if this.hasError()
results = spec.results()
@length++
if results.passed()
JHW.stdout.print('.'.foreground('green'))
JHW.report.puts("PASS||" + spec.getJHWSpecInformation())
else
JHW.stdout.print('F'.foreground('red'))
JHW.report.puts("FAIL||" + spec.getJHWSpecInformation())
@failedCount++
failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName())
testCount = 1
for result in results.getItems()
if result.type == 'expect' and !result.passed_
if foundLine = result.expectations[testCount - 1]
[ result.line, result.lineNumber ] = foundLine
failureResult.addResult(result)
testCount += 1
@results.push(failureResult)
reportSpecStarting: (spec) ->
if this.hasError()
spec.finish()
spec.suite.finish()
reportSuiteResults: (suite) ->
hasError: ->
JHW._hasErrors
_formatResultLine: (runtime) ->
line = []
line.push(@length)
line.push((if @length == 1 then "test" else "tests") + ',')
line.push(@failedCount)
line.push((if @failedCount == 1 then "failure" else "failures") + ',')
line.push(runtime)
line.push((if runtime == 1.0 then "sec" else "secs") + '.')
line.join(' ')

View File

@ -0,0 +1,73 @@
if window.JHW
window.console =
log: (data) ->
if typeof(jQuery) != 'undefined' && data instanceof jQuery
JHW.log(style_html($("<div />").append(data).html(), { indent_size: 2 }))
else
useJsDump = true
try
if typeof data.toJSON == 'function'
JHW.log("JSON: #{JSON.stringify(data, null, 2)}")
useJsDump = false
catch e
if useJsDump
dump = jsDump.doParse(data)
if dump.indexOf("\n") == -1
JHW.log(dump)
else
JHW.log("jsDump: #{dump}")
pp: (data) ->
JHW.log(if jasmine then jasmine.pp(data) else console.log(data))
peek: (data) ->
console.log(data)
data
window.onbeforeunload = (e) ->
e = e || window.event
JHW.hasError()
JHW.stdout.puts('The code tried to leave the test page. Check for unhandled form submits and link clicks.')
if e
e.returnValue = 'string'
return 'string'
window.confirm = (message) ->
JHW.stderr.puts("#{"[confirm]".foreground('red')} jasmine-headless-webkit can't handle confirm() yet! You should mock window.confirm. Returning true.")
true
window.alert = (message) ->
JHW.stderr.puts("[alert] ".foreground('red') + message)
JHW._hasErrors = false
JHW._handleError = (message, lineNumber, sourceURL) ->
JHW.stderr.puts(message)
JHW._hasErrors = true
false
JHW._setColors = (useColors) ->
Intense.useColors = useColors
createHandle = (handle) ->
JHW[handle] =
print: (content) -> JHW.print(handle, content)
puts: (content) -> JHW.print(handle, content + "\n")
createHandle(handle) for handle in [ 'stdout', 'stderr', 'report' ]
JHW._usedConsole = false
JHW.log = (msg) ->
JHW.hasUsedConsole()
JHW.report.puts("CONSOLE||#{msg}")
JHW._usedConsole = true
JHW.stdout.puts(msg)
window.CoffeeScriptToFilename = {}
window.CSTF = window.CoffeeScriptToFilename

View File

@ -0,0 +1,72 @@
(function() {
window.HeadlessReporterResult = (function() {
function HeadlessReporterResult(name, splitName) {
this.name = name;
this.splitName = splitName;
this.results = [];
}
HeadlessReporterResult.prototype.addResult = function(message) {
return this.results.push(message);
};
HeadlessReporterResult.prototype.print = function() {
var bestChoice, output, result, _i, _len, _ref, _results;
output = this.name.foreground('red');
bestChoice = HeadlessReporterResult.findSpecLine(this.splitName);
if (bestChoice.file) {
output += (" (" + bestChoice.file + ":" + bestChoice.lineNumber + ")").foreground('blue');
}
JHW.stdout.puts("\n\n" + output);
_ref = this.results;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
result = _ref[_i];
output = result.message.foreground('red');
if (result.lineNumber) {
output += (" (line ~" + (bestChoice.lineNumber + result.lineNumber) + ")").foreground('red').bright();
}
JHW.stdout.puts(" " + output);
_results.push(result.line != null ? JHW.stdout.puts((" " + result.line).foreground('yellow')) : void 0);
}
return _results;
};
HeadlessReporterResult.findSpecLine = function(splitName) {
var bestChoice, file, index, lastLine, line, lineNumber, lines, newLineNumberInfo, _i, _len, _ref;
bestChoice = {
accuracy: 0,
file: null,
lineNumber: null
};
_ref = HeadlessReporterResult.specLineNumbers;
for (file in _ref) {
lines = _ref[file];
index = 0;
lineNumber = 0;
while (newLineNumberInfo = lines[splitName[index]]) {
if (newLineNumberInfo.length === 0) {
lineNumber = newLineNumberInfo[0];
} else {
lastLine = null;
for (_i = 0, _len = newLineNumberInfo.length; _i < _len; _i++) {
line = newLineNumberInfo[_i];
lastLine = line;
if (line > lineNumber) {
break;
}
}
lineNumber = lastLine;
}
index++;
}
if (index > bestChoice.accuracy) {
bestChoice = {
accuracy: index,
file: file,
lineNumber: lineNumber
};
}
}
return bestChoice;
};
return HeadlessReporterResult;
})();
}).call(this);

37
vendor/assets/javascripts/intense.js vendored Normal file
View File

@ -0,0 +1,37 @@
(function() {
var code, method, _ref;
window.Intense = {
colors: {
black: 0,
red: 1,
green: 2,
yellow: 3,
blue: 4,
magenta: 5,
cyan: 6,
white: 7
},
methods: {
foreground: function(color) {
if (Intense.useColors) {
return "\033[3" + Intense.colors[color] + "m" + this + "\033[0m";
} else {
return this;
}
},
bright: function() {
if (Intense.useColors) {
return "\033[1m" + this + "\033[0m";
} else {
return this;
}
}
},
useColors: true
};
_ref = Intense.methods;
for (method in _ref) {
code = _ref[method];
String.prototype[method] = code;
}
}).call(this);

View File

@ -0,0 +1,97 @@
(function() {
var getSplitName, pauseAndRun;
if (!(typeof jasmine !== "undefined" && jasmine !== null)) {
throw new Error("jasmine not laoded!");
}
if (window.JHW) {
getSplitName = function(parts) {
parts.push(String(this.description).replace(/[\n\r]/g, ' '));
return parts;
};
jasmine.Suite.prototype.getSuiteSplitName = function() {
return this.getSplitName(this.parentSuite ? this.parentSuite.getSuiteSplitName() : []);
};
jasmine.Spec.prototype.getSpecSplitName = function() {
return this.getSplitName(this.suite.getSuiteSplitName());
};
jasmine.Suite.prototype.getSplitName = getSplitName;
jasmine.Spec.prototype.getSplitName = getSplitName;
jasmine.Spec.prototype.getJHWSpecInformation = function() {
var parts, specLineInfo;
parts = this.getSpecSplitName();
specLineInfo = HeadlessReporterResult.findSpecLine(parts);
if (specLineInfo.file) {
parts.push("" + specLineInfo.file + ":" + specLineInfo.lineNumber);
} else {
parts.push('');
}
return parts.join("||");
};
jasmine.Spec.prototype.fail = function(e) {
var expectationResult, filename, realFilename;
if (e && e.sourceURL && window.CoffeeScriptToFilename) {
filename = e.sourceURL.split('/').pop();
if (realFilename = window.CoffeeScriptToFilename[filename]) {
e = {
name: e.name,
message: e.message,
lineNumber: "~" + String(e.line),
sourceURL: realFilename
};
}
}
expectationResult = new jasmine.ExpectationResult({
passed: false,
message: e ? jasmine.util.formatException(e) : 'Exception',
trace: {
stack: e.stack
}
});
return this.results_.addResult(expectationResult);
};
jasmine.NestedResults.isValidSpecLine = function(line) {
return line.match(/^\s*expect/) !== null || line.match(/^\s*return\s*expect/) !== null;
};
jasmine.NestedResults.parseFunction = function(func) {
var line, lineCount, lines, _i, _len, _ref;
lines = [];
lineCount = 0;
_ref = func.split("\n");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
if (jasmine.NestedResults.isValidSpecLine(line)) {
line = line.replace(/^\s*/, '').replace(/\s*$/, '').replace(/^return\s*/, '');
lines.push([line, lineCount]);
}
lineCount += 1;
}
return lines;
};
jasmine.NestedResults.parseAndStore = function(func) {
if (!jasmine.NestedResults.ParsedFunctions[func]) {
jasmine.NestedResults.ParsedFunctions[func] = jasmine.NestedResults.parseFunction(func);
}
return jasmine.NestedResults.ParsedFunctions[func];
};
jasmine.NestedResults.ParsedFunctions = [];
if (!jasmine.WaitsBlock.prototype._execute) {
jasmine.WaitsBlock.prototype._execute = jasmine.WaitsBlock.prototype.execute;
jasmine.WaitsForBlock.prototype._execute = jasmine.WaitsForBlock.prototype.execute;
pauseAndRun = function(onComplete) {
JHW.timerPause();
return this._execute(function() {
JHW.timerDone();
return onComplete();
});
};
jasmine.WaitsBlock.prototype.execute = pauseAndRun;
jasmine.WaitsForBlock.prototype.execute = pauseAndRun;
jasmine.NestedResults.prototype.addResult_ = jasmine.NestedResults.prototype.addResult;
jasmine.NestedResults.prototype.addResult = function(result) {
result.expectations = [];
result.expectations = jasmine.NestedResults.parseAndStore(arguments.callee.caller.caller.caller.toString());
return this.addResult_(result);
};
}
}
}).call(this);

View File

@ -0,0 +1,95 @@
(function() {
if (!(typeof jasmine !== "undefined" && jasmine !== null)) {
throw new Error("jasmine not loaded!");
}
jasmine.HeadlessConsoleReporter = (function() {
function HeadlessConsoleReporter(callback) {
this.callback = callback != null ? callback : null;
this.results = [];
this.failedCount = 0;
this.length = 0;
}
HeadlessConsoleReporter.prototype.reportRunnerResults = function(runner) {
var output, result, resultLine, runtime, _i, _len, _ref;
if (this.hasError()) {
return;
}
runtime = (new Date() - this.startTime) / 1000.0;
JHW.stdout.print("\n");
resultLine = this._formatResultLine(runtime);
if (this.failedCount === 0) {
JHW.stdout.puts(("PASS: " + resultLine).foreground('green'));
} else {
JHW.stdout.puts(("FAIL: " + resultLine).foreground('red'));
JHW.hasSpecFailure();
}
output = "TOTAL||" + this.length + "||" + this.failedCount + "||" + runtime + "||" + (JHW._hasErrors ? "T" : "F");
JHW.report.puts(output);
_ref = this.results;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
result = _ref[_i];
result.print();
}
if (window.JHW) {
window.onbeforeunload = null;
}
return JHW.finishSuite();
};
HeadlessConsoleReporter.prototype.reportRunnerStarting = function(runner) {
this.startTime = new Date();
return JHW.stdout.puts("\nRunning Jasmine specs...".bright());
};
HeadlessConsoleReporter.prototype.reportSpecResults = function(spec) {
var failureResult, foundLine, result, results, testCount, _i, _len, _ref;
if (this.hasError()) {
return;
}
results = spec.results();
this.length++;
if (results.passed()) {
JHW.stdout.print('.'.foreground('green'));
return JHW.report.puts("PASS||" + spec.getJHWSpecInformation());
} else {
JHW.stdout.print('F'.foreground('red'));
JHW.report.puts("FAIL||" + spec.getJHWSpecInformation());
this.failedCount++;
failureResult = new HeadlessReporterResult(spec.getFullName(), spec.getSpecSplitName());
testCount = 1;
_ref = results.getItems();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
result = _ref[_i];
if (result.type === 'expect' && !result.passed_) {
if (foundLine = result.expectations[testCount - 1]) {
result.line = foundLine[0], result.lineNumber = foundLine[1];
}
failureResult.addResult(result);
}
testCount += 1;
}
return this.results.push(failureResult);
}
};
HeadlessConsoleReporter.prototype.reportSpecStarting = function(spec) {
if (this.hasError()) {
spec.finish();
return spec.suite.finish();
}
};
HeadlessConsoleReporter.prototype.reportSuiteResults = function(suite) {};
HeadlessConsoleReporter.prototype.hasError = function() {
return JHW._hasErrors;
};
HeadlessConsoleReporter.prototype._formatResultLine = function(runtime) {
var line;
line = [];
line.push(this.length);
line.push((this.length === 1 ? "test" : "tests") + ',');
line.push(this.failedCount);
line.push((this.failedCount === 1 ? "failure" : "failures") + ',');
line.push(runtime);
line.push((runtime === 1.0 ? "sec" : "secs") + '.');
return line.join(' ');
};
return HeadlessConsoleReporter;
})();
}).call(this);

89
vendor/assets/javascripts/prolog.js vendored Normal file
View File

@ -0,0 +1,89 @@
(function() {
var createHandle, handle, _i, _len, _ref;
if (window.JHW) {
window.console = {
log: function(data) {
var dump, useJsDump;
if (typeof jQuery !== 'undefined' && data instanceof jQuery) {
return JHW.log(style_html($("<div />").append(data).html(), {
indent_size: 2
}));
} else {
useJsDump = true;
try {
if (typeof data.toJSON === 'function') {
JHW.log("JSON: " + (JSON.stringify(data, null, 2)));
useJsDump = false;
}
} catch (e) {
}
if (useJsDump) {
dump = jsDump.doParse(data);
if (dump.indexOf("\n") === -1) {
return JHW.log(dump);
} else {
return JHW.log("jsDump: " + dump);
}
}
}
},
pp: function(data) {
return JHW.log(jasmine ? jasmine.pp(data) : console.log(data));
},
peek: function(data) {
console.log(data);
return data;
}
};
window.onbeforeunload = function(e) {
e = e || window.event;
JHW.hasError();
JHW.stdout.puts('The code tried to leave the test page. Check for unhandled form submits and link clicks.');
if (e) {
e.returnValue = 'string';
}
return 'string';
};
window.confirm = function(message) {
JHW.stderr.puts("" + ("[confirm]".foreground('red')) + " jasmine-headless-webkit can't handle confirm() yet! You should mock window.confirm. Returning true.");
return true;
};
window.alert = function(message) {
return JHW.stderr.puts("[alert] ".foreground('red') + message);
};
JHW._hasErrors = false;
JHW._handleError = function(message, lineNumber, sourceURL) {
JHW.stderr.puts(message);
JHW._hasErrors = true;
return false;
};
JHW._setColors = function(useColors) {
return Intense.useColors = useColors;
};
createHandle = function(handle) {
return JHW[handle] = {
print: function(content) {
return JHW.print(handle, content);
},
puts: function(content) {
return JHW.print(handle, content + "\n");
}
};
};
_ref = ['stdout', 'stderr', 'report'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
handle = _ref[_i];
createHandle(handle);
}
JHW._usedConsole = false;
JHW.log = function(msg) {
JHW.hasUsedConsole();
JHW.report.puts("CONSOLE||" + msg);
JHW._usedConsole = true;
return JHW.stdout.puts(msg);
};
}
window.CoffeeScriptToFilename = {};
window.CSTF = window.CoffeeScriptToFilename;
}).call(this);