From 0ae36d6cfcdc2e63db59aed7673cd95b1f7af75a Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Wed, 10 Jul 2013 19:10:51 +0800 Subject: [PATCH] MDL-18375 calendar: created a test calendar type to use for PHPUnit tests and added tests --- calendar/tests/calendartype_test.php | 281 +++++++++++++++++++ calendar/tests/calendartype_test_example.php | 180 ++++++++++++ 2 files changed, 461 insertions(+) create mode 100644 calendar/tests/calendartype_test.php create mode 100644 calendar/tests/calendartype_test_example.php diff --git a/calendar/tests/calendartype_test.php b/calendar/tests/calendartype_test.php new file mode 100644 index 00000000000..66c2595ca7f --- /dev/null +++ b/calendar/tests/calendartype_test.php @@ -0,0 +1,281 @@ +. + +/** + * Calendar type system unit tests. + * + * @package core_calendar + * @copyright 2013 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +// The test calendar type. +require_once($CFG->dirroot . '/calendar/tests/calendartype_test_example.php'); + +// Used to test the dateselector elements. +require_once($CFG->libdir . '/form/dateselector.php'); +require_once($CFG->libdir . '/form/datetimeselector.php'); + +// Used to test the user datetime profile field. +require_once($CFG->dirroot . '/user/profile/lib.php'); +require_once($CFG->dirroot . '/user/profile/definelib.php'); +require_once($CFG->dirroot . '/user/profile/index_field_form.php'); + +/** + * Unit tests for the calendar type system. + * + * @package core_calendar + * @copyright 2013 Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.6 + */ +class core_calendar_type_testcase extends advanced_testcase { + + /** + * The test user. + */ + private $user; + + /** + * Test set up. + */ + protected function setUp() { + // The user we are going to test this on. + $this->user = self::getDataGenerator()->create_user(); + self::setUser($this->user); + } + + /** + * Test that setting the calendar type works. + */ + public function test_calendar_type_set() { + // We want to reset the test data after this run. + $this->resetAfterTest(); + + // Test setting it as the 'Test' calendar type. + $this->set_calendar_type('test'); + $this->assertEquals('test', \core_calendar\type_factory::get_calendar_type()); + + // Test setting it as the 'Gregorian' calendar type. + $this->set_calendar_type('gregorian'); + $this->assertEquals('gregorian', \core_calendar\type_factory::get_calendar_type()); + } + + /** + * Test that calling core Moodle functions responsible for displaying the date + * have the same results as directly calling the same function in the calendar type. + */ + public function test_calendar_type_core_functions() { + // We want to reset the test data after this run. + $this->resetAfterTest(); + + // Test that the core functions reproduce the same results as the Gregorian calendar. + $this->core_functions_test('gregorian'); + + // Test that the core functions reproduce the same results as the test calendar. + $this->core_functions_test('test'); + } + + /** + * Test that dates selected using the date selector elements are being saved as unixtime, and that the + * unixtime is being converted back to a valid date to display in the date selector elements for + * different calendar types. + */ + public function test_calendar_type_dateselector_elements() { + // We want to reset the test data after this run. + $this->resetAfterTest(); + + // Check converting dates to Gregorian when submitting a date selector element works. Note: the test + // calendar is 2 years, 2 months, 2 days, 2 hours and 2 minutes ahead of the Gregorian calendar. + $date1 = array(); + $date1['day'] = 4; + $date1['month'] = 7; + $date1['year'] = 2013; + $date1['hour'] = 0; + $date1['minute'] = 0; + $date1['timestamp'] = 1372896000; + $this->convert_dateselector_to_unixtime_test('dateselector', 'gregorian', $date1); + + $date2 = array(); + $date2['day'] = 7; + $date2['month'] = 9; + $date2['year'] = 2015; + $date2['hour'] = 0; // The dateselector element does not have hours. + $date2['minute'] = 0; // The dateselector element does not have minutes. + $date2['timestamp'] = 1372896000; + $this->convert_dateselector_to_unixtime_test('dateselector', 'test', $date2); + + $date3 = array(); + $date3['day'] = 4; + $date3['month'] = 7; + $date3['year'] = 2013; + $date3['hour'] = 23; + $date3['minute'] = 15; + $date3['timestamp'] = 1372979700; + $this->convert_dateselector_to_unixtime_test('datetimeselector', 'gregorian', $date3); + + $date4 = array(); + $date4['day'] = 7; + $date4['month'] = 9; + $date4['year'] = 2015; + $date4['hour'] = 1; + $date4['minute'] = 17; + $date4['timestamp'] = 1372979700; + $this->convert_dateselector_to_unixtime_test('datetimeselector', 'test', $date4); + + // The date selector element values are set by using the function usergetdate, here we want to check that + // the unixtime passed is being successfully converted to the correct values for the calendar type. + $this->convert_unixtime_to_dateselector_test('gregorian', $date3); + $this->convert_unixtime_to_dateselector_test('test', $date4); + } + + /** + * Test that the user profile field datetime minimum and maximum year settings are saved as the + * equivalent Gregorian years. + */ + public function test_calendar_type_datetime_field_submission() { + // We want to reset the test data after this run. + $this->resetAfterTest(); + + // Create an array with the input values and expected values once submitted. + $date = array(); + $date['inputminyear'] = '1970'; + $date['inputmaxyear'] = '2013'; + $date['expectedminyear'] = '1970'; + $date['expectedmaxyear'] = '2013'; + $this->datetime_field_submission_test('gregorian', $date); + + // The test calendar is 2 years, 2 months, 2 days in the future, so when the year 1970 is submitted, + // the year 1967 should be saved in the DB, as 1/1/1970 converts to 30/10/1967 in Gregorian. + $date['expectedminyear'] = '1967'; + $date['expectedmaxyear'] = '2010'; + $this->datetime_field_submission_test('test', $date); + } + + /** + * Test all the core functions that use the calendar type system. + * + * @param string $type the calendar type we want to test + */ + private function core_functions_test($type) { + $this->set_calendar_type($type); + + $class = "\\calendartype_$type\\structure"; + $calendar = new $class(); + + // Test the userdate function. + $this->assertEquals($calendar->userdate($this->user->timecreated, '', 99, true, true), userdate($this->user->timecreated)); + + // Test the usergetdate function. + $this->assertEquals($calendar->usergetdate($this->user->timecreated, '', 99, true, true), usergetdate($this->user->timecreated)); + } + + /** + * Simulates submitting a form with a date selector element and tests that the chosen dates + * are converted into unixtime before being saved in DB. + * + * @param string $element the form element we are testing + * @param string $type the calendar type we want to test + * @param array $date the date variables + */ + private function convert_dateselector_to_unixtime_test($element, $type, $date) { + $this->set_calendar_type($type); + + if ($element == 'dateselector') { + $el = new MoodleQuickForm_date_selector('dateselector', null, array('timezone' => 0.0, 'step' => 1)); + } else { + $el = new MoodleQuickForm_date_time_selector('dateselector', null, array('timezone' => 0.0, 'step' => 1)); + } + $el->_createElements(); + $submitvalues = array('dateselector' => $date); + + $this->assertSame($el->exportValue($submitvalues), array('dateselector' => $date['timestamp'])); + } + + /** + * Test converting dates from unixtime to a date for the calendar type specified. + * + * @param string $type the calendar type we want to test + * @param array $date the date variables + */ + private function convert_unixtime_to_dateselector_test($type, $date) { + $this->set_calendar_type($type); + + $usergetdate = usergetdate($date['timestamp'], 0.0); + $comparedate = array( + 'minute' => $usergetdate['minutes'], + 'hour' => $usergetdate['hours'], + 'day' => $usergetdate['mday'], + 'month' => $usergetdate['mon'], + 'year' => $usergetdate['year'], + 'timestamp' => $date['timestamp'] + ); + + $this->assertEquals($comparedate, $date); + } + + /** + * Test saving the minimum and max year settings for the user datetime field. + * + * @param string $type the calendar type we want to test + * @param array $date the date variables + */ + private function datetime_field_submission_test($type, $date) { + $this->set_calendar_type($type); + + // Get the data we are submitting for the form. + $formdata = array(); + $formdata['shortname'] = 'Shortname'; + $formdata['name'] = 'Name'; + $formdata['param1'] = $date['inputminyear']; + $formdata['param2'] = $date['inputmaxyear']; + + // Mock submitting this. + field_form::mock_submit($formdata); + + // Create the user datetime form. + $form = new field_form(null, 'datetime'); + + // Get the data from the submission. + $submissiondata = $form->get_data(); + // On the user profile field page after get_data, the function define_save is called + // in the field base class, which then calls the field's function define_save_preprocess. + $field = new profile_define_datetime(); + $submissiondata = $field->define_save_preprocess($submissiondata); + + // Create an array we want to compare with the date passed. + $comparedate = $date; + $comparedate['expectedminyear'] = $submissiondata->param1; + $comparedate['expectedmaxyear'] = $submissiondata->param2; + + $this->assertEquals($comparedate, $date); + } + + /** + * Set the calendar type for this user. + * + * @param string $type the calendar type we want to set + */ + private function set_calendar_type($type) { + $this->user->calendartype = $type; + session_set_user($this->user); + } +} diff --git a/calendar/tests/calendartype_test_example.php b/calendar/tests/calendartype_test_example.php new file mode 100644 index 00000000000..f251ccd0060 --- /dev/null +++ b/calendar/tests/calendartype_test_example.php @@ -0,0 +1,180 @@ +. + +namespace calendartype_test; +use \core_calendar\type_base; + +/** + * Handles calendar functions for the test calendar. + * + * The test calendar is going to be 2 years, 2 days, 2 hours and 2 minutes + * in the future of the Gregorian calendar. + * + * @package core_calendar + * @copyright Mark Nelson + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class structure extends type_base { + + /** + * Returns a list of all the possible days for all months. + * + * This is used to generate the select box for the days + * in the date selector elements. Some months contain more days + * than others so this function should return all possible days as + * we can not predict what month will be chosen (the user + * may have JS turned off and we need to support this situation in + * Moodle). + * + * @return array the days + */ + public function get_days() { + $days = array(); + + for ($i = 1; $i <= 31; $i++) { + $days[$i] = $i; + } + + return $days; + } + + /** + * Returns a list of all the names of the months. + * + * @return array the month names + */ + public function get_months() { + $months = array(); + + for ($i=1; $i<=12; $i++) { + $months[$i] = $i; + } + + return $months; + } + + /** + * Returns the minimum year of the calendar. + * + * @return int the minumum year + */ + public function get_min_year() { + return 1970; + } + + /** + * Returns the maximum year of the calendar. + * + * @return int the max year + */ + public function get_max_year() { + return 2050; + } + + /** + * Returns a formatted string that represents a date in user time. + * + * If parameter fixday = true (default), then take off leading + * zero from %d, else maintain it. + * + * @param int $date the timestamp in UTC, as obtained from the database. + * @param string $format strftime format. You should probably get this using + * get_string('strftime...', 'langconfig'); + * @param int|float|string $timezone by default, uses the user's time zone. if numeric and + * not 99 then daylight saving will not be added. + * {@link http://docs.moodle.org/dev/Time_API#Timezone} + * @param bool $fixday if true (default) then the leading zero from %d is removed. + * If false then the leading zero is maintained. + * @param bool $fixhour if true (default) then the leading zero from %I is removed. + * @return string the formatted date/time. + */ + public function userdate($date, $format, $timezone, $fixday, $fixhour) { + return ""; + } + + /** + * Given a $time timestamp in GMT (seconds since epoch), returns an array that + * represents the date in user time. + * + * @param int $time Timestamp in GMT + * @param float|int|string $timezone offset's time with timezone, if float and not 99, then no + * dst offset is applyed {@link http://docs.moodle.org/dev/Time_API#Timezone} + * @return array An array that represents the date in user time + */ + public function usergetdate($time, $timezone) { + $date = parent::usergetdate($time, $timezone); + $newdate = $this->convert_from_gregorian($date["year"], $date["mon"], $date["mday"], + $date['hours'], $date['minutes']); + + $date["year"] = $newdate['year']; + $date["mon"] = $newdate['month']; + $date["mday"] = $newdate['day']; + $date['hours'] = $newdate['hour']; + $date['minutes'] = $newdate['minute']; + + return $date; + } + + /** + * Provided with a day, month, year, hour and minute + * convert it into the equivalent Gregorian date. + * + * @param int $year + * @param int $month + * @param int $day + * @param int $hour + * @param int $minute + * @return array the converted day, month, year, hour and minute. + */ + public function convert_to_gregorian($year, $month, $day, $hour = 0, $minute = 0) { + $timestamp = make_timestamp($year, $month, $day, $hour, $minute); + $date = date('Y/n/j/H/i', strtotime('-2 year, -2 months, -2 days, -2 hours, -2 minutes', $timestamp)); + + list($year, $month, $day, $hour, $minute) = explode('/', $date); + + return array('year' => (int) $year, + 'month' => (int) $month, + 'day' => (int) $day, + 'hour' => (int) $hour, + 'minute' => (int) $minute); + + } + + /** + * Provided with a day, month, year, hour and minute in a Gregorian date + * convert it into the specific calendar type date. + * + * @param int $year + * @param int $month + * @param int $day + * @param int $hour + * @param int $minute + * @return array the converted day, month, year, hour and minute. + */ + public function convert_from_gregorian($year, $month, $day, $hour = 0, $minute = 0) { + $timestamp = make_timestamp($year, $month, $day, $hour, $minute); + $date = date('Y/n/j/H/i', strtotime('+2 year, +2 months, +2 days, +2 hours, +2 minutes', $timestamp)); + + list($year, $month, $day, $hour, $minute) = explode('/', $date); + + return array('year' => (int) $year, + 'month' => (int) $month, + 'day' => (int) $day, + 'hour' => (int) $hour, + 'minute' => (int) $minute); + } +}