Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
842
gaia/apps/calendar/test/unit/common/calc_test.js
Executable file
842
gaia/apps/calendar/test/unit/common/calc_test.js
Executable file
|
|
@ -0,0 +1,842 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
/* global MockMozIntl */
|
||||
|
||||
require('/shared/test/unit/mocks/mock_moz_intl.js');
|
||||
|
||||
var Timespan = require('common/timespan');
|
||||
var Calc = require('common/calc');
|
||||
|
||||
//Worth noting that these tests will fail
|
||||
//in horrible ways outside of US timezone.
|
||||
suite('calendar/calc', function() {
|
||||
var subject, mocked = {};
|
||||
|
||||
setup(function() {
|
||||
subject = Calc;
|
||||
window.mozIntl = MockMozIntl;
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
var key;
|
||||
for (key in mocked) {
|
||||
if (mocked.hasOwnProperty(key)) {
|
||||
subject[key] = mocked[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function mock(fn, value) {
|
||||
if (!(fn in mocked)) {
|
||||
mocked[fn] = subject[fn];
|
||||
}
|
||||
subject[fn] = function() {
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
suite('#isOnlyDate', function() {
|
||||
function verify(date, message, isTrue=true) {
|
||||
test(message + ' ' + date.toString() + ' === ' + isTrue, function() {
|
||||
assert.equal(
|
||||
subject.isOnlyDate(date),
|
||||
isTrue,
|
||||
message
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
verify(new Date(2012, 1), 'month');
|
||||
|
||||
verify(
|
||||
new Date(2012, 1, 1),
|
||||
'YYYY:DD:MM'
|
||||
);
|
||||
|
||||
verify(
|
||||
new Date(2012, 1, 1, 1),
|
||||
'hour',
|
||||
false
|
||||
);
|
||||
|
||||
verify(
|
||||
new Date(2012, 1, 1, 0, 1),
|
||||
'minute',
|
||||
false
|
||||
);
|
||||
|
||||
verify(
|
||||
new Date(2012, 1, 1, 0, 0, 1),
|
||||
'second',
|
||||
false
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
suite('#dayOfWeekFromStartDay', function() {
|
||||
test('sunday', function() {
|
||||
subject.startDay = 0;
|
||||
|
||||
var expected = [
|
||||
['sun', 0, 0],
|
||||
['mon', 1, 1],
|
||||
['tue', 2, 2],
|
||||
['wed', 3, 3],
|
||||
['thu', 4, 4],
|
||||
['fri', 5, 5],
|
||||
['sat', 6, 6]
|
||||
];
|
||||
|
||||
expected.forEach(function(line) {
|
||||
var [name, date, numeric] = line;
|
||||
assert.equal(
|
||||
subject.dayOfWeekFromStartDay(date),
|
||||
numeric,
|
||||
name
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('Monday', function() {
|
||||
subject.startDay = 1;
|
||||
|
||||
var expected = [
|
||||
['mon', 1, 0],
|
||||
['tue', 2, 1],
|
||||
['wed', 3, 2],
|
||||
['thu', 4, 3],
|
||||
['fri', 5, 4],
|
||||
['sat', 6, 5],
|
||||
['sun', 0, 6]
|
||||
];
|
||||
|
||||
expected.forEach(function(line) {
|
||||
var [name, date, numeric] = line;
|
||||
assert.equal(
|
||||
subject.dayOfWeekFromStartDay(date),
|
||||
numeric,
|
||||
name
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('Saturday', function() {
|
||||
subject.startDay = 6;
|
||||
|
||||
var expected = [
|
||||
['sat', 6, 0],
|
||||
['sun', 0, 1],
|
||||
['mon', 1, 2],
|
||||
['tue', 2, 3],
|
||||
['wed', 3, 4],
|
||||
['thu', 4, 5],
|
||||
['fri', 5, 6]
|
||||
];
|
||||
|
||||
expected.forEach(function(line) {
|
||||
var [name, date, numeric] = line;
|
||||
assert.equal(
|
||||
subject.dayOfWeekFromStartDay(date),
|
||||
numeric,
|
||||
name
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('#dayOfWeekFromMonday', function() {
|
||||
var expected = [
|
||||
['mon', 1, 0],
|
||||
['tue', 2, 1],
|
||||
['wed', 3, 2],
|
||||
['thu', 4, 3],
|
||||
['fri', 5, 4],
|
||||
['sat', 6, 5],
|
||||
['sun', 0, 6]
|
||||
];
|
||||
|
||||
expected.forEach(function(line) {
|
||||
var [name, date, numeric] = line;
|
||||
assert.equal(
|
||||
subject.dayOfWeekFromMonday(date),
|
||||
numeric,
|
||||
name
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('#dayOfWeek', function() {
|
||||
var realStartDay;
|
||||
var date = new Date(2012, 0, 1); // 2012-01-01 is a Sunday
|
||||
|
||||
suiteSetup(function() {
|
||||
realStartDay = subject.startDay;
|
||||
});
|
||||
|
||||
suiteTeardown(function() {
|
||||
subject.startDay = realStartDay;
|
||||
});
|
||||
|
||||
test('weekStartDay = 0', function() {
|
||||
subject.startDay = 0; // week starts on Sunday => Sunday is day 0
|
||||
assert.equal(
|
||||
subject.dayOfWeek(date),
|
||||
0
|
||||
);
|
||||
});
|
||||
|
||||
test('weekStartDay = 1', function() {
|
||||
subject.startDay = 1; // week starts on Monday => Sunday is day 6
|
||||
assert.equal(
|
||||
subject.dayOfWeek(date),
|
||||
6
|
||||
);
|
||||
});
|
||||
|
||||
test('weekStartDay = 6', function() {
|
||||
subject.startDay = 6; // week starts on Saturday => Sunday is day 1
|
||||
assert.equal(
|
||||
subject.dayOfWeek(date),
|
||||
1
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('handle localization events', function() {
|
||||
var firstDayOfTheWeek = 0;
|
||||
|
||||
suiteSetup(function() {
|
||||
sinon.stub(window.mozIntl, 'calendarInfo', function(token) {
|
||||
return Promise.resolve(firstDayOfTheWeek);
|
||||
});
|
||||
});
|
||||
|
||||
suiteTeardown(function() {
|
||||
window.mozIntl.calendarInfo.restore();
|
||||
});
|
||||
|
||||
test('firstDayOfTheWeek = 1', function(done) {
|
||||
firstDayOfTheWeek = 1;
|
||||
window.dispatchEvent(new window.Event('localized'));
|
||||
Promise.resolve().then(() => {
|
||||
assert.equal(subject.startDay, 1, 'week starts on Monday');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('firstDayOfTheWeek = 6', function(done) {
|
||||
firstDayOfTheWeek = 6;
|
||||
window.dispatchEvent(new window.Event('localized'));
|
||||
Promise.resolve().then(() => {
|
||||
assert.equal(subject.startDay, 6, 'week starts on Saturday');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('firstDayOfTheWeek = 0', function(done) {
|
||||
firstDayOfTheWeek = 0;
|
||||
window.dispatchEvent(new window.Event('localized'));
|
||||
Promise.resolve().then(() => {
|
||||
assert.equal(subject.startDay, 0, 'week starts on Sunday');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('#spanOfMonth', function() {
|
||||
|
||||
function time(year, month, day, hour, min) {
|
||||
var date = new Date(
|
||||
year,
|
||||
month || 0,
|
||||
day || 1,
|
||||
hour || 0,
|
||||
min || 0
|
||||
);
|
||||
return v(date);
|
||||
}
|
||||
|
||||
function v(date) {
|
||||
return date.valueOf();
|
||||
}
|
||||
|
||||
test('5 week month', function() {
|
||||
var date = new Date(2012, 3, 1, 5, 1);
|
||||
var range = subject.spanOfMonth(date);
|
||||
|
||||
assert.equal(
|
||||
time(2012, 3, 1),
|
||||
range.start
|
||||
);
|
||||
|
||||
var end = new Date(2012, 4, 6);
|
||||
end.setMilliseconds(-1);
|
||||
|
||||
assert.equal(
|
||||
range.end,
|
||||
v(end)
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
test('6 week month', function() {
|
||||
var date = new Date(2012, 11, 1);
|
||||
var range = subject.spanOfMonth(date);
|
||||
|
||||
assert.equal(
|
||||
time(2012, 10, 25),
|
||||
range.start
|
||||
);
|
||||
|
||||
var end = new Date(2013, 0, 6);
|
||||
end.setMilliseconds(-1);
|
||||
|
||||
assert.equal(
|
||||
range.end,
|
||||
v(end)
|
||||
);
|
||||
});
|
||||
|
||||
test('4 week month', function() {
|
||||
var date = new Date(2009, 1, 1);
|
||||
var range = subject.spanOfMonth(date);
|
||||
|
||||
var end = new Date(2009, 2, 1);
|
||||
end.setMilliseconds(-1);
|
||||
|
||||
assert.equal(
|
||||
range.end,
|
||||
v(end)
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('#dateToTransport', function() {
|
||||
|
||||
test('ICAL date', function() {
|
||||
var date = new Date(2012, 0, 1, 11);
|
||||
var utc = Date.UTC(
|
||||
date.getFullYear(),
|
||||
date.getMonth(),
|
||||
date.getDate(),
|
||||
date.getHours(),
|
||||
date.getMinutes(),
|
||||
date.getSeconds(),
|
||||
date.getMilliseconds()
|
||||
);
|
||||
|
||||
var expected = {
|
||||
tzid: subject.FLOATING,
|
||||
utc: utc,
|
||||
offset: 0,
|
||||
isDate: true
|
||||
};
|
||||
|
||||
assert.deepEqual(
|
||||
subject.dateToTransport(date, null, true),
|
||||
expected
|
||||
);
|
||||
});
|
||||
|
||||
test('floating tz', function() {
|
||||
var date = new Date(2012, 0, 1, 11, 1, 7);
|
||||
var utc = Date.UTC(
|
||||
date.getFullYear(),
|
||||
date.getMonth(),
|
||||
date.getDate(),
|
||||
date.getHours(),
|
||||
date.getMinutes(),
|
||||
date.getSeconds(),
|
||||
date.getMilliseconds()
|
||||
);
|
||||
|
||||
var expected = {
|
||||
tzid: subject.FLOATING,
|
||||
utc: utc,
|
||||
offset: 0
|
||||
};
|
||||
|
||||
assert.deepEqual(
|
||||
subject.dateToTransport(date, subject.FLOATING),
|
||||
expected
|
||||
);
|
||||
});
|
||||
|
||||
test('utc', function() {
|
||||
var date = new Date(2012, 0, 1, 11, 1);
|
||||
var utc = Date.UTC(2012, 0, 1, 11, 1);
|
||||
var offset = utc - date;
|
||||
|
||||
var expected = {
|
||||
offset: offset,
|
||||
utc: utc
|
||||
};
|
||||
|
||||
assert.deepEqual(
|
||||
subject.dateToTransport(date),
|
||||
expected
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('#getUTC', function() {
|
||||
test('utc - conversion', function() {
|
||||
var date = new Date(2012, 9, 1, 7, 11);
|
||||
|
||||
assert.notEqual(
|
||||
date,
|
||||
subject.getUTC(date)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('#dateFromTransport', function() {
|
||||
|
||||
test('utc - DST', function() {
|
||||
// NOTE: I don't expect this test to fail
|
||||
// in other timezones but it relies on
|
||||
// hard coded DST info to verify that DST
|
||||
// actually works in PST.
|
||||
|
||||
var date = new Date(2012, 9, 1, 7, 11);
|
||||
var data = subject.dateToTransport(date);
|
||||
|
||||
assert.deepEqual(
|
||||
subject.dateFromTransport(data),
|
||||
date
|
||||
);
|
||||
});
|
||||
|
||||
test('utc - standard', function() {
|
||||
var expected = new Date(2012, 0, 1, 0, 5);
|
||||
var data = subject.dateToTransport(expected);
|
||||
|
||||
assert.deepEqual(
|
||||
subject.dateFromTransport(data),
|
||||
expected
|
||||
);
|
||||
});
|
||||
|
||||
test('floating', function() {
|
||||
var expected = new Date(2012, 0, 8, 9, 10);
|
||||
|
||||
var data = subject.dateToTransport(
|
||||
expected, subject.FLOATING
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
subject.dateFromTransport(data),
|
||||
expected
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('#getWeekStartDate', function() {
|
||||
// we are testing for first week of Aug 2012
|
||||
var expected = new Date(2012, 6, 29);
|
||||
|
||||
function matches(given) {
|
||||
assert.equal(
|
||||
subject.getWeekStartDate(given).valueOf(),
|
||||
expected.valueOf()
|
||||
);
|
||||
}
|
||||
|
||||
test('when given middle', function() {
|
||||
matches(new Date(2012, 7, 2));
|
||||
});
|
||||
|
||||
test('when given start', function() {
|
||||
matches(new Date(2012, 6, 29));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('#spanOfDay', function() {
|
||||
|
||||
var date = new Date(2012, 1, 1, 10, 33);
|
||||
|
||||
test('include time', function() {
|
||||
var end = new Date(
|
||||
date.getFullYear(),
|
||||
date.getMonth(),
|
||||
date.getDate() + 1
|
||||
);
|
||||
|
||||
var out = subject.spanOfDay(date, true);
|
||||
|
||||
assert.deepEqual(out, new Timespan(date, end));
|
||||
});
|
||||
|
||||
test('ignore time', function() {
|
||||
var start = new Date(
|
||||
date.getFullYear(),
|
||||
date.getMonth(),
|
||||
date.getDate()
|
||||
);
|
||||
|
||||
var end = new Date(start.valueOf());
|
||||
end.setDate(end.getDate() + 1);
|
||||
|
||||
var out = subject.spanOfDay(date);
|
||||
|
||||
assert.deepEqual(out, new Timespan(start, end));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('#hourDiff', function() {
|
||||
var start = new Date(2012, 0, 5);
|
||||
var end = new Date(2012, 0, 7);
|
||||
|
||||
var expected = 48;
|
||||
var out = subject.hourDiff(start, end);
|
||||
|
||||
assert.equal(out, expected);
|
||||
});
|
||||
|
||||
suite('#daysBetween', function() {
|
||||
//Nov 29th 2012
|
||||
var start = new Date(2012, 10, 29, 2);
|
||||
// Dec 2nd 2012
|
||||
var end = new Date(2012, 11, 2, 5);
|
||||
|
||||
test('same day', function() {
|
||||
var end = new Date(
|
||||
start.getFullYear(),
|
||||
start.getMonth(),
|
||||
start.getDate(),
|
||||
start.getHours() + 1
|
||||
);
|
||||
|
||||
var expected = new Date(
|
||||
start.getFullYear(),
|
||||
start.getMonth(),
|
||||
start.getDate()
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
subject.daysBetween(start, end),
|
||||
[expected]
|
||||
);
|
||||
});
|
||||
|
||||
test('include time', function() {
|
||||
var expected = [
|
||||
start,
|
||||
new Date(2012, 10, 30),
|
||||
new Date(2012, 11, 1),
|
||||
end
|
||||
];
|
||||
|
||||
assert.deepEqual(
|
||||
subject.daysBetween(start, end, true),
|
||||
expected
|
||||
);
|
||||
});
|
||||
|
||||
test('exclude time', function() {
|
||||
var expected = [
|
||||
new Date(2012, 10, 29),
|
||||
new Date(2012, 10, 30),
|
||||
new Date(2012, 11, 1),
|
||||
new Date(2012, 11, 2)
|
||||
];
|
||||
|
||||
assert.deepEqual(
|
||||
subject.daysBetween(start, end),
|
||||
expected
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('#getWeekEndDate', function() {
|
||||
// we are testing for first week of Aug 2012
|
||||
var expected = new Date(2012, 7, 4, 23, 59, 59, 999);
|
||||
|
||||
function matches(given) {
|
||||
assert.equal(
|
||||
subject.getWeekEndDate(given).valueOf(),
|
||||
expected.valueOf()
|
||||
);
|
||||
}
|
||||
|
||||
test('when given middle', function() {
|
||||
matches(new Date(2012, 7, 2));
|
||||
});
|
||||
|
||||
test('when given start', function() {
|
||||
matches(new Date(2012, 6, 29));
|
||||
});
|
||||
});
|
||||
|
||||
suite('#isSameDate', function() {
|
||||
|
||||
test('same day', function() {
|
||||
assert.isTrue(subject.isSameDate(
|
||||
new Date(2012, 1, 1, 8),
|
||||
new Date(2012, 1, 1, 23)
|
||||
));
|
||||
});
|
||||
|
||||
test('same day different month', function() {
|
||||
assert.isFalse(subject.isSameDate(
|
||||
new Date(2012, 2, 1, 8),
|
||||
new Date(2012, 1, 1, 8)
|
||||
));
|
||||
});
|
||||
});
|
||||
|
||||
suite('#isToday', function() {
|
||||
test('when given is today', function() {
|
||||
var result = subject.isToday(new Date());
|
||||
|
||||
assert.isTrue(result, 'should be true when given today');
|
||||
});
|
||||
|
||||
test('when given is not today', function() {
|
||||
var now = new Date();
|
||||
now.setDate(now.getDate() - 1);
|
||||
var result = subject.isToday(now);
|
||||
|
||||
assert.isFalse(result, 'should be false when given is not today');
|
||||
});
|
||||
});
|
||||
|
||||
suite('#isPast', function() {
|
||||
test('when date is passed', function() {
|
||||
var date = new Date();
|
||||
date.setTime(Date.now() - 1000);
|
||||
var result = subject.isPast(date);
|
||||
|
||||
assert.isTrue(result, 'should be true when given is in the past');
|
||||
});
|
||||
|
||||
test('when given is in the future', function() {
|
||||
var date = new Date();
|
||||
date.setTime(Date.now() + 100);
|
||||
var result = subject.isPast(date);
|
||||
|
||||
assert.isFalse(result, 'should return false when date is in the future');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('#isFuture', function() {
|
||||
test('when date is passed', function() {
|
||||
var date = new Date();
|
||||
date.setTime(Date.now() - 100);
|
||||
var result = subject.isFuture(date);
|
||||
|
||||
assert.isFalse(result);
|
||||
});
|
||||
|
||||
test('when given is in the future', function() {
|
||||
var date = new Date(Date.now() + 100);
|
||||
var result = subject.isFuture(date);
|
||||
|
||||
assert.isTrue(result);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('#dateFromId', function() {
|
||||
var id,
|
||||
date = new Date(2012, 7, 3);
|
||||
|
||||
suite('from day', function() {
|
||||
setup(function() {
|
||||
id = subject.getDayId(date);
|
||||
});
|
||||
|
||||
test('id to date', function() {
|
||||
assert.deepEqual(
|
||||
subject.dateFromId(id),
|
||||
date
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
suite('from month', function() {
|
||||
setup(function() {
|
||||
id = subject.getMonthId(date);
|
||||
});
|
||||
|
||||
test('id to date', function() {
|
||||
assert.deepEqual(
|
||||
subject.dateFromId(id),
|
||||
new Date(2012, 7, 1)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('#getWeeksDays', function() {
|
||||
|
||||
test('starting from monday', function() {
|
||||
//starts on thursday
|
||||
var start = new Date(2012, 10, 1);
|
||||
|
||||
//expected days by their getDayId
|
||||
var expected = [
|
||||
'd-2012-9-28',
|
||||
'd-2012-9-29',
|
||||
'd-2012-9-30',
|
||||
'd-2012-9-31',
|
||||
'd-2012-10-1',
|
||||
'd-2012-10-2',
|
||||
'd-2012-10-3'
|
||||
];
|
||||
|
||||
var result = subject.getWeeksDays(start).map(
|
||||
subject.getDayId
|
||||
);
|
||||
|
||||
assert.deepEqual(result, expected);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('#getDayId', function() {
|
||||
var result = subject.getDayId(
|
||||
new Date(2012, 3, 7)
|
||||
);
|
||||
|
||||
assert.equal(result, 'd-2012-3-7');
|
||||
});
|
||||
|
||||
test('#getMonthId', function() {
|
||||
var result = subject.getMonthId(
|
||||
new Date(2012, 3, 7)
|
||||
);
|
||||
|
||||
assert.equal(result, 'm-2012-3');
|
||||
});
|
||||
|
||||
suite('#relativeState', function() {
|
||||
|
||||
setup(function() {
|
||||
mock('isToday', false);
|
||||
});
|
||||
|
||||
test('when in the past', function() {
|
||||
mock('isPast', true);
|
||||
var state = subject.relativeState(
|
||||
new Date(1991, 1, 1),
|
||||
new Date(1991, 1, 1)
|
||||
);
|
||||
|
||||
assert.equal(state, subject.PAST);
|
||||
});
|
||||
|
||||
test('when in the future', function() {
|
||||
mock('isPast', false);
|
||||
var state = subject.relativeState(
|
||||
new Date(1991, subject.today.getMonth(), 1),
|
||||
new Date(1991, subject.today.getMonth(), 1)
|
||||
);
|
||||
assert.equal(state, subject.FUTURE);
|
||||
});
|
||||
|
||||
test('when is in a different month in the past', function() {
|
||||
mock('isPast', true);
|
||||
|
||||
var state = subject.relativeState(
|
||||
new Date(1991, subject.today.getMonth() - 1, 1),
|
||||
new Date(1991, subject.today.getMonth(), 1)
|
||||
);
|
||||
|
||||
assert.include(state, subject.PAST);
|
||||
assert.include(state, subject.OTHER_MONTH);
|
||||
});
|
||||
|
||||
test('when is in a different month in the future', function() {
|
||||
mock('isPast', false);
|
||||
|
||||
var state = subject.relativeState(
|
||||
new Date(1991, subject.today.getMonth() + 1, 1),
|
||||
new Date(1991, subject.today.getMonth(), 1)
|
||||
);
|
||||
|
||||
assert.include(state, subject.FUTURE);
|
||||
assert.include(state, subject.OTHER_MONTH);
|
||||
});
|
||||
|
||||
|
||||
test('when is today', function() {
|
||||
mock('isToday', true);
|
||||
var state = subject.relativeState(new Date(1991, 1, 1));
|
||||
|
||||
assert.equal(state, subject.PRESENT);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('#isAllDay', function() {
|
||||
test('full day', function() {
|
||||
assert.isTrue(subject.isAllDay(
|
||||
new Date(2014, 9, 5),
|
||||
new Date(2014, 9, 5),
|
||||
new Date(2014, 9, 6)
|
||||
));
|
||||
});
|
||||
|
||||
test('not start of the day', function() {
|
||||
assert.isFalse(subject.isAllDay(
|
||||
new Date(2014, 9, 5),
|
||||
new Date(2014, 9, 5, 5),
|
||||
new Date(2014, 9, 6)
|
||||
));
|
||||
});
|
||||
|
||||
test('longer than a full day', function() {
|
||||
assert.isTrue(subject.isAllDay(
|
||||
new Date(2014, 9, 5),
|
||||
new Date(2014, 9, 5),
|
||||
new Date(2014, 9, 6, 5)
|
||||
));
|
||||
});
|
||||
|
||||
test('multiple days', function() {
|
||||
assert.isTrue(subject.isAllDay(
|
||||
new Date(2014, 9, 5),
|
||||
new Date(2014, 9, 5),
|
||||
new Date(2014, 9, 16)
|
||||
));
|
||||
assert.isTrue(subject.isAllDay(
|
||||
new Date(2014, 9, 8),
|
||||
new Date(2014, 9, 5),
|
||||
new Date(2014, 9, 16)
|
||||
));
|
||||
});
|
||||
|
||||
test('same date', function() {
|
||||
// yahoo uses same start/end dates for recurring all day events
|
||||
assert.isTrue(subject.isAllDay(
|
||||
new Date(2014, 9, 5),
|
||||
new Date(2014, 9, 5),
|
||||
new Date(2014, 9, 5)
|
||||
));
|
||||
});
|
||||
});
|
||||
|
||||
test('#monthStart', function() {
|
||||
assert.deepEqual(
|
||||
Calc.monthStart(new Date(2014, 10, 1)),
|
||||
new Date(2014, 10, 1),
|
||||
'first day'
|
||||
);
|
||||
assert.deepEqual(
|
||||
Calc.monthStart(new Date(2014, 10, 12)),
|
||||
new Date(2014, 10, 1),
|
||||
'middle'
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
12
gaia/apps/calendar/test/unit/common/compare_test.js
Executable file
12
gaia/apps/calendar/test/unit/common/compare_test.js
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var compare = require('common/compare');
|
||||
|
||||
test('compare', function() {
|
||||
assert.equal(compare(0, 1), -1);
|
||||
assert.equal(compare(1, 0), 1);
|
||||
assert.equal(compare(10, 10), 0);
|
||||
});
|
||||
|
||||
});
|
||||
25
gaia/apps/calendar/test/unit/common/error_test.js
Executable file
25
gaia/apps/calendar/test/unit/common/error_test.js
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var CalendarError = require('common/error');
|
||||
|
||||
suite('errors', function() {
|
||||
function verify(symbol) {
|
||||
test(symbol, function() {
|
||||
var detail = {};
|
||||
assert.ok(CalendarError[symbol], 'CalendarError.' + symbol);
|
||||
var err = new CalendarError[symbol](detail);
|
||||
assert.equal(detail, err.detail, 'uses detail');
|
||||
assert.ok(err.l10nID, 'has l10nID');
|
||||
assert.ok(err.name, 'has name');
|
||||
});
|
||||
}
|
||||
|
||||
([
|
||||
'Authentication',
|
||||
'InvalidServer',
|
||||
'ServerFailure'
|
||||
]).forEach(verify);
|
||||
});
|
||||
|
||||
});
|
||||
22
gaia/apps/calendar/test/unit/common/next_tick_test.js
Executable file
22
gaia/apps/calendar/test/unit/common/next_tick_test.js
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var nextTick = require('common/next_tick');
|
||||
|
||||
test('nextTick', function(done) {
|
||||
var inc = 0;
|
||||
nextTick(() => {
|
||||
assert.equal(inc, 1);
|
||||
|
||||
nextTick(() => {
|
||||
assert.equal(inc, 2);
|
||||
nextTick(done);
|
||||
});
|
||||
|
||||
inc++;
|
||||
});
|
||||
|
||||
inc = 1;
|
||||
});
|
||||
|
||||
});
|
||||
63
gaia/apps/calendar/test/unit/common/object_test.js
Executable file
63
gaia/apps/calendar/test/unit/common/object_test.js
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var object = require('common/object');
|
||||
|
||||
suite('Object', function() {
|
||||
var subject;
|
||||
|
||||
setup(function() {
|
||||
subject = object;
|
||||
});
|
||||
|
||||
test('#filter', function() {
|
||||
assert.deepEqual(
|
||||
subject.filter(
|
||||
{
|
||||
'0': 'red',
|
||||
'1': 'orange',
|
||||
'2': 'yellow',
|
||||
'3': 'green',
|
||||
'4': 'blue',
|
||||
'5': 'violet'
|
||||
},
|
||||
(key, value) => {
|
||||
return value === 'red' || parseInt(key, 10) % 2 === 1;
|
||||
}
|
||||
),
|
||||
[
|
||||
'red',
|
||||
'orange',
|
||||
'green',
|
||||
'violet'
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('#forEach', function() {
|
||||
var input = { a: 'b', p: 'q', x: 'y' };
|
||||
var result = {};
|
||||
subject.forEach(input, (key, value) => {
|
||||
result[key] = value;
|
||||
});
|
||||
|
||||
assert.deepEqual(input, result);
|
||||
});
|
||||
|
||||
test('#map', function() {
|
||||
var input = { a: 'b', p: 'q', x: 'y' };
|
||||
var result = subject.map(input, (key, value) => {
|
||||
return value;
|
||||
});
|
||||
|
||||
assert.deepEqual(result, ['b', 'q', 'y']);
|
||||
});
|
||||
|
||||
test('#values', function() {
|
||||
var input = { a: 'b', p: 'q', x: 'y' };
|
||||
var result = subject.values(input);
|
||||
assert.deepEqual(result, ['b', 'q', 'y']);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
10
gaia/apps/calendar/test/unit/common/presets_test.js
Executable file
10
gaia/apps/calendar/test/unit/common/presets_test.js
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var presets = require('common/presets');
|
||||
|
||||
test('list', function() {
|
||||
assert.instanceOf(presets, Object);
|
||||
});
|
||||
|
||||
});
|
||||
146
gaia/apps/calendar/test/unit/common/promise_test.js
Executable file
146
gaia/apps/calendar/test/unit/common/promise_test.js
Executable file
|
|
@ -0,0 +1,146 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var promise = require('common/promise');
|
||||
|
||||
function errorOrFive(shouldError, callback) {
|
||||
var error;
|
||||
if (shouldError) {
|
||||
error = new Error('You told me to error!');
|
||||
} else {
|
||||
error = null;
|
||||
}
|
||||
|
||||
return callback(error, !shouldError && 5);
|
||||
}
|
||||
|
||||
suite('denodeify', function() {
|
||||
var subject;
|
||||
|
||||
setup(function() {
|
||||
subject = promise.denodeify(errorOrFive);
|
||||
});
|
||||
|
||||
test('node-style error', function(done) {
|
||||
subject(true /* shouldError */, function(error) {
|
||||
assert.instanceOf(error, Error);
|
||||
assert.strictEqual(error.message, 'You told me to error!');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('node-style without error', function(done) {
|
||||
subject(false /* shouldError */, function(error, result) {
|
||||
assert.isNull(error);
|
||||
assert.strictEqual(result, 5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('promise with error', function(done) {
|
||||
subject(true /* shouldError */)
|
||||
.catch(function(error) {
|
||||
assert.instanceOf(error, Error);
|
||||
assert.strictEqual(error.message, 'You told me to error!');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('promise without error', function(done) {
|
||||
subject(false /* shouldError */)
|
||||
.then(function(value) {
|
||||
assert.strictEqual(value, 5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('no callback and no promise', function() {
|
||||
// Should not hiccup.
|
||||
subject(false /* shouldError */);
|
||||
});
|
||||
});
|
||||
|
||||
function SlowCalculator() {
|
||||
this.currentValue = 0;
|
||||
promise.denodeifyAll(this, [
|
||||
'add',
|
||||
'multiply'
|
||||
]);
|
||||
}
|
||||
|
||||
SlowCalculator.prototype = {
|
||||
add: function(x, callback) {
|
||||
var error = null;
|
||||
if (typeof x !== 'number') {
|
||||
error = new Error('Can only add numbers!');
|
||||
}
|
||||
|
||||
this.currentValue += x;
|
||||
setTimeout(function() {
|
||||
callback(error, error || this.currentValue);
|
||||
}.bind(this), 10);
|
||||
},
|
||||
|
||||
multiply: function(x, callback) {
|
||||
var error = null;
|
||||
if (typeof x !== 'number') {
|
||||
error = new Error('Can only multiply numbers!');
|
||||
}
|
||||
|
||||
this.currentValue *= x;
|
||||
setTimeout(function() {
|
||||
callback(error, error || this.currentValue);
|
||||
}.bind(this), 10);
|
||||
}
|
||||
};
|
||||
|
||||
suite('denodeifyAll', function() {
|
||||
var subject;
|
||||
|
||||
setup(function() {
|
||||
subject = new SlowCalculator();
|
||||
});
|
||||
|
||||
test('node-style error', function(done) {
|
||||
subject.multiply('lolcats', function(error) {
|
||||
assert.instanceOf(error, Error);
|
||||
assert.strictEqual(error.message, 'Can only multiply numbers!');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('node-style without error', function(done) {
|
||||
subject.add(5, function(error, result) {
|
||||
assert.isNull(error);
|
||||
assert.strictEqual(result, 5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('promise with error', function(done) {
|
||||
subject.add(/\s+/).catch(function(error) {
|
||||
assert.instanceOf(error, Error);
|
||||
assert.strictEqual(error.message, 'Can only add numbers!');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('promise without error', function(done) {
|
||||
subject.add(9)
|
||||
.then(function(value) {
|
||||
assert.strictEqual(value, 9);
|
||||
return subject.multiply(8);
|
||||
})
|
||||
.then(function(value) {
|
||||
assert.strictEqual(value, 72);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('no callback and no promise', function() {
|
||||
// Should not hiccup.
|
||||
subject.multiply(3.14);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
87
gaia/apps/calendar/test/unit/common/responder_test.js
Executable file
87
gaia/apps/calendar/test/unit/common/responder_test.js
Executable file
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* Responder is actually an downstream of test-agent
|
||||
* porting the handleEvent thing over here for now
|
||||
* to eventually be moved back with the other tweaks.
|
||||
*/
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var Responder = require('common/responder');
|
||||
|
||||
suite('responder', function() {
|
||||
var subject;
|
||||
|
||||
setup(function() {
|
||||
subject = new Responder();
|
||||
});
|
||||
|
||||
test('multi arg responder', function() {
|
||||
var calledWith;
|
||||
|
||||
subject.on('test', function() {
|
||||
calledWith = Array.slice(arguments);
|
||||
});
|
||||
|
||||
subject.respond(['test', 'one', 'two', 'three']);
|
||||
assert.deepEqual(calledWith, ['one', 'two', 'three']);
|
||||
});
|
||||
|
||||
suite('handleEvent', function() {
|
||||
test('object', function() {
|
||||
var events = {};
|
||||
var target = {
|
||||
// mimic the actual eventTarget api's
|
||||
handleEvent: function(e) {
|
||||
var type = e.type;
|
||||
|
||||
if (!(type in events)) {
|
||||
events[type] = [];
|
||||
}
|
||||
|
||||
events[type].push(e.data);
|
||||
}
|
||||
};
|
||||
|
||||
subject.on('foo', target);
|
||||
subject.on('foo', target);
|
||||
subject.on('bar', target);
|
||||
|
||||
subject.emit('foo', 1);
|
||||
subject.emit('bar', 1, 2);
|
||||
|
||||
assert.deepEqual(
|
||||
events.foo,
|
||||
[[1], [1]]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
events.bar,
|
||||
[[1, 2]]
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('#emitWhenListener', function(done) {
|
||||
subject.emitWhenListener('foo', 'bar');
|
||||
subject.emitWhenListener('foo', 'baz');
|
||||
|
||||
// Let the event loop tick before listening for the 'foo' topic.
|
||||
setTimeout(() => {
|
||||
var count = 0;
|
||||
subject.on('foo', function onFoo(word) {
|
||||
if (count === 0) {
|
||||
assert.equal(word, 'bar');
|
||||
count++;
|
||||
return;
|
||||
}
|
||||
|
||||
assert.equal(word, 'baz');
|
||||
subject.off('foo', onFoo);
|
||||
done();
|
||||
});
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
358
gaia/apps/calendar/test/unit/common/timespan_test.js
Executable file
358
gaia/apps/calendar/test/unit/common/timespan_test.js
Executable file
|
|
@ -0,0 +1,358 @@
|
|||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var Calc = require('common/calc');
|
||||
var Timespan = require('common/timespan');
|
||||
|
||||
suite('timespan', function() {
|
||||
var subject;
|
||||
var startDate;
|
||||
var endDate;
|
||||
|
||||
setup(function() {
|
||||
startDate = new Date(2012, 1, 1);
|
||||
endDate = new Date(2012, 12, 1);
|
||||
|
||||
subject = new Timespan(
|
||||
startDate,
|
||||
endDate
|
||||
);
|
||||
});
|
||||
|
||||
test('initializer', function() {
|
||||
assert.equal(
|
||||
subject.start,
|
||||
startDate.valueOf()
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
subject.end,
|
||||
endDate.valueOf()
|
||||
);
|
||||
});
|
||||
|
||||
test('#isEqual', function() {
|
||||
var span = new Timespan(
|
||||
new Date(2012, 1, 1),
|
||||
new Date(2012, 1, 5)
|
||||
);
|
||||
|
||||
var eqlSpan = new Timespan(
|
||||
new Date(2012, 1, 1),
|
||||
new Date(2012, 1, 5)
|
||||
);
|
||||
|
||||
var notEqualSpan = new Timespan(
|
||||
new Date(2012, 1, 1),
|
||||
new Date(2012, 1, 6)
|
||||
);
|
||||
|
||||
assert.isTrue(span.isEqual(eqlSpan));
|
||||
assert.isFalse(span.isEqual(notEqualSpan));
|
||||
});
|
||||
|
||||
test('#daysBetween', function() {
|
||||
var range = new Timespan(
|
||||
new Date(2012, 1, 1),
|
||||
new Date(2012, 1, 3)
|
||||
);
|
||||
|
||||
var dates = Calc.daysBetween(range);
|
||||
assert.deepEqual(
|
||||
dates[0],
|
||||
new Date(2012, 1, 1)
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
dates[1],
|
||||
new Date(2012, 1, 2)
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
dates[2],
|
||||
new Date(2012, 1, 3)
|
||||
);
|
||||
});
|
||||
|
||||
suite('#trimOverlap', function() {
|
||||
var before;
|
||||
var subject;
|
||||
var none;
|
||||
|
||||
setup(function() {
|
||||
none = new Timespan(
|
||||
new Date(2012, 5, 1),
|
||||
new Date(2012, 5, 15)
|
||||
);
|
||||
|
||||
before = new Timespan(
|
||||
// July 1
|
||||
new Date(2012, 6, 1),
|
||||
// Aug 4th
|
||||
new Date(2012, 7, 4)
|
||||
);
|
||||
|
||||
subject = new Timespan(
|
||||
// July 29th
|
||||
new Date(2012, 6, 29),
|
||||
// Aug 31
|
||||
new Date(2012, 7, 31)
|
||||
);
|
||||
});
|
||||
|
||||
test('middle', function() {
|
||||
var long = new Timespan(
|
||||
new Date(2012, 0, 1),
|
||||
new Date(2012, 0, 31)
|
||||
);
|
||||
|
||||
var short = new Timespan(
|
||||
new Date(2012, 0, 5),
|
||||
new Date(2012, 0, 10)
|
||||
);
|
||||
|
||||
assert.isNull(
|
||||
long.trimOverlap(short),
|
||||
'should return null subject contains given'
|
||||
);
|
||||
|
||||
assert.isNull(
|
||||
short.trimOverlap(long),
|
||||
'should return null when given contains subject'
|
||||
);
|
||||
});
|
||||
|
||||
test('no overlap', function() {
|
||||
var out = before.trimOverlap(none);
|
||||
assert.deepEqual(out, none);
|
||||
});
|
||||
|
||||
test('overlaps && input.end > subject.start', function() {
|
||||
var output = subject.trimOverlap(
|
||||
before
|
||||
);
|
||||
|
||||
var start = new Date(2012, 6, 1);
|
||||
var end = new Date(
|
||||
2012, 6, 29
|
||||
);
|
||||
|
||||
end.setMilliseconds(-1);
|
||||
|
||||
var expected = new Timespan(
|
||||
start, end
|
||||
);
|
||||
|
||||
assert.deepEqual(output, expected);
|
||||
});
|
||||
|
||||
test('overlaps && subject.end > input.start', function() {
|
||||
var output = before.trimOverlap(
|
||||
subject
|
||||
);
|
||||
|
||||
var start = new Date(2012, 7, 4);
|
||||
start.setMilliseconds(
|
||||
start.getMilliseconds() + 1
|
||||
);
|
||||
|
||||
var end = new Date(
|
||||
2012, 7, 31
|
||||
);
|
||||
|
||||
var expected = new Timespan(
|
||||
start, end
|
||||
);
|
||||
|
||||
assert.deepEqual(output, expected);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('#overlaps', function() {
|
||||
var dates;
|
||||
|
||||
suiteSetup(function() {
|
||||
dates = {
|
||||
'range: inside': {
|
||||
assert: true,
|
||||
value: new Timespan(
|
||||
startDate,
|
||||
endDate
|
||||
)
|
||||
},
|
||||
|
||||
'range: starts on end date': {
|
||||
assert: false,
|
||||
value: new Timespan(
|
||||
endDate,
|
||||
new Date(2015, 1, 1)
|
||||
)
|
||||
},
|
||||
|
||||
'range: outside before': {
|
||||
assert: false,
|
||||
value: new Timespan(
|
||||
new Date(1991, 1, 1),
|
||||
new Date(2000, 1, 1)
|
||||
)
|
||||
},
|
||||
|
||||
'range: outside after': {
|
||||
assert: false,
|
||||
value: new Timespan(
|
||||
new Date(2015, 1, 1),
|
||||
new Date(2016, 1, 1)
|
||||
)
|
||||
},
|
||||
|
||||
'range: greater': {
|
||||
assert: true,
|
||||
value: new Timespan(
|
||||
new Date(2011, 12, 31),
|
||||
new Date(2012, 12, 2)
|
||||
)
|
||||
},
|
||||
|
||||
'range overlap: start before': {
|
||||
assert: true,
|
||||
value: new Timespan(
|
||||
new Date(2011, 1, 1),
|
||||
new Date(2012, 1, 15)
|
||||
)
|
||||
},
|
||||
|
||||
'range overlap: end before': {
|
||||
assert: true,
|
||||
value: new Timespan(
|
||||
new Date(2012, 1, 2),
|
||||
new Date(2012, 11, 12)
|
||||
)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
test('overlaping times', function() {
|
||||
var key;
|
||||
|
||||
for (key in dates) {
|
||||
if (dates.hasOwnProperty(key)) {
|
||||
var value = dates[key].value;
|
||||
|
||||
assert.equal(
|
||||
subject.overlaps(value),
|
||||
dates[key].assert,
|
||||
key
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('overlaping times as dates', function() {
|
||||
var key;
|
||||
|
||||
for (key in dates) {
|
||||
if (dates.hasOwnProperty(key)) {
|
||||
var value = dates[key].value;
|
||||
var start = new Date(value.start);
|
||||
var end = new Date(value.end);
|
||||
|
||||
assert.equal(
|
||||
subject.overlaps(start, end),
|
||||
dates[key].assert,
|
||||
key
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
suite('#contains', function() {
|
||||
var dates;
|
||||
|
||||
suiteSetup(function() {
|
||||
dates = {
|
||||
'day of': {
|
||||
assert: true,
|
||||
value: new Date(2012, 1, 1)
|
||||
},
|
||||
|
||||
'one day after': {
|
||||
assert: true,
|
||||
value: new Date(2012, 1, 2)
|
||||
},
|
||||
|
||||
'day of end range': {
|
||||
assert: true,
|
||||
value: new Date(2012, 12, 1)
|
||||
},
|
||||
|
||||
'day before range': {
|
||||
assert: false,
|
||||
value: new Date(2011, 12, 31)
|
||||
},
|
||||
|
||||
'day after range': {
|
||||
assert: false,
|
||||
value: new Date(2012, 12, 2)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
test('timespan in range', function() {
|
||||
var span = new Timespan(
|
||||
new Date(2012, 1, 1),
|
||||
new Date(2012, 1, 5)
|
||||
);
|
||||
|
||||
assert.isTrue(
|
||||
subject.contains(span)
|
||||
);
|
||||
|
||||
assert.isFalse(
|
||||
span.contains(subject)
|
||||
);
|
||||
});
|
||||
|
||||
function testWith(method, useNumeric) {
|
||||
var key;
|
||||
var prefix = '';
|
||||
|
||||
if (useNumeric) {
|
||||
prefix += '[numeric] ';
|
||||
}
|
||||
|
||||
prefix += method;
|
||||
|
||||
for (key in dates) {
|
||||
if (dates.hasOwnProperty(key)) {
|
||||
var value = dates[key].value.valueOf();
|
||||
|
||||
if (useNumeric) {
|
||||
value = value.valueOf();
|
||||
}
|
||||
|
||||
assert.equal(
|
||||
subject.contains(value),
|
||||
dates[key].assert,
|
||||
prefix + key
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('numeric (contains)', function() {
|
||||
testWith('contains', true);
|
||||
});
|
||||
|
||||
test('numeric (containsNumeric)', function() {
|
||||
testWith('containsNumeric', true);
|
||||
});
|
||||
|
||||
test('date', function() {
|
||||
testWith('contains', false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
Loading…
Reference in a new issue