summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Müller <thomas.mueller@tmit.eu>2014-09-23 13:45:21 +0200
committerThomas Müller <thomas.mueller@tmit.eu>2014-09-23 13:45:21 +0200
commitc587a4aaa212a48aca0b34fc2f9625774e02c472 (patch)
tree125b5ba8c98d5137e63e71c003135a9b338586d9
parenta062db4fd02feb1a0eff48eb130da7cc48c49899 (diff)
parent814114ab8eda5d383f4c620f3854cfefcdb6895d (diff)
downloadnextcloud-server-c587a4aaa212a48aca0b34fc2f9625774e02c472.tar.gz
nextcloud-server-c587a4aaa212a48aca0b34fc2f9625774e02c472.zip
Merge pull request #11222 from owncloud/store-users-timezone-master
send browsers timezone back tp the server on login
-rw-r--r--core/js/jstz.js358
-rw-r--r--core/js/visitortimezone.js5
-rw-r--r--core/templates/login.php2
-rw-r--r--lib/base.php16
-rwxr-xr-xlib/private/util.php24
-rw-r--r--lib/public/util.php6
-rw-r--r--settings/templates/admin.php2
-rw-r--r--tests/lib/util.php24
8 files changed, 417 insertions, 20 deletions
diff --git a/core/js/jstz.js b/core/js/jstz.js
new file mode 100644
index 00000000000..0f9abe8b78d
--- /dev/null
+++ b/core/js/jstz.js
@@ -0,0 +1,358 @@
+/**
+ * This script gives you the zone info key representing your device's time zone setting.
+ *
+ * @name jsTimezoneDetect
+ * @version 1.0.5
+ * @author Jon Nylander
+ * @license MIT License - http://www.opensource.org/licenses/mit-license.php
+ *
+ * For usage and examples, visit:
+ * http://pellepim.bitbucket.org/jstz/
+ *
+ * Copyright (c) Jon Nylander
+ */
+
+/*jslint undef: true */
+/*global console, exports*/
+
+(function(root) {
+ /**
+ * Namespace to hold all the code for timezone detection.
+ */
+ var jstz = (function () {
+ 'use strict';
+ var HEMISPHERE_SOUTH = 's',
+
+ /**
+ * Gets the offset in minutes from UTC for a certain date.
+ * @param {Date} date
+ * @returns {Number}
+ */
+ get_date_offset = function (date) {
+ var offset = -date.getTimezoneOffset();
+ return (offset !== null ? offset : 0);
+ },
+
+ get_date = function (year, month, date) {
+ var d = new Date();
+ if (year !== undefined) {
+ d.setFullYear(year);
+ }
+ d.setMonth(month);
+ d.setDate(date);
+ return d;
+ },
+
+ get_january_offset = function (year) {
+ return get_date_offset(get_date(year, 0 ,2));
+ },
+
+ get_june_offset = function (year) {
+ return get_date_offset(get_date(year, 5, 2));
+ },
+
+ /**
+ * Private method.
+ * Checks whether a given date is in daylight saving time.
+ * If the date supplied is after august, we assume that we're checking
+ * for southern hemisphere DST.
+ * @param {Date} date
+ * @returns {Boolean}
+ */
+ date_is_dst = function (date) {
+ var is_southern = date.getMonth() > 7,
+ base_offset = is_southern ? get_june_offset(date.getFullYear()) :
+ get_january_offset(date.getFullYear()),
+ date_offset = get_date_offset(date),
+ is_west = base_offset < 0,
+ dst_offset = base_offset - date_offset;
+
+ if (!is_west && !is_southern) {
+ return dst_offset < 0;
+ }
+
+ return dst_offset !== 0;
+ },
+
+ /**
+ * This function does some basic calculations to create information about
+ * the user's timezone. It uses REFERENCE_YEAR as a solid year for which
+ * the script has been tested rather than depend on the year set by the
+ * client device.
+ *
+ * Returns a key that can be used to do lookups in jstz.olson.timezones.
+ * eg: "720,1,2".
+ *
+ * @returns {String}
+ */
+
+ lookup_key = function () {
+ var january_offset = get_january_offset(),
+ june_offset = get_june_offset(),
+ diff = january_offset - june_offset;
+
+ if (diff < 0) {
+ return january_offset + ",1";
+ } else if (diff > 0) {
+ return june_offset + ",1," + HEMISPHERE_SOUTH;
+ }
+
+ return january_offset + ",0";
+ },
+
+ /**
+ * Uses get_timezone_info() to formulate a key to use in the olson.timezones dictionary.
+ *
+ * Returns a primitive object on the format:
+ * {'timezone': TimeZone, 'key' : 'the key used to find the TimeZone object'}
+ *
+ * @returns Object
+ */
+ determine = function () {
+ var key = lookup_key();
+ return new jstz.TimeZone(jstz.olson.timezones[key]);
+ },
+
+ /**
+ * This object contains information on when daylight savings starts for
+ * different timezones.
+ *
+ * The list is short for a reason. Often we do not have to be very specific
+ * to single out the correct timezone. But when we do, this list comes in
+ * handy.
+ *
+ * Each value is a date denoting when daylight savings starts for that timezone.
+ */
+ dst_start_for = function (tz_name) {
+
+ var ru_pre_dst_change = new Date(2010, 6, 15, 1, 0, 0, 0), // In 2010 Russia had DST, this allows us to detect Russia :)
+ dst_starts = {
+ 'America/Denver': new Date(2011, 2, 13, 3, 0, 0, 0),
+ 'America/Mazatlan': new Date(2011, 3, 3, 3, 0, 0, 0),
+ 'America/Chicago': new Date(2011, 2, 13, 3, 0, 0, 0),
+ 'America/Mexico_City': new Date(2011, 3, 3, 3, 0, 0, 0),
+ 'America/Asuncion': new Date(2012, 9, 7, 3, 0, 0, 0),
+ 'America/Santiago': new Date(2012, 9, 3, 3, 0, 0, 0),
+ 'America/Campo_Grande': new Date(2012, 9, 21, 5, 0, 0, 0),
+ 'America/Montevideo': new Date(2011, 9, 2, 3, 0, 0, 0),
+ 'America/Sao_Paulo': new Date(2011, 9, 16, 5, 0, 0, 0),
+ 'America/Los_Angeles': new Date(2011, 2, 13, 8, 0, 0, 0),
+ 'America/Santa_Isabel': new Date(2011, 3, 5, 8, 0, 0, 0),
+ 'America/Havana': new Date(2012, 2, 10, 2, 0, 0, 0),
+ 'America/New_York': new Date(2012, 2, 10, 7, 0, 0, 0),
+ 'Europe/Helsinki': new Date(2013, 2, 31, 5, 0, 0, 0),
+ 'Pacific/Auckland': new Date(2011, 8, 26, 7, 0, 0, 0),
+ 'America/Halifax': new Date(2011, 2, 13, 6, 0, 0, 0),
+ 'America/Goose_Bay': new Date(2011, 2, 13, 2, 1, 0, 0),
+ 'America/Miquelon': new Date(2011, 2, 13, 5, 0, 0, 0),
+ 'America/Godthab': new Date(2011, 2, 27, 1, 0, 0, 0),
+ 'Europe/Moscow': ru_pre_dst_change,
+ 'Asia/Amman': new Date(2013, 2, 29, 1, 0, 0, 0),
+ 'Asia/Beirut': new Date(2013, 2, 31, 2, 0, 0, 0),
+ 'Asia/Damascus': new Date(2013, 3, 6, 2, 0, 0, 0),
+ 'Asia/Jerusalem': new Date(2013, 2, 29, 5, 0, 0, 0),
+ 'Asia/Yekaterinburg': ru_pre_dst_change,
+ 'Asia/Omsk': ru_pre_dst_change,
+ 'Asia/Krasnoyarsk': ru_pre_dst_change,
+ 'Asia/Irkutsk': ru_pre_dst_change,
+ 'Asia/Yakutsk': ru_pre_dst_change,
+ 'Asia/Vladivostok': ru_pre_dst_change,
+ 'Asia/Baku': new Date(2013, 2, 31, 4, 0, 0),
+ 'Asia/Yerevan': new Date(2013, 2, 31, 3, 0, 0),
+ 'Asia/Kamchatka': ru_pre_dst_change,
+ 'Asia/Gaza': new Date(2010, 2, 27, 4, 0, 0),
+ 'Africa/Cairo': new Date(2010, 4, 1, 3, 0, 0),
+ 'Europe/Minsk': ru_pre_dst_change,
+ 'Pacific/Apia': new Date(2010, 10, 1, 1, 0, 0, 0),
+ 'Pacific/Fiji': new Date(2010, 11, 1, 0, 0, 0),
+ 'Australia/Perth': new Date(2008, 10, 1, 1, 0, 0, 0)
+ };
+
+ return dst_starts[tz_name];
+ };
+
+ return {
+ determine: determine,
+ date_is_dst: date_is_dst,
+ dst_start_for: dst_start_for
+ };
+ }());
+
+ /**
+ * Simple object to perform ambiguity check and to return name of time zone.
+ */
+ jstz.TimeZone = function (tz_name) {
+ 'use strict';
+ /**
+ * The keys in this object are timezones that we know may be ambiguous after
+ * a preliminary scan through the olson_tz object.
+ *
+ * The array of timezones to compare must be in the order that daylight savings
+ * starts for the regions.
+ */
+ var AMBIGUITIES = {
+ 'America/Denver': ['America/Denver', 'America/Mazatlan'],
+ 'America/Chicago': ['America/Chicago', 'America/Mexico_City'],
+ 'America/Santiago': ['America/Santiago', 'America/Asuncion', 'America/Campo_Grande'],
+ 'America/Montevideo': ['America/Montevideo', 'America/Sao_Paulo'],
+ 'Asia/Beirut': ['Asia/Amman', 'Asia/Jerusalem', 'Asia/Beirut', 'Europe/Helsinki','Asia/Damascus'],
+ 'Pacific/Auckland': ['Pacific/Auckland', 'Pacific/Fiji'],
+ 'America/Los_Angeles': ['America/Los_Angeles', 'America/Santa_Isabel'],
+ 'America/New_York': ['America/Havana', 'America/New_York'],
+ 'America/Halifax': ['America/Goose_Bay', 'America/Halifax'],
+ 'America/Godthab': ['America/Miquelon', 'America/Godthab'],
+ 'Asia/Dubai': ['Europe/Moscow'],
+ 'Asia/Dhaka': ['Asia/Yekaterinburg'],
+ 'Asia/Jakarta': ['Asia/Omsk'],
+ 'Asia/Shanghai': ['Asia/Krasnoyarsk', 'Australia/Perth'],
+ 'Asia/Tokyo': ['Asia/Irkutsk'],
+ 'Australia/Brisbane': ['Asia/Yakutsk'],
+ 'Pacific/Noumea': ['Asia/Vladivostok'],
+ 'Pacific/Tarawa': ['Asia/Kamchatka', 'Pacific/Fiji'],
+ 'Pacific/Tongatapu': ['Pacific/Apia'],
+ 'Asia/Baghdad': ['Europe/Minsk'],
+ 'Asia/Baku': ['Asia/Yerevan','Asia/Baku'],
+ 'Africa/Johannesburg': ['Asia/Gaza', 'Africa/Cairo']
+ },
+
+ timezone_name = tz_name,
+
+ /**
+ * Checks if a timezone has possible ambiguities. I.e timezones that are similar.
+ *
+ * For example, if the preliminary scan determines that we're in America/Denver.
+ * We double check here that we're really there and not in America/Mazatlan.
+ *
+ * This is done by checking known dates for when daylight savings start for different
+ * timezones during 2010 and 2011.
+ */
+ ambiguity_check = function () {
+ var ambiguity_list = AMBIGUITIES[timezone_name],
+ length = ambiguity_list.length,
+ i = 0,
+ tz = ambiguity_list[0];
+
+ for (; i < length; i += 1) {
+ tz = ambiguity_list[i];
+
+ if (jstz.date_is_dst(jstz.dst_start_for(tz))) {
+ timezone_name = tz;
+ return;
+ }
+ }
+ },
+
+ /**
+ * Checks if it is possible that the timezone is ambiguous.
+ */
+ is_ambiguous = function () {
+ return typeof (AMBIGUITIES[timezone_name]) !== 'undefined';
+ };
+
+ if (is_ambiguous()) {
+ ambiguity_check();
+ }
+
+ return {
+ name: function () {
+ return timezone_name;
+ }
+ };
+ };
+
+ jstz.olson = {};
+
+ /*
+ * The keys in this dictionary are comma separated as such:
+ *
+ * First the offset compared to UTC time in minutes.
+ *
+ * Then a flag which is 0 if the timezone does not take daylight savings into account and 1 if it
+ * does.
+ *
+ * Thirdly an optional 's' signifies that the timezone is in the southern hemisphere,
+ * only interesting for timezones with DST.
+ *
+ * The mapped arrays is used for constructing the jstz.TimeZone object from within
+ * jstz.determine_timezone();
+ */
+ jstz.olson.timezones = {
+ '-720,0' : 'Pacific/Majuro',
+ '-660,0' : 'Pacific/Pago_Pago',
+ '-600,1' : 'America/Adak',
+ '-600,0' : 'Pacific/Honolulu',
+ '-570,0' : 'Pacific/Marquesas',
+ '-540,0' : 'Pacific/Gambier',
+ '-540,1' : 'America/Anchorage',
+ '-480,1' : 'America/Los_Angeles',
+ '-480,0' : 'Pacific/Pitcairn',
+ '-420,0' : 'America/Phoenix',
+ '-420,1' : 'America/Denver',
+ '-360,0' : 'America/Guatemala',
+ '-360,1' : 'America/Chicago',
+ '-360,1,s' : 'Pacific/Easter',
+ '-300,0' : 'America/Bogota',
+ '-300,1' : 'America/New_York',
+ '-270,0' : 'America/Caracas',
+ '-240,1' : 'America/Halifax',
+ '-240,0' : 'America/Santo_Domingo',
+ '-240,1,s' : 'America/Santiago',
+ '-210,1' : 'America/St_Johns',
+ '-180,1' : 'America/Godthab',
+ '-180,0' : 'America/Argentina/Buenos_Aires',
+ '-180,1,s' : 'America/Montevideo',
+ '-120,0' : 'America/Noronha',
+ '-120,1' : 'America/Noronha',
+ '-60,1' : 'Atlantic/Azores',
+ '-60,0' : 'Atlantic/Cape_Verde',
+ '0,0' : 'UTC',
+ '0,1' : 'Europe/London',
+ '60,1' : 'Europe/Berlin',
+ '60,0' : 'Africa/Lagos',
+ '60,1,s' : 'Africa/Windhoek',
+ '120,1' : 'Asia/Beirut',
+ '120,0' : 'Africa/Johannesburg',
+ '180,0' : 'Asia/Baghdad',
+ '180,1' : 'Europe/Moscow',
+ '210,1' : 'Asia/Tehran',
+ '240,0' : 'Asia/Dubai',
+ '240,1' : 'Asia/Baku',
+ '270,0' : 'Asia/Kabul',
+ '300,1' : 'Asia/Yekaterinburg',
+ '300,0' : 'Asia/Karachi',
+ '330,0' : 'Asia/Kolkata',
+ '345,0' : 'Asia/Kathmandu',
+ '360,0' : 'Asia/Dhaka',
+ '360,1' : 'Asia/Omsk',
+ '390,0' : 'Asia/Rangoon',
+ '420,1' : 'Asia/Krasnoyarsk',
+ '420,0' : 'Asia/Jakarta',
+ '480,0' : 'Asia/Shanghai',
+ '480,1' : 'Asia/Irkutsk',
+ '525,0' : 'Australia/Eucla',
+ '525,1,s' : 'Australia/Eucla',
+ '540,1' : 'Asia/Yakutsk',
+ '540,0' : 'Asia/Tokyo',
+ '570,0' : 'Australia/Darwin',
+ '570,1,s' : 'Australia/Adelaide',
+ '600,0' : 'Australia/Brisbane',
+ '600,1' : 'Asia/Vladivostok',
+ '600,1,s' : 'Australia/Sydney',
+ '630,1,s' : 'Australia/Lord_Howe',
+ '660,1' : 'Asia/Kamchatka',
+ '660,0' : 'Pacific/Noumea',
+ '690,0' : 'Pacific/Norfolk',
+ '720,1,s' : 'Pacific/Auckland',
+ '720,0' : 'Pacific/Tarawa',
+ '765,1,s' : 'Pacific/Chatham',
+ '780,0' : 'Pacific/Tongatapu',
+ '780,1,s' : 'Pacific/Apia',
+ '840,0' : 'Pacific/Kiritimati'
+ };
+
+ if (typeof exports !== 'undefined') {
+ exports.jstz = jstz;
+ } else {
+ root.jstz = jstz;
+ }
+})(this);
diff --git a/core/js/visitortimezone.js b/core/js/visitortimezone.js
index 9146e00aade..e6e99ee7e20 100644
--- a/core/js/visitortimezone.js
+++ b/core/js/visitortimezone.js
@@ -1,6 +1,7 @@
+/* global jstz */
$(document).ready(function () {
- var visitortimezone = (-new Date().getTimezoneOffset() / 60);
- $('#timezone-offset').val(visitortimezone);
+ $('#timezone-offset').val((-new Date().getTimezoneOffset() / 60));
+ $('#timezone').val(jstz.determine().name());
// only enable the submit button once we are sure that the timezone is set
var $loginForm = $('form[name="login"]');
diff --git a/core/templates/login.php b/core/templates/login.php
index 819010c5485..ad9db14bac1 100644
--- a/core/templates/login.php
+++ b/core/templates/login.php
@@ -1,4 +1,5 @@
<?php /** @var $l OC_L10N */ ?>
+<?php script('core', 'jstz') ?>
<!--[if IE 8]><style>input[type="checkbox"]{padding:0;}</style><![endif]-->
<form method="post" name="login">
@@ -47,6 +48,7 @@
<label for="remember_login"><?php p($l->t('remember')); ?></label>
<?php endif; ?>
<input type="hidden" name="timezone-offset" id="timezone-offset"/>
+ <input type="hidden" name="timezone" id="timezone"/>
<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
<input type="submit" id="submit" class="login primary" value="<?php p($l->t('Log in')); ?>" disabled="disabled"/>
</fieldset>
diff --git a/lib/base.php b/lib/base.php
index fc2bdddb440..7d735f523f4 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -913,7 +913,7 @@ class OC {
}
/**
- * Tries to login a user using the formbased authentication
+ * Tries to login a user using the form based authentication
* @return bool|void
*/
protected static function tryFormLogin() {
@@ -928,20 +928,22 @@ class OC {
OC_User::setupBackends();
if (OC_User::login($_POST["user"], $_POST["password"])) {
+ $userId = OC_User::getUser();
+
// setting up the time zone
if (isset($_POST['timezone-offset'])) {
self::$server->getSession()->set('timezone', $_POST['timezone-offset']);
+ self::$server->getConfig()->setUserValue($userId, 'core', 'timezone', $_POST['timezone']);
}
- $userid = OC_User::getUser();
- self::cleanupLoginTokens($userid);
+ self::cleanupLoginTokens($userId);
if (!empty($_POST["remember_login"])) {
if (defined("DEBUG") && DEBUG) {
- OC_Log::write('core', 'Setting remember login to cookie', OC_Log::DEBUG);
+ self::$server->getLogger()->debug('Setting remember login to cookie', array('app' => 'core'));
}
$token = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(32);
- OC_Preferences::setValue($userid, 'login_token', $token, time());
- OC_User::setMagicInCookie($userid, $token);
+ self::$server->getConfig()->setUserValue($userId, 'login_token', $token, time());
+ OC_User::setMagicInCookie($userId, $token);
} else {
OC_User::unsetMagicInCookie();
}
@@ -950,8 +952,6 @@ class OC {
}
return true;
}
-
-
}
if (!function_exists('get_temp_dir')) {
diff --git a/lib/private/util.php b/lib/private/util.php
index 18857139791..5a310273258 100755
--- a/lib/private/util.php
+++ b/lib/private/util.php
@@ -381,16 +381,26 @@ class OC_Util {
*
* @param int $timestamp
* @param bool $dateOnly option to omit time from the result
+ * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to
* @return string timestamp
* @description adjust to clients timezone if we know it
*/
- public static function formatDate( $timestamp, $dateOnly = false) {
- if(\OC::$server->getSession()->exists('timezone')) {
- $systemTimeZone = intval(date('O'));
- $systemTimeZone = (round($systemTimeZone / 100, 0) * 60) + ($systemTimeZone % 100);
- $clientTimeZone = \OC::$server->getSession()->get('timezone') * 60;
- $offset = $clientTimeZone - $systemTimeZone;
- $timestamp = $timestamp + $offset * 60;
+ public static function formatDate($timestamp, $dateOnly = false, $timeZone = null) {
+ if (is_null($timeZone)) {
+ if (\OC::$server->getSession()->exists('timezone')) {
+ $systemTimeZone = intval(date('O'));
+ $systemTimeZone = (round($systemTimeZone / 100, 0) * 60) + ($systemTimeZone % 100);
+ $clientTimeZone = \OC::$server->getSession()->get('timezone') * 60;
+ $offset = $clientTimeZone - $systemTimeZone;
+ $timestamp = $timestamp + $offset * 60;
+ }
+ } else {
+ if (!$timeZone instanceof DateTimeZone) {
+ $timeZone = new DateTimeZone($timeZone);
+ }
+ $dt = new DateTime("@$timestamp");
+ $offset = $timeZone->getOffset($dt);
+ $timestamp += $offset;
}
$l = \OC::$server->getL10N('lib');
return $l->l($dateOnly ? 'date' : 'datetime', $timestamp);
diff --git a/lib/public/util.php b/lib/public/util.php
index 244c11ba2cc..35847fce38a 100644
--- a/lib/public/util.php
+++ b/lib/public/util.php
@@ -29,6 +29,7 @@
// use OCP namespace for all classes that are considered public.
// This means that they should be used by apps instead of the internal ownCloud classes
namespace OCP;
+use DateTimeZone;
/**
* This class provides different helper functions to make the life of a developer easier
@@ -167,10 +168,11 @@ class Util {
* formats a timestamp in the "right" way
* @param int $timestamp $timestamp
* @param bool $dateOnly option to omit time from the result
+ * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to
* @return string timestamp
*/
- public static function formatDate( $timestamp, $dateOnly=false) {
- return(\OC_Util::formatDate( $timestamp, $dateOnly ));
+ public static function formatDate($timestamp, $dateOnly=false, $timeZone = null) {
+ return(\OC_Util::formatDate($timestamp, $dateOnly, $timeZone));
}
/**
diff --git a/settings/templates/admin.php b/settings/templates/admin.php
index 9ceebad4ee1..bfd1c676b64 100644
--- a/settings/templates/admin.php
+++ b/settings/templates/admin.php
@@ -221,7 +221,7 @@ if ($_['suggestedOverwriteWebroot']) {
<?php if ($_['cron_log']): ?>
<p class="cronlog inlineblock">
<?php if ($_['lastcron'] !== false):
- $human_time = OC_Util::formatDate($_['lastcron']) . " UTC";
+ $human_time = OC_Util::formatDate($_['lastcron']);
if (time() - $_['lastcron'] <= 3600): ?>
<span class="cronstatus success"></span>
<?php p($l->t("Last cron was executed at %s.", array($human_time)));
diff --git a/tests/lib/util.php b/tests/lib/util.php
index 999c62486a7..600b794d8b8 100644
--- a/tests/lib/util.php
+++ b/tests/lib/util.php
@@ -37,6 +37,30 @@ class Test_Util extends PHPUnit_Framework_TestCase {
$this->assertEquals($expected, $result);
}
+ function testFormatDateWithTZ() {
+ date_default_timezone_set("UTC");
+
+ $result = OC_Util::formatDate(1350129205, false, 'Europe/Berlin');
+ $expected = 'October 13, 2012 13:53';
+ $this->assertEquals($expected, $result);
+ }
+
+ /**
+ * @expectedException Exception
+ */
+ function testFormatDateWithInvalidTZ() {
+ OC_Util::formatDate(1350129205, false, 'Mordor/Barad-dûr');
+ }
+
+ function testFormatDateWithTZFromSession() {
+ date_default_timezone_set("UTC");
+
+ \OC::$server->getSession()->set('timezone', 3);
+ $result = OC_Util::formatDate(1350129205, false);
+ $expected = 'October 13, 2012 14:53';
+ $this->assertEquals($expected, $result);
+ }
+
function testCallRegister() {
$result = strlen(OC_Util::callRegister());
$this->assertEquals(30, $result);