~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Tools/BuildSlaveSupport/build.webkit.org-config/public_html/TestFailures/scripts/base.js

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2011 Google Inc. All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 * 1. Redistributions of source code must retain the above copyright
 
8
 *    notice, this list of conditions and the following disclaimer.
 
9
 * 2. Redistributions in binary form must reproduce the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer in the
 
11
 *    documentation and/or other materials provided with the distribution.
 
12
 *
 
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 
14
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
15
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
16
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 
17
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
19
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
20
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
21
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
22
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 
23
 * THE POSSIBILITY OF SUCH DAMAGE.
 
24
 */
 
25
 
 
26
var base = base || {};
 
27
 
 
28
(function(){
 
29
 
 
30
// Safari 5.1 lacks Function.prototype.bind.
 
31
if (!('bind' in Function.prototype)) {
 
32
    Function.prototype.bind = function(thisObject) {
 
33
        var method = this;
 
34
        var boundArguments = [];
 
35
        for (var i = 1; i < arguments.length; ++i) {
 
36
            boundArguments.push(arguments[i]);
 
37
        }
 
38
        return function() {
 
39
            var actualParameters = [];
 
40
            for (var i = 0; i < boundArguments.length; ++i) {
 
41
                actualParameters.push(boundArguments[i]);
 
42
            }
 
43
            for (var i = 0; i < arguments.length; ++i) {
 
44
                actualParameters.push(arguments[i]);
 
45
            }
 
46
            return method.apply(thisObject, actualParameters);
 
47
        }
 
48
    }
 
49
}
 
50
 
 
51
base.asInteger = function(stringOrInteger)
 
52
{
 
53
    if (typeof stringOrInteger == 'string')
 
54
        return parseInt(stringOrInteger);
 
55
    return stringOrInteger;
 
56
};
 
57
 
 
58
base.endsWith = function(string, suffix)
 
59
{
 
60
    if (suffix.length > string.length)
 
61
        return false;
 
62
    var expectedIndex = string.length - suffix.length;
 
63
    return string.lastIndexOf(suffix) == expectedIndex;
 
64
};
 
65
 
 
66
base.repeatString = function(string, count)
 
67
{
 
68
    return new Array(count + 1).join(string);
 
69
};
 
70
 
 
71
base.joinPath = function(parent, child)
 
72
{
 
73
    if (parent.length == 0)
 
74
        return child;
 
75
    return parent + '/' + child;
 
76
};
 
77
 
 
78
base.dirName = function(path)
 
79
{
 
80
    var directoryIndex = path.lastIndexOf('/');
 
81
    if (directoryIndex == -1)
 
82
        return path;
 
83
    return path.substr(0, directoryIndex);
 
84
};
 
85
 
 
86
base.trimExtension = function(url)
 
87
{
 
88
    var index = url.lastIndexOf('.');
 
89
    if (index == -1)
 
90
        return url;
 
91
    return url.substr(0, index);
 
92
}
 
93
 
 
94
base.uniquifyArray = function(array)
 
95
{
 
96
    var seen = {};
 
97
    var result = [];
 
98
    $.each(array, function(index, value) {
 
99
        if (seen[value])
 
100
            return;
 
101
        seen[value] = true;
 
102
        result.push(value);
 
103
    });
 
104
    return result;
 
105
};
 
106
 
 
107
base.flattenArray = function(arrayOfArrays)
 
108
{
 
109
    if (!arrayOfArrays.length)
 
110
        return [];
 
111
    return arrayOfArrays.reduce(function(left, right) {
 
112
        return left.concat(right);  
 
113
    });
 
114
};
 
115
 
 
116
base.filterDictionary = function(dictionary, predicate)
 
117
{
 
118
    var result = {};
 
119
 
 
120
    for (var key in dictionary) {
 
121
        if (predicate(key))
 
122
            result[key] = dictionary[key];
 
123
    }
 
124
 
 
125
    return result;
 
126
};
 
127
 
 
128
base.mapDictionary = function(dictionary, functor)
 
129
{
 
130
    var result = {};
 
131
 
 
132
    for (var key in dictionary) {
 
133
        var value = functor(dictionary[key]);
 
134
        if (typeof value !== 'undefined')
 
135
            result[key] = value;
 
136
    }
 
137
 
 
138
    return result;
 
139
};
 
140
 
 
141
base.filterTree = function(tree, isLeaf, predicate)
 
142
{
 
143
    var filteredTree = {};
 
144
 
 
145
    function walkSubtree(subtree, directory)
 
146
    {
 
147
        for (var childName in subtree) {
 
148
            var child = subtree[childName];
 
149
            var childPath = base.joinPath(directory, childName);
 
150
            if (isLeaf(child)) {
 
151
                if (predicate(child))
 
152
                    filteredTree[childPath] = child;
 
153
                continue;
 
154
            }
 
155
            walkSubtree(child, childPath);
 
156
        }
 
157
    }
 
158
 
 
159
    walkSubtree(tree, '');
 
160
    return filteredTree;
 
161
};
 
162
 
 
163
base.forEachDirectory = function(pathList, callback)
 
164
{
 
165
    var pathsByDirectory = {};
 
166
    pathList.forEach(function(path) {
 
167
        var directory = base.dirName(path);
 
168
        pathsByDirectory[directory] = pathsByDirectory[directory] || [];
 
169
        pathsByDirectory[directory].push(path);
 
170
    });
 
171
    Object.keys(pathsByDirectory).sort().forEach(function(directory) {
 
172
        var paths = pathsByDirectory[directory];
 
173
        callback(directory + ' (' + paths.length + ' tests)', paths);
 
174
    });
 
175
};
 
176
 
 
177
base.parseJSONP = function(jsonp)
 
178
{
 
179
    var startIndex = jsonp.indexOf('(') + 1;
 
180
    var endIndex = jsonp.lastIndexOf(')');
 
181
    return JSON.parse(jsonp.substr(startIndex, endIndex - startIndex));
 
182
};
 
183
 
 
184
base.RequestTracker = function(requestsInFlight, callback, args)
 
185
{
 
186
    this._requestsInFlight = requestsInFlight;
 
187
    this._callback = callback;
 
188
    this._args = args || [];
 
189
    this._tryCallback();
 
190
};
 
191
 
 
192
base.RequestTracker.prototype = {
 
193
    _tryCallback: function()
 
194
    {
 
195
        if (!this._requestsInFlight && this._callback)
 
196
            this._callback.apply(null, this._args);
 
197
    },
 
198
    requestComplete: function()
 
199
    {
 
200
        --this._requestsInFlight;
 
201
        this._tryCallback();
 
202
    }
 
203
}
 
204
 
 
205
base.callInParallel = function(functionList, callback)
 
206
{
 
207
    var requestTracker = new base.RequestTracker(functionList.length, callback);
 
208
 
 
209
    $.each(functionList, function(index, func) {
 
210
        func(function() {
 
211
            requestTracker.requestComplete();
 
212
        });
 
213
    });
 
214
};
 
215
 
 
216
base.callInSequence = function(func, argumentList, callback)
 
217
{
 
218
    var nextIndex = 0;
 
219
 
 
220
    function callNext()
 
221
    {
 
222
        if (nextIndex >= argumentList.length) {
 
223
            callback();
 
224
            return;
 
225
        }
 
226
 
 
227
        func(argumentList[nextIndex++], callNext);
 
228
    }
 
229
 
 
230
    callNext();
 
231
};
 
232
 
 
233
base.CallbackIterator = function(callback, listOfArgumentArrays)
 
234
{
 
235
    this._callback = callback;
 
236
    this._nextIndex = 0;
 
237
    this._listOfArgumentArrays = listOfArgumentArrays;
 
238
};
 
239
 
 
240
base.CallbackIterator.prototype.hasNext = function()
 
241
{
 
242
    return this._nextIndex < this._listOfArgumentArrays.length;
 
243
};
 
244
 
 
245
base.CallbackIterator.prototype.hasPrevious = function()
 
246
{
 
247
    return this._nextIndex - 2 >= 0;
 
248
};
 
249
 
 
250
base.CallbackIterator.prototype.callNext = function()
 
251
{
 
252
    if (!this.hasNext())
 
253
        return;
 
254
    var args = this._listOfArgumentArrays[this._nextIndex];
 
255
    this._nextIndex++;
 
256
    this._callback.apply(null, args);
 
257
};
 
258
 
 
259
base.CallbackIterator.prototype.callPrevious = function()
 
260
{
 
261
    if (!this.hasPrevious())
 
262
        return;
 
263
    var args = this._listOfArgumentArrays[this._nextIndex - 2];
 
264
    this._nextIndex--;
 
265
    this._callback.apply(null, args);
 
266
};
 
267
 
 
268
base.AsynchronousCache = function(fetch)
 
269
{
 
270
    this._fetch = fetch;
 
271
    this._dataCache = {};
 
272
    this._callbackCache = {};
 
273
};
 
274
 
 
275
base.AsynchronousCache.prototype.get = function(key, callback)
 
276
{
 
277
    var self = this;
 
278
 
 
279
    if (self._dataCache[key]) {
 
280
        // FIXME: Consider always calling callback asynchronously.
 
281
        callback(self._dataCache[key]);
 
282
        return;
 
283
    }
 
284
 
 
285
    if (key in self._callbackCache) {
 
286
        self._callbackCache[key].push(callback);
 
287
        return;
 
288
    }
 
289
 
 
290
    self._callbackCache[key] = [callback];
 
291
 
 
292
    self._fetch.call(null, key, function(data) {
 
293
        self._dataCache[key] = data;
 
294
 
 
295
        var callbackList = self._callbackCache[key];
 
296
        delete self._callbackCache[key];
 
297
 
 
298
        callbackList.forEach(function(cachedCallback) {
 
299
            cachedCallback(data);
 
300
        });
 
301
    });
 
302
};
 
303
 
 
304
base.AsynchronousCache.prototype.clear = function()
 
305
{
 
306
    this._dataCache = {};
 
307
    this._callbackCache = {};
 
308
}
 
309
 
 
310
/*
 
311
    Maintains a dictionary of items, tracking their updates and removing items that haven't been updated.
 
312
    An "update" is a call to the "update" method.
 
313
    To remove stale items, call the "remove" method. It will remove all
 
314
    items that have not been been updated since the last call of "remove".
 
315
*/
 
316
base.UpdateTracker = function()
 
317
{
 
318
    this._items = {};
 
319
    this._updated = {};
 
320
}
 
321
 
 
322
base.UpdateTracker.prototype = {
 
323
    /*
 
324
        Update an {key}/{item} pair. You can make the dictionary act as a set and
 
325
        skip the {item}, in which case the {key} is also the {item}.
 
326
    */
 
327
    update: function(key, object)
 
328
    {
 
329
        object = object || key;
 
330
        this._items[key] = object;
 
331
        this._updated[key] = 1;
 
332
    },
 
333
    exists: function(key)
 
334
    {
 
335
        return !!this.get(key);
 
336
    },
 
337
    get: function(key)
 
338
    {
 
339
        return this._items[key];
 
340
    },
 
341
    length: function()
 
342
    {
 
343
        return Object.keys(this._items).length;
 
344
    },
 
345
    /*
 
346
        Callback parameters are:
 
347
        - item
 
348
        - key
 
349
        - updated, which is true if the item was updated after last purge() call.
 
350
    */
 
351
    forEach: function(callback, thisObject)
 
352
    {
 
353
        if (!callback)
 
354
            return;
 
355
 
 
356
        Object.keys(this._items).sort().forEach(function(key) {
 
357
            var item = this._items[key];
 
358
            callback.call(thisObject || item, item, key, !!this._updated[key]);
 
359
        }, this);
 
360
    },
 
361
    purge: function(removeCallback, thisObject) {
 
362
        removeCallback = removeCallback || function() {};
 
363
        this.forEach(function(item, key, updated) {
 
364
            if (updated)
 
365
                return;
 
366
            removeCallback.call(thisObject || item, item);
 
367
            delete this._items[key];
 
368
        }, this);
 
369
        this._updated = {};
 
370
    }
 
371
}
 
372
 
 
373
// Based on http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/resources/shared/js/cr/ui.js
 
374
base.extends = function(base, prototype)
 
375
{
 
376
    var extended = function() {
 
377
        var element = typeof base == 'string' ? document.createElement(base) : base.call(this);
 
378
        extended.prototype.__proto__ = element.__proto__;
 
379
        element.__proto__ = extended.prototype;
 
380
        var singleton = element.init && element.init.apply(element, arguments);
 
381
        if (singleton)
 
382
            return singleton;
 
383
        return element;
 
384
    }
 
385
 
 
386
    extended.prototype = prototype;
 
387
    return extended;
 
388
}
 
389
 
 
390
function createRelativeTimeDescriptor(divisorInMilliseconds, unit)
 
391
{
 
392
    return function(delta) {
 
393
        var deltaInUnits = delta / divisorInMilliseconds;
 
394
        return (deltaInUnits).toFixed(0) + ' ' + unit + (deltaInUnits >= 1.5 ? 's' : '') + ' ago';
 
395
    }
 
396
}
 
397
 
 
398
var kMinuteInMilliseconds = 60 * 1000;
 
399
var kRelativeTimeSlots = [
 
400
    {
 
401
        maxMilliseconds: kMinuteInMilliseconds,
 
402
        describe: function(delta) { return 'Just now'; }
 
403
    },
 
404
    {
 
405
        maxMilliseconds: 60 * kMinuteInMilliseconds,
 
406
        describe: createRelativeTimeDescriptor(kMinuteInMilliseconds, 'minute')
 
407
    },
 
408
    {
 
409
        maxMilliseconds: 24 * 60 * kMinuteInMilliseconds,
 
410
        describe: createRelativeTimeDescriptor(60 * kMinuteInMilliseconds, 'hour')
 
411
    },
 
412
    {
 
413
        maxMilliseconds: Number.MAX_VALUE,
 
414
        describe: createRelativeTimeDescriptor(24 * 60 * kMinuteInMilliseconds, 'day')
 
415
    }
 
416
];
 
417
 
 
418
/*
 
419
    Represent time as descriptive text, relative to now and gradually decreasing in precision:
 
420
        delta < 1 minutes => Just Now
 
421
        delta < 60 minutes => X minute[s] ago
 
422
        delta < 24 hours => X hour[s] ago
 
423
        delta < inf => X day[s] ago
 
424
*/
 
425
base.relativizeTime = function(time)
 
426
{
 
427
    var result;
 
428
    var delta = new Date().getTime() - time;
 
429
    kRelativeTimeSlots.some(function(slot) {
 
430
        if (delta >= slot.maxMilliseconds)
 
431
            return false;
 
432
 
 
433
        result = slot.describe(delta);
 
434
        return true;
 
435
    });
 
436
    return result;
 
437
}
 
438
 
 
439
base.getURLParameter = function(name)
 
440
{
 
441
    var match = RegExp(name + '=' + '(.+?)(&|$)').exec(location.search);
 
442
    if (!match)
 
443
        return null;
 
444
    return decodeURI(match[1])
 
445
}
 
446
 
 
447
base.underscoredBuilderName = function(builderName)
 
448
{
 
449
    return builderName.replace(/[ .()]/g, '_');
 
450
}
 
451
 
 
452
base.createLinkNode = function(url, textContent, opt_target)
 
453
{
 
454
    var link = document.createElement('a');
 
455
    link.href = url;
 
456
    if (opt_target)
 
457
        link.target = opt_target;
 
458
    link.appendChild(document.createTextNode(textContent));
 
459
    return link;
 
460
}
 
461
 
 
462
})();