simple_pvr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +133 -0
- data/LICENSE.txt +13 -0
- data/README.md +169 -0
- data/Rakefile +16 -0
- data/bin/pvr_server +10 -0
- data/bin/pvr_xmltv +18 -0
- data/features/channel_overview.feature +48 -0
- data/features/programme_search.feature +20 -0
- data/features/scheduling.feature +112 -0
- data/features/step_definitions/pvr_steps.rb +104 -0
- data/features/step_definitions/web_steps.rb +219 -0
- data/features/support/env.rb +28 -0
- data/features/support/paths.rb +17 -0
- data/features/week_overview.feature +39 -0
- data/lib/simple_pvr/ffmpeg.rb +22 -0
- data/lib/simple_pvr/hdhomerun.rb +103 -0
- data/lib/simple_pvr/hdhomerun_save.sh +10 -0
- data/lib/simple_pvr/model/channel.rb +72 -0
- data/lib/simple_pvr/model/database_initializer.rb +36 -0
- data/lib/simple_pvr/model/programme.rb +58 -0
- data/lib/simple_pvr/model/recording.rb +45 -0
- data/lib/simple_pvr/model/schedule.rb +33 -0
- data/lib/simple_pvr/pvr_initializer.rb +47 -0
- data/lib/simple_pvr/pvr_logger.rb +14 -0
- data/lib/simple_pvr/recorder.rb +25 -0
- data/lib/simple_pvr/recording_manager.rb +101 -0
- data/lib/simple_pvr/recording_planner.rb +72 -0
- data/lib/simple_pvr/scheduler.rb +124 -0
- data/lib/simple_pvr/server/app_controller.rb +13 -0
- data/lib/simple_pvr/server/base_controller.rb +94 -0
- data/lib/simple_pvr/server/channels_controller.rb +68 -0
- data/lib/simple_pvr/server/config.ru +8 -0
- data/lib/simple_pvr/server/programmes_controller.rb +46 -0
- data/lib/simple_pvr/server/rack_maps.rb +7 -0
- data/lib/simple_pvr/server/schedules_controller.rb +71 -0
- data/lib/simple_pvr/server/shows_controller.rb +63 -0
- data/lib/simple_pvr/server/status_controller.rb +11 -0
- data/lib/simple_pvr/server/upcoming_recordings_controller.rb +18 -0
- data/lib/simple_pvr/version.rb +3 -0
- data/lib/simple_pvr/xmltv_reader.rb +83 -0
- data/lib/simple_pvr.rb +22 -0
- data/public/css/bootstrap-responsive.min.css +9 -0
- data/public/css/bootstrap.min.css +9 -0
- data/public/css/simplepvr.css +11 -0
- data/public/img/glyphicons-halflings-white.png +0 -0
- data/public/img/glyphicons-halflings.png +0 -0
- data/public/index.html +55 -0
- data/public/js/angular/angular-resource.min.js +10 -0
- data/public/js/angular/angular.min.js +157 -0
- data/public/js/app.js +145 -0
- data/public/js/bootstrap/bootstrap.min.js +6 -0
- data/public/js/controllers.js +156 -0
- data/public/js/services.js +27 -0
- data/public/partials/about.html +5 -0
- data/public/partials/channels.html +41 -0
- data/public/partials/programme.html +20 -0
- data/public/partials/programmeListing.html +18 -0
- data/public/partials/schedule.html +80 -0
- data/public/partials/schedules.html +44 -0
- data/public/partials/search.html +17 -0
- data/public/partials/show.html +21 -0
- data/public/partials/shows.html +7 -0
- data/public/partials/status.html +6 -0
- data/simple_pvr.gemspec +30 -0
- data/spec/resources/channels.txt +11 -0
- data/spec/resources/programs-without-icon.xmltv +95 -0
- data/spec/resources/programs.xmltv +98 -0
- data/spec/simple_pvr/ffmpeg_spec.rb +26 -0
- data/spec/simple_pvr/hdhomerun_spec.rb +82 -0
- data/spec/simple_pvr/model/channel_spec.rb +114 -0
- data/spec/simple_pvr/model/programme_spec.rb +110 -0
- data/spec/simple_pvr/model/schedule_spec.rb +47 -0
- data/spec/simple_pvr/pvr_initializer_spec.rb +50 -0
- data/spec/simple_pvr/recorder_spec.rb +32 -0
- data/spec/simple_pvr/recording_manager_spec.rb +158 -0
- data/spec/simple_pvr/recording_planner_spec.rb +104 -0
- data/spec/simple_pvr/scheduler_spec.rb +201 -0
- data/spec/simple_pvr/xmltv_reader_spec.rb +49 -0
- data/test/config/jsTestDriver-scenario.conf +10 -0
- data/test/config/jsTestDriver.conf +12 -0
- data/test/config/jstd-scenario-adapter-config.js +6 -0
- data/test/filtersSpec.js +97 -0
- data/test/lib/angular/angular-mocks.js +1719 -0
- data/test/lib/angular/angular-scenario.js +25937 -0
- data/test/lib/angular/jstd-scenario-adapter.js +185 -0
- data/test/lib/angular/version.txt +1 -0
- data/test/lib/jasmine/MIT.LICENSE +20 -0
- data/test/lib/jasmine/index.js +180 -0
- data/test/lib/jasmine/jasmine-html.js +190 -0
- data/test/lib/jasmine/jasmine.css +166 -0
- data/test/lib/jasmine/jasmine.js +2476 -0
- data/test/lib/jasmine/jasmine_favicon.png +0 -0
- data/test/lib/jasmine/version.txt +1 -0
- data/test/lib/jasmine-jstd-adapter/JasmineAdapter.js +196 -0
- data/test/lib/jasmine-jstd-adapter/version.txt +1 -0
- data/test/lib/jstestdriver/JsTestDriver.jar +0 -0
- data/test/lib/jstestdriver/version.txt +1 -0
- data/test/scripts/test-server.sh +14 -0
- data/test/scripts/test.sh +8 -0
- metadata +342 -0
@@ -0,0 +1,185 @@
|
|
1
|
+
/**
|
2
|
+
* @license AngularJS v1.0.0rc1
|
3
|
+
* (c) 2010-2011 AngularJS http://angularjs.org
|
4
|
+
* License: MIT
|
5
|
+
*/
|
6
|
+
(function(window) {
|
7
|
+
'use strict';
|
8
|
+
|
9
|
+
/**
|
10
|
+
* JSTestDriver adapter for angular scenario tests
|
11
|
+
*
|
12
|
+
* Example of jsTestDriver.conf for running scenario tests with JSTD:
|
13
|
+
<pre>
|
14
|
+
server: http://localhost:9877
|
15
|
+
|
16
|
+
load:
|
17
|
+
- lib/angular-scenario.js
|
18
|
+
- lib/jstd-scenario-adapter-config.js
|
19
|
+
- lib/jstd-scenario-adapter.js
|
20
|
+
# your test files go here #
|
21
|
+
|
22
|
+
proxy:
|
23
|
+
- {matcher: "/your-prefix/*", server: "http://localhost:8000/"}
|
24
|
+
</pre>
|
25
|
+
*
|
26
|
+
* For more information on how to configure jstd proxy, see {@link http://code.google.com/p/js-test-driver/wiki/Proxy}
|
27
|
+
* Note the order of files - it's important !
|
28
|
+
*
|
29
|
+
* Example of jstd-scenario-adapter-config.js
|
30
|
+
<pre>
|
31
|
+
var jstdScenarioAdapter = {
|
32
|
+
relativeUrlPrefix: '/your-prefix/'
|
33
|
+
};
|
34
|
+
</pre>
|
35
|
+
*
|
36
|
+
* Whenever you use <code>browser().navigateTo('relativeUrl')</code> in your scenario test, the relativeUrlPrefix will be prepended.
|
37
|
+
* You have to configure this to work together with JSTD proxy.
|
38
|
+
*
|
39
|
+
* Let's assume you are using the above configuration (jsTestDriver.conf and jstd-scenario-adapter-config.js):
|
40
|
+
* Now, when you call <code>browser().navigateTo('index.html')</code> in your scenario test, the browser will open /your-prefix/index.html.
|
41
|
+
* That matches the proxy, so JSTD will proxy this request to http://localhost:8000/index.html.
|
42
|
+
*/
|
43
|
+
|
44
|
+
/**
|
45
|
+
* Custom type of test case
|
46
|
+
*
|
47
|
+
* @const
|
48
|
+
* @see jstestdriver.TestCaseInfo
|
49
|
+
*/
|
50
|
+
var SCENARIO_TYPE = 'scenario';
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Plugin for JSTestDriver
|
54
|
+
* Connection point between scenario's jstd output and jstestdriver.
|
55
|
+
*
|
56
|
+
* @see jstestdriver.PluginRegistrar
|
57
|
+
*/
|
58
|
+
function JstdPlugin() {
|
59
|
+
var nop = function() {};
|
60
|
+
|
61
|
+
this.reportResult = nop;
|
62
|
+
this.reportEnd = nop;
|
63
|
+
this.runScenario = nop;
|
64
|
+
|
65
|
+
this.name = 'Angular Scenario Adapter';
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Called for each JSTD TestCase
|
69
|
+
*
|
70
|
+
* Handles only SCENARIO_TYPE test cases. There should be only one fake TestCase.
|
71
|
+
* Runs all scenario tests (under one fake TestCase) and report all results to JSTD.
|
72
|
+
*
|
73
|
+
* @param {jstestdriver.TestRunConfiguration} configuration
|
74
|
+
* @param {Function} onTestDone
|
75
|
+
* @param {Function} onAllTestsComplete
|
76
|
+
* @returns {boolean} True if this type of test is handled by this plugin, false otherwise
|
77
|
+
*/
|
78
|
+
this.runTestConfiguration = function(configuration, onTestDone, onAllTestsComplete) {
|
79
|
+
if (configuration.getTestCaseInfo().getType() != SCENARIO_TYPE) return false;
|
80
|
+
|
81
|
+
this.reportResult = onTestDone;
|
82
|
+
this.reportEnd = onAllTestsComplete;
|
83
|
+
this.runScenario();
|
84
|
+
|
85
|
+
return true;
|
86
|
+
};
|
87
|
+
|
88
|
+
this.getTestRunsConfigurationFor = function(testCaseInfos, expressions, testRunsConfiguration) {
|
89
|
+
testRunsConfiguration.push(
|
90
|
+
new jstestdriver.TestRunConfiguration(
|
91
|
+
new jstestdriver.TestCaseInfo(
|
92
|
+
'Angular Scenario Tests', function() {}, SCENARIO_TYPE), []));
|
93
|
+
|
94
|
+
return true;
|
95
|
+
};
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Singleton instance of the plugin
|
100
|
+
* Accessed using closure by:
|
101
|
+
* - jstd output (reports to this plugin)
|
102
|
+
* - initScenarioAdapter (register the plugin to jstd)
|
103
|
+
*/
|
104
|
+
var plugin = new JstdPlugin();
|
105
|
+
|
106
|
+
/**
|
107
|
+
* Initialise scenario jstd-adapter
|
108
|
+
* (only if jstestdriver is defined)
|
109
|
+
*
|
110
|
+
* @param {Object} jstestdriver Undefined when run from browser (without jstd)
|
111
|
+
* @param {Function} initScenarioAndRun Function that inits scenario and runs all the tests
|
112
|
+
* @param {Object=} config Configuration object, supported properties:
|
113
|
+
* - relativeUrlPrefix: prefix for all relative links when navigateTo()
|
114
|
+
*/
|
115
|
+
function initScenarioAdapter(jstestdriver, initScenarioAndRun, config) {
|
116
|
+
if (jstestdriver) {
|
117
|
+
// create and register ScenarioPlugin
|
118
|
+
jstestdriver.pluginRegistrar.register(plugin);
|
119
|
+
plugin.runScenario = initScenarioAndRun;
|
120
|
+
|
121
|
+
/**
|
122
|
+
* HACK (angular.scenario.Application.navigateTo)
|
123
|
+
*
|
124
|
+
* We need to navigate to relative urls when running from browser (without JSTD),
|
125
|
+
* because we want to allow running scenario tests without creating its own virtual host.
|
126
|
+
* For example: http://angular.local/build/docs/docs-scenario.html
|
127
|
+
*
|
128
|
+
* On the other hand, when running with JSTD, we need to navigate to absolute urls,
|
129
|
+
* because of JSTD proxy. (proxy, because of same domain policy)
|
130
|
+
*
|
131
|
+
* So this hack is applied only if running with JSTD and change all relative urls to absolute.
|
132
|
+
*/
|
133
|
+
var appProto = angular.scenario.Application.prototype,
|
134
|
+
navigateTo = appProto.navigateTo,
|
135
|
+
relativeUrlPrefix = config && config.relativeUrlPrefix || '/';
|
136
|
+
|
137
|
+
appProto.navigateTo = function(url, loadFn, errorFn) {
|
138
|
+
if (url.charAt(0) != '/' && url.charAt(0) != '#' &&
|
139
|
+
url != 'about:blank' && !url.match(/^https?/)) {
|
140
|
+
url = relativeUrlPrefix + url;
|
141
|
+
}
|
142
|
+
|
143
|
+
return navigateTo.call(this, url, loadFn, errorFn);
|
144
|
+
};
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
/**
|
149
|
+
* Builds proper TestResult object from given model spec
|
150
|
+
*
|
151
|
+
* TODO(vojta) report error details
|
152
|
+
*
|
153
|
+
* @param {angular.scenario.ObjectModel.Spec} spec
|
154
|
+
* @returns {jstestdriver.TestResult}
|
155
|
+
*/
|
156
|
+
function createTestResultFromSpec(spec) {
|
157
|
+
var map = {
|
158
|
+
success: 'PASSED',
|
159
|
+
error: 'ERROR',
|
160
|
+
failure: 'FAILED'
|
161
|
+
};
|
162
|
+
|
163
|
+
return new jstestdriver.TestResult(
|
164
|
+
spec.fullDefinitionName,
|
165
|
+
spec.name,
|
166
|
+
jstestdriver.TestResult.RESULT[map[spec.status]],
|
167
|
+
spec.error || '',
|
168
|
+
spec.line || '',
|
169
|
+
spec.duration);
|
170
|
+
}
|
171
|
+
|
172
|
+
/**
|
173
|
+
* Generates JSTD output (jstestdriver.TestResult)
|
174
|
+
*/
|
175
|
+
angular.scenario.output('jstd', function(context, runner, model) {
|
176
|
+
model.on('SpecEnd', function(spec) {
|
177
|
+
plugin.reportResult(createTestResultFromSpec(spec));
|
178
|
+
});
|
179
|
+
|
180
|
+
model.on('RunnerEnd', function() {
|
181
|
+
plugin.reportEnd();
|
182
|
+
});
|
183
|
+
});
|
184
|
+
initScenarioAdapter(window.jstestdriver, angular.scenario.setUpAndRun, window.jstdScenarioAdapter);
|
185
|
+
})(window);
|
@@ -0,0 +1 @@
|
|
1
|
+
1.0.1
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008-2011 Pivotal Labs
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,180 @@
|
|
1
|
+
var fs = require('fs');
|
2
|
+
var sys = require('sys');
|
3
|
+
var path = require('path');
|
4
|
+
|
5
|
+
var filename = __dirname + '/jasmine.js';
|
6
|
+
global.window = {
|
7
|
+
setTimeout: setTimeout,
|
8
|
+
clearTimeout: clearTimeout,
|
9
|
+
setInterval: setInterval,
|
10
|
+
clearInterval: clearInterval
|
11
|
+
};
|
12
|
+
var src = fs.readFileSync(filename);
|
13
|
+
var jasmine = process.compile(src + '\njasmine;', filename);
|
14
|
+
delete global.window;
|
15
|
+
|
16
|
+
function noop(){}
|
17
|
+
|
18
|
+
jasmine.executeSpecsInFolder = function(folder, done, isVerbose, showColors, matcher){
|
19
|
+
var log = [];
|
20
|
+
var columnCounter = 0;
|
21
|
+
var start = 0;
|
22
|
+
var elapsed = 0;
|
23
|
+
var verbose = isVerbose || false;
|
24
|
+
var fileMatcher = new RegExp(matcher || "\.js$");
|
25
|
+
var colors = showColors || false;
|
26
|
+
var specs = jasmine.getAllSpecFiles(folder, fileMatcher);
|
27
|
+
|
28
|
+
var ansi = {
|
29
|
+
green: '\033[32m',
|
30
|
+
red: '\033[31m',
|
31
|
+
yellow: '\033[33m',
|
32
|
+
none: '\033[0m'
|
33
|
+
};
|
34
|
+
|
35
|
+
for (var i = 0, len = specs.length; i < len; ++i){
|
36
|
+
var filename = specs[i];
|
37
|
+
require(filename.replace(/\.*$/, ""));
|
38
|
+
}
|
39
|
+
|
40
|
+
var jasmineEnv = jasmine.getEnv();
|
41
|
+
jasmineEnv.reporter = {
|
42
|
+
log: function(str){
|
43
|
+
},
|
44
|
+
|
45
|
+
reportSpecStarting: function(runner) {
|
46
|
+
},
|
47
|
+
|
48
|
+
reportRunnerStarting: function(runner) {
|
49
|
+
sys.puts('Started');
|
50
|
+
start = Number(new Date);
|
51
|
+
},
|
52
|
+
|
53
|
+
reportSuiteResults: function(suite) {
|
54
|
+
var specResults = suite.results();
|
55
|
+
var path = [];
|
56
|
+
while(suite) {
|
57
|
+
path.unshift(suite.description);
|
58
|
+
suite = suite.parentSuite;
|
59
|
+
}
|
60
|
+
var description = path.join(' ');
|
61
|
+
|
62
|
+
if (verbose)
|
63
|
+
log.push('Spec ' + description);
|
64
|
+
|
65
|
+
specResults.items_.forEach(function(spec){
|
66
|
+
if (spec.failedCount > 0 && spec.description) {
|
67
|
+
if (!verbose)
|
68
|
+
log.push(description);
|
69
|
+
log.push(' it ' + spec.description);
|
70
|
+
spec.items_.forEach(function(result){
|
71
|
+
log.push(' ' + result.trace.stack + '\n');
|
72
|
+
});
|
73
|
+
}
|
74
|
+
});
|
75
|
+
},
|
76
|
+
|
77
|
+
reportSpecResults: function(spec) {
|
78
|
+
var result = spec.results();
|
79
|
+
var msg = '';
|
80
|
+
if (result.passed())
|
81
|
+
{
|
82
|
+
msg = (colors) ? (ansi.green + '.' + ansi.none) : '.';
|
83
|
+
// } else if (result.skipped) { TODO: Research why "result.skipped" returns false when "xit" is called on a spec?
|
84
|
+
// msg = (colors) ? (ansi.yellow + '*' + ansi.none) : '*';
|
85
|
+
} else {
|
86
|
+
msg = (colors) ? (ansi.red + 'F' + ansi.none) : 'F';
|
87
|
+
}
|
88
|
+
sys.print(msg);
|
89
|
+
if (columnCounter++ < 50) return;
|
90
|
+
columnCounter = 0;
|
91
|
+
sys.print('\n');
|
92
|
+
},
|
93
|
+
|
94
|
+
|
95
|
+
reportRunnerResults: function(runner) {
|
96
|
+
elapsed = (Number(new Date) - start) / 1000;
|
97
|
+
sys.puts('\n');
|
98
|
+
log.forEach(function(log){
|
99
|
+
sys.puts(log);
|
100
|
+
});
|
101
|
+
sys.puts('Finished in ' + elapsed + ' seconds');
|
102
|
+
|
103
|
+
var summary = jasmine.printRunnerResults(runner);
|
104
|
+
if(colors)
|
105
|
+
{
|
106
|
+
if(runner.results().failedCount === 0 )
|
107
|
+
sys.puts(ansi.green + summary + ansi.none);
|
108
|
+
else
|
109
|
+
sys.puts(ansi.red + summary + ansi.none);
|
110
|
+
} else {
|
111
|
+
sys.puts(summary);
|
112
|
+
}
|
113
|
+
(done||noop)(runner, log);
|
114
|
+
}
|
115
|
+
};
|
116
|
+
jasmineEnv.execute();
|
117
|
+
};
|
118
|
+
|
119
|
+
jasmine.getAllSpecFiles = function(dir, matcher){
|
120
|
+
var specs = [];
|
121
|
+
|
122
|
+
if (fs.statSync(dir).isFile() && dir.match(matcher)) {
|
123
|
+
specs.push(dir);
|
124
|
+
} else {
|
125
|
+
var files = fs.readdirSync(dir);
|
126
|
+
for (var i = 0, len = files.length; i < len; ++i){
|
127
|
+
var filename = dir + '/' + files[i];
|
128
|
+
if (fs.statSync(filename).isFile() && filename.match(matcher)){
|
129
|
+
specs.push(filename);
|
130
|
+
}else if (fs.statSync(filename).isDirectory()){
|
131
|
+
var subfiles = this.getAllSpecFiles(filename, matcher);
|
132
|
+
subfiles.forEach(function(result){
|
133
|
+
specs.push(result);
|
134
|
+
});
|
135
|
+
}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
return specs;
|
140
|
+
};
|
141
|
+
|
142
|
+
jasmine.printRunnerResults = function(runner){
|
143
|
+
var results = runner.results();
|
144
|
+
var suites = runner.suites();
|
145
|
+
var msg = '';
|
146
|
+
msg += suites.length + ' test' + ((suites.length === 1) ? '' : 's') + ', ';
|
147
|
+
msg += results.totalCount + ' assertion' + ((results.totalCount === 1) ? '' : 's') + ', ';
|
148
|
+
msg += results.failedCount + ' failure' + ((results.failedCount === 1) ? '' : 's') + '\n';
|
149
|
+
return msg;
|
150
|
+
};
|
151
|
+
|
152
|
+
function now(){
|
153
|
+
return new Date().getTime();
|
154
|
+
}
|
155
|
+
|
156
|
+
jasmine.asyncSpecWait = function(){
|
157
|
+
var wait = jasmine.asyncSpecWait;
|
158
|
+
wait.start = now();
|
159
|
+
wait.done = false;
|
160
|
+
(function innerWait(){
|
161
|
+
waits(10);
|
162
|
+
runs(function() {
|
163
|
+
if (wait.start + wait.timeout < now()) {
|
164
|
+
expect('timeout waiting for spec').toBeNull();
|
165
|
+
} else if (wait.done) {
|
166
|
+
wait.done = false;
|
167
|
+
} else {
|
168
|
+
innerWait();
|
169
|
+
}
|
170
|
+
});
|
171
|
+
})();
|
172
|
+
};
|
173
|
+
jasmine.asyncSpecWait.timeout = 4 * 1000;
|
174
|
+
jasmine.asyncSpecDone = function(){
|
175
|
+
jasmine.asyncSpecWait.done = true;
|
176
|
+
};
|
177
|
+
|
178
|
+
for ( var key in jasmine) {
|
179
|
+
exports[key] = jasmine[key];
|
180
|
+
}
|
@@ -0,0 +1,190 @@
|
|
1
|
+
jasmine.TrivialReporter = function(doc) {
|
2
|
+
this.document = doc || document;
|
3
|
+
this.suiteDivs = {};
|
4
|
+
this.logRunningSpecs = false;
|
5
|
+
};
|
6
|
+
|
7
|
+
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
|
8
|
+
var el = document.createElement(type);
|
9
|
+
|
10
|
+
for (var i = 2; i < arguments.length; i++) {
|
11
|
+
var child = arguments[i];
|
12
|
+
|
13
|
+
if (typeof child === 'string') {
|
14
|
+
el.appendChild(document.createTextNode(child));
|
15
|
+
} else {
|
16
|
+
if (child) { el.appendChild(child); }
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
for (var attr in attrs) {
|
21
|
+
if (attr == "className") {
|
22
|
+
el[attr] = attrs[attr];
|
23
|
+
} else {
|
24
|
+
el.setAttribute(attr, attrs[attr]);
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
return el;
|
29
|
+
};
|
30
|
+
|
31
|
+
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
|
32
|
+
var showPassed, showSkipped;
|
33
|
+
|
34
|
+
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
|
35
|
+
this.createDom('div', { className: 'banner' },
|
36
|
+
this.createDom('div', { className: 'logo' },
|
37
|
+
this.createDom('span', { className: 'title' }, "Jasmine"),
|
38
|
+
this.createDom('span', { className: 'version' }, runner.env.versionString())),
|
39
|
+
this.createDom('div', { className: 'options' },
|
40
|
+
"Show ",
|
41
|
+
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
|
42
|
+
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
|
43
|
+
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
|
44
|
+
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
|
45
|
+
)
|
46
|
+
),
|
47
|
+
|
48
|
+
this.runnerDiv = this.createDom('div', { className: 'runner running' },
|
49
|
+
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
|
50
|
+
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
|
51
|
+
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
|
52
|
+
);
|
53
|
+
|
54
|
+
this.document.body.appendChild(this.outerDiv);
|
55
|
+
|
56
|
+
var suites = runner.suites();
|
57
|
+
for (var i = 0; i < suites.length; i++) {
|
58
|
+
var suite = suites[i];
|
59
|
+
var suiteDiv = this.createDom('div', { className: 'suite' },
|
60
|
+
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
|
61
|
+
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
|
62
|
+
this.suiteDivs[suite.id] = suiteDiv;
|
63
|
+
var parentDiv = this.outerDiv;
|
64
|
+
if (suite.parentSuite) {
|
65
|
+
parentDiv = this.suiteDivs[suite.parentSuite.id];
|
66
|
+
}
|
67
|
+
parentDiv.appendChild(suiteDiv);
|
68
|
+
}
|
69
|
+
|
70
|
+
this.startedAt = new Date();
|
71
|
+
|
72
|
+
var self = this;
|
73
|
+
showPassed.onclick = function(evt) {
|
74
|
+
if (showPassed.checked) {
|
75
|
+
self.outerDiv.className += ' show-passed';
|
76
|
+
} else {
|
77
|
+
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
|
78
|
+
}
|
79
|
+
};
|
80
|
+
|
81
|
+
showSkipped.onclick = function(evt) {
|
82
|
+
if (showSkipped.checked) {
|
83
|
+
self.outerDiv.className += ' show-skipped';
|
84
|
+
} else {
|
85
|
+
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
|
86
|
+
}
|
87
|
+
};
|
88
|
+
};
|
89
|
+
|
90
|
+
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
|
91
|
+
var results = runner.results();
|
92
|
+
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
|
93
|
+
this.runnerDiv.setAttribute("class", className);
|
94
|
+
//do it twice for IE
|
95
|
+
this.runnerDiv.setAttribute("className", className);
|
96
|
+
var specs = runner.specs();
|
97
|
+
var specCount = 0;
|
98
|
+
for (var i = 0; i < specs.length; i++) {
|
99
|
+
if (this.specFilter(specs[i])) {
|
100
|
+
specCount++;
|
101
|
+
}
|
102
|
+
}
|
103
|
+
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
|
104
|
+
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
|
105
|
+
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
|
106
|
+
|
107
|
+
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
|
108
|
+
};
|
109
|
+
|
110
|
+
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
|
111
|
+
var results = suite.results();
|
112
|
+
var status = results.passed() ? 'passed' : 'failed';
|
113
|
+
if (results.totalCount === 0) { // todo: change this to check results.skipped
|
114
|
+
status = 'skipped';
|
115
|
+
}
|
116
|
+
this.suiteDivs[suite.id].className += " " + status;
|
117
|
+
};
|
118
|
+
|
119
|
+
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
|
120
|
+
if (this.logRunningSpecs) {
|
121
|
+
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
|
122
|
+
}
|
123
|
+
};
|
124
|
+
|
125
|
+
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
|
126
|
+
var results = spec.results();
|
127
|
+
var status = results.passed() ? 'passed' : 'failed';
|
128
|
+
if (results.skipped) {
|
129
|
+
status = 'skipped';
|
130
|
+
}
|
131
|
+
var specDiv = this.createDom('div', { className: 'spec ' + status },
|
132
|
+
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
|
133
|
+
this.createDom('a', {
|
134
|
+
className: 'description',
|
135
|
+
href: '?spec=' + encodeURIComponent(spec.getFullName()),
|
136
|
+
title: spec.getFullName()
|
137
|
+
}, spec.description));
|
138
|
+
|
139
|
+
|
140
|
+
var resultItems = results.getItems();
|
141
|
+
var messagesDiv = this.createDom('div', { className: 'messages' });
|
142
|
+
for (var i = 0; i < resultItems.length; i++) {
|
143
|
+
var result = resultItems[i];
|
144
|
+
|
145
|
+
if (result.type == 'log') {
|
146
|
+
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
|
147
|
+
} else if (result.type == 'expect' && result.passed && !result.passed()) {
|
148
|
+
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
|
149
|
+
|
150
|
+
if (result.trace.stack) {
|
151
|
+
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
if (messagesDiv.childNodes.length > 0) {
|
157
|
+
specDiv.appendChild(messagesDiv);
|
158
|
+
}
|
159
|
+
|
160
|
+
this.suiteDivs[spec.suite.id].appendChild(specDiv);
|
161
|
+
};
|
162
|
+
|
163
|
+
jasmine.TrivialReporter.prototype.log = function() {
|
164
|
+
var console = jasmine.getGlobal().console;
|
165
|
+
if (console && console.log) {
|
166
|
+
if (console.log.apply) {
|
167
|
+
console.log.apply(console, arguments);
|
168
|
+
} else {
|
169
|
+
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
|
170
|
+
}
|
171
|
+
}
|
172
|
+
};
|
173
|
+
|
174
|
+
jasmine.TrivialReporter.prototype.getLocation = function() {
|
175
|
+
return this.document.location;
|
176
|
+
};
|
177
|
+
|
178
|
+
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
|
179
|
+
var paramMap = {};
|
180
|
+
var params = this.getLocation().search.substring(1).split('&');
|
181
|
+
for (var i = 0; i < params.length; i++) {
|
182
|
+
var p = params[i].split('=');
|
183
|
+
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
|
184
|
+
}
|
185
|
+
|
186
|
+
if (!paramMap.spec) {
|
187
|
+
return true;
|
188
|
+
}
|
189
|
+
return spec.getFullName().indexOf(paramMap.spec) === 0;
|
190
|
+
};
|