diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4773508
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/bin/
+/composer.lock
+/phpunit.xml
+/vendor/
diff --git a/.scrutinizer.yml b/.scrutinizer.yml
new file mode 100644
index 0000000..6ebfd66
--- /dev/null
+++ b/.scrutinizer.yml
@@ -0,0 +1,12 @@
+tools:
+ external_code_coverage:
+ timeout: 600
+ php_code_sniffer: true
+ php_cpd: true
+ php_loc: true
+ php_mess_detector: true
+ php_pdepend: true
+ php_analyzer: true
+ sensiolabs_security_checker: true
+filter:
+ paths: [src/*]
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..3b0f06c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,21 @@
+language: php
+
+sudo: false
+
+php:
+ - 5.4
+ - 5.5
+ - 5.6
+ - hhvm
+ - nightly
+
+before_script:
+ - composer self-update
+ - composer install --prefer-dist --no-interaction
+
+script:
+ - bin/phpunit --coverage-clover=coverage.clover --coverage-text
+
+after_script:
+ - wget https://scrutinizer-ci.com/ocular.phar
+ - php ocular.phar code-coverage:upload --format=php-clover coverage.clover
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..1053119
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,30 @@
+Contributing
+============
+
+If you are reading this, **thank you**! You are about to make things better and this makes you **a hero**!
+
+Here are a few rules to follow in order to ease code reviews, and discussions before
+maintainers accept and merge your work.
+
+You MUST follow the [PSR-1](http://www.php-fig.org/psr/1/) and
+[PSR-2](http://www.php-fig.org/psr/2/). If you don't know about any of them, you
+should really read the recommendations. Can't wait? Use the [PHP-CS-Fixer
+tool](http://cs.sensiolabs.org/).
+
+You MUST run the test suite.
+
+You MUST write (or update) unit tests.
+
+You SHOULD write documentation.
+
+Please, write [commit messages that make
+sense](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html),
+and [rebase your branch](http://git-scm.com/book/en/Git-Branching-Rebasing)
+before submitting your Pull Request.
+
+One may ask you to [squash your
+commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html)
+too. This is used to "clean" your Pull Request before merging it (we don't want
+commits such as `fix tests`, `fix 2`, `fix 3`, etc.).
+
+Thank you very much!
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bc23710
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Nicolò Pignatelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 80a713b..d119c39 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,6 @@
-# valueobjects
\ No newline at end of file
+ValueObjects
+============
+
+*nicolopignatelli/valueobjects*
+
+Temporary substitute library
diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md
new file mode 100644
index 0000000..b16cb72
--- /dev/null
+++ b/UPGRADE-3.0.md
@@ -0,0 +1,7 @@
+UPGRADE FROM 2.x to 3.0
+=======================
+
+### StringLiteral
+
+ * The `String` and `Null` classed and namespaces have been respectively renamed to
+ `StringLiteral` and `NullValue` in order to be compatible with PHP 7.
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..2662612
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,43 @@
+{
+ "name": "ytake/valueobjects",
+ "description": "A PHP library/collection of classes aimed to help developers using and undestanding immutable objects.(temporary package)",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolò Pignatelli",
+ "email": "pignatelli.nicolo@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.4",
+ "ramsey/uuid": "~3.0",
+ "mathiasverraes/money": "~1.2",
+ "marc-mabe/php-enum": "~1.0",
+ "zendframework/zend-validator": "~2.2",
+ "league/geotools": "~0.7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.0"
+ },
+ "config": {
+ "bin-dir": "bin"
+ },
+ "autoload": {
+ "psr-4": {
+ "ValueObjects\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "ValueObjects\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.2.x-dev"
+ }
+ },
+ "replace": {
+ "nicolopignatelli/valueobjects": "^4.0"
+ }
+}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..ccde45f
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,23 @@
+
+
+
+
+ ./tests/
+
+
+
+
+ ./src/
+
+
+
diff --git a/src/Climate/Celsius.php b/src/Climate/Celsius.php
new file mode 100644
index 0000000..020f466
--- /dev/null
+++ b/src/Climate/Celsius.php
@@ -0,0 +1,30 @@
+value);
+ }
+
+ /**
+ * @return Kelvin
+ */
+ public function toKelvin()
+ {
+ return new Kelvin($this->value + 273.15);
+ }
+
+ /**
+ * @return Fahrenheit
+ */
+ public function toFahrenheit()
+ {
+ return new Fahrenheit($this->value * 1.8 + 32);
+ }
+}
diff --git a/src/Climate/Fahrenheit.php b/src/Climate/Fahrenheit.php
new file mode 100644
index 0000000..e14bff2
--- /dev/null
+++ b/src/Climate/Fahrenheit.php
@@ -0,0 +1,30 @@
+value - 32) / 1.8);
+ }
+
+ /**
+ * @return Kelvin
+ */
+ public function toKelvin()
+ {
+ return new Kelvin($this->toCelsius()->toNative() + 273.15);
+ }
+
+ /**
+ * @return Fahrenheit
+ */
+ public function toFahrenheit()
+ {
+ return new static($this->value);
+ }
+}
diff --git a/src/Climate/Kelvin.php b/src/Climate/Kelvin.php
new file mode 100644
index 0000000..85f83dd
--- /dev/null
+++ b/src/Climate/Kelvin.php
@@ -0,0 +1,30 @@
+value - 273.15);
+ }
+
+ /**
+ * @return Kelvin
+ */
+ public function toKelvin()
+ {
+ return new static($this->value);
+ }
+
+ /**
+ * @return Fahrenheit
+ */
+ public function toFahrenheit()
+ {
+ return new Fahrenheit($this->toCelsius()->toNative() * 1.8 + 32);
+ }
+}
diff --git a/src/Climate/RelativeHumidity.php b/src/Climate/RelativeHumidity.php
new file mode 100644
index 0000000..16bbd89
--- /dev/null
+++ b/src/Climate/RelativeHumidity.php
@@ -0,0 +1,46 @@
+ array('min_range' => self::MIN, 'max_range' => self::MAX)
+ );
+
+ $value = filter_var($value, FILTER_VALIDATE_INT, $options);
+
+ if (false === $value) {
+ throw new InvalidNativeArgumentException($value, array('int (>=' . self::MIN . ', <=' . self::MAX . ')'));
+ }
+
+ parent::__construct($value);
+ }
+}
diff --git a/src/Climate/Temperature.php b/src/Climate/Temperature.php
new file mode 100644
index 0000000..fd2f261
--- /dev/null
+++ b/src/Climate/Temperature.php
@@ -0,0 +1,23 @@
+format('Y'));
+ $month = Month::fromNativeDateTime($date);
+ $day = \intval($date->format('d'));
+
+ return new static(new Year($year), $month, new MonthDay($day));
+ }
+
+ /**
+ * Returns current Date
+ *
+ * @return Date
+ */
+ public static function now()
+ {
+ $date = new static(Year::now(), Month::now(), MonthDay::now());
+
+ return $date;
+ }
+
+ /**
+ * Create a new Date
+ *
+ * @param Year $year
+ * @param Month $month
+ * @param MonthDay $day
+ * @throws InvalidDateException
+ */
+ public function __construct(Year $year, Month $month, MonthDay $day)
+ {
+ \DateTime::createFromFormat('Y-F-j', \sprintf('%d-%s-%d', $year->toNative(), $month, $day->toNative()));
+ $nativeDateErrors = \DateTime::getLastErrors();
+
+ if ($nativeDateErrors['warning_count'] > 0 || $nativeDateErrors['error_count'] > 0) {
+ throw new InvalidDateException($year->toNative(), $month->toNative(), $day->toNative());
+ }
+
+ $this->year = $year;
+ $this->month = $month;
+ $this->day = $day;
+ }
+
+ /**
+ * Tells whether two Date are equal by comparing their values
+ *
+ * @param ValueObjectInterface $date
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $date)
+ {
+ if (false === Util::classEquals($this, $date)) {
+ return false;
+ }
+
+ return $this->getYear()->sameValueAs($date->getYear()) &&
+ $this->getMonth()->sameValueAs($date->getMonth()) &&
+ $this->getDay()->sameValueAs($date->getDay());
+ }
+
+ /**
+ * Get year
+ *
+ * @return Year
+ */
+ public function getYear()
+ {
+ return clone $this->year;
+ }
+
+ /**
+ * Get month
+ *
+ * @return Month
+ */
+ public function getMonth()
+ {
+ return $this->month;
+ }
+
+ /**
+ * Get day
+ *
+ * @return MonthDay
+ */
+ public function getDay()
+ {
+ return clone $this->day;
+ }
+
+ /**
+ * Returns a native PHP \DateTime version of the current Date
+ *
+ * @return \DateTime
+ */
+ public function toNativeDateTime()
+ {
+ $year = $this->getYear()->toNative();
+ $month = $this->getMonth()->getNumericValue();
+ $day = $this->getDay()->toNative();
+
+ $date = new \DateTime();
+ $date->setDate($year, $month, $day);
+ $date->setTime(0, 0, 0);
+
+ return $date;
+ }
+
+ /**
+ * Returns date as string in format Y-n-j
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toNativeDateTime()->format('Y-n-j');
+ }
+}
diff --git a/src/DateTime/DateTime.php b/src/DateTime/DateTime.php
new file mode 100644
index 0000000..ca38922
--- /dev/null
+++ b/src/DateTime/DateTime.php
@@ -0,0 +1,145 @@
+date = $date;
+
+ if (null === $time) {
+ $time = Time::zero();
+ }
+
+ $this->time = $time;
+ }
+
+ /**
+ * Tells whether two DateTime are equal by comparing their values
+ *
+ * @param ValueObjectInterface $date_time
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $date_time)
+ {
+ if (false === Util::classEquals($this, $date_time)) {
+ return false;
+ }
+
+ return $this->getDate()->sameValueAs($date_time->getDate()) && $this->getTime()->sameValueAs($date_time->getTime());
+ }
+
+ /**
+ * Returns date from current DateTime
+ *
+ * @return Date
+ */
+ public function getDate()
+ {
+ return clone $this->date;
+ }
+
+ /**
+ * Returns time from current DateTime
+ *
+ * @return Time
+ */
+ public function getTime()
+ {
+ return clone $this->time;
+ }
+
+ /**
+ * Returns a native PHP \DateTime version of the current DateTime.
+ *
+ * @return \DateTime
+ */
+ public function toNativeDateTime()
+ {
+ $year = $this->getDate()->getYear()->toNative();
+ $month = $this->getDate()->getMonth()->getNumericValue();
+ $day = $this->getDate()->getDay()->toNative();
+ $hour = $this->getTime()->getHour()->toNative();
+ $minute = $this->getTime()->getMinute()->toNative();
+ $second = $this->getTime()->getSecond()->toNative();
+
+ $dateTime = new \DateTime();
+ $dateTime->setDate($year, $month, $day);
+ $dateTime->setTime($hour, $minute, $second);
+
+ return $dateTime;
+ }
+
+ /**
+ * Returns DateTime as string in format "Y-n-j G:i:s"
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return \sprintf('%s %s', $this->getDate(), $this->getTime());
+ }
+}
diff --git a/src/DateTime/DateTimeWithTimeZone.php b/src/DateTime/DateTimeWithTimeZone.php
new file mode 100644
index 0000000..bd8cb8b
--- /dev/null
+++ b/src/DateTime/DateTimeWithTimeZone.php
@@ -0,0 +1,163 @@
+getTimezone());
+
+ return new static($datetime, $timezone);
+ }
+
+ /**
+ * Returns a DateTimeWithTimeZone object using current DateTime and default TimeZone
+ *
+ * @return DateTimeWithTimeZone
+ */
+ public static function now()
+ {
+ return new static(DateTime::now(), TimeZone::fromDefault());
+ }
+
+ /**
+ * Returns a new DateTimeWithTimeZone object
+ *
+ * @param DateTime $datetime
+ * @param TimeZone $timezone
+ */
+ public function __construct(DateTime $datetime, TimeZone $timezone = null)
+ {
+ $this->dateTime = $datetime;
+ $this->timeZone = $timezone;
+ }
+
+ /**
+ * Tells whether two DateTimeWithTimeZone are equal by comparing their values
+ *
+ * @param ValueObjectInterface $dateTimeWithTimeZone
+ *
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $dateTimeWithTimeZone)
+ {
+ if (false === Util::classEquals($this, $dateTimeWithTimeZone)) {
+ return false;
+ }
+
+ return $this->getDateTime()->sameValueAs($dateTimeWithTimeZone->getDateTime()) &&
+ $this->getTimeZone()->sameValueAs($dateTimeWithTimeZone->getTimeZone());
+ }
+
+ /**
+ * Tells whether two DateTimeWithTimeZone represents the same timestamp
+ *
+ * @param ValueObjectInterface $dateTimeWithTimeZone
+ *
+ * @return bool
+ */
+ public function sameTimestampAs(ValueObjectInterface $dateTimeWithTimeZone)
+ {
+ if (false === Util::classEquals($this, $dateTimeWithTimeZone)) {
+ return false;
+ }
+
+ return $this->toNativeDateTime() == $dateTimeWithTimeZone->toNativeDateTime();
+ }
+
+ /**
+ * Returns datetime from current DateTimeWithTimeZone
+ *
+ * @return DateTime
+ */
+ public function getDateTime()
+ {
+ return clone $this->dateTime;
+ }
+
+ /**
+ * Returns timezone from current DateTimeWithTimeZone
+ *
+ * @return TimeZone
+ */
+ public function getTimeZone()
+ {
+ return clone $this->timeZone;
+ }
+
+ /**
+ * Returns a native PHP \DateTime version of the current DateTimeWithTimeZone
+ *
+ * @return \DateTime
+ */
+ public function toNativeDateTime()
+ {
+ $date = $this->getDateTime()->getDate();
+ $time = $this->getDateTime()->getTime();
+ $year = $date->getYear()->toNative();
+ $month = $date->getMonth()->getNumericValue();
+ $day = $date->getDay()->toNative();
+ $hour = $time->getHour()->toNative();
+ $minute = $time->getMinute()->toNative();
+ $second = $time->getSecond()->toNative();
+ $timezone = $this->getTimeZone()->toNativeDateTimeZone();
+
+ $dateTime = new \DateTime();
+ $dateTime->setTimezone($timezone);
+ $dateTime->setDate($year, $month, $day);
+ $dateTime->setTime($hour, $minute, $second);
+
+ return $dateTime;
+ }
+
+ /**
+ * Returns DateTime as string in format "Y-n-j G:i:s e"
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return \sprintf('%s %s', $this->getDateTime(), $this->getTimeZone());
+ }
+}
diff --git a/src/DateTime/Exception/InvalidDateException.php b/src/DateTime/Exception/InvalidDateException.php
new file mode 100644
index 0000000..224d26e
--- /dev/null
+++ b/src/DateTime/Exception/InvalidDateException.php
@@ -0,0 +1,13 @@
+ array('min_range' => self::MIN_HOUR, 'max_range' => self::MAX_HOUR)
+ );
+
+ $value = filter_var($value, FILTER_VALIDATE_INT, $options);
+
+ if (false === $value) {
+ throw new InvalidNativeArgumentException($value, array('int (>=0, <=23)'));
+ }
+
+ parent::__construct($value);
+ }
+
+ /**
+ * Returns the current hour.
+ *
+ * @return Hour
+ */
+ public static function now()
+ {
+ $now = new \DateTime('now');
+ $hour = \intval($now->format('G'));
+
+ return new static($hour);
+ }
+}
diff --git a/src/DateTime/Minute.php b/src/DateTime/Minute.php
new file mode 100644
index 0000000..950cc81
--- /dev/null
+++ b/src/DateTime/Minute.php
@@ -0,0 +1,59 @@
+ array('min_range' => self::MIN_MINUTE, 'max_range' => self::MAX_MINUTE)
+ );
+
+ $value = filter_var($value, FILTER_VALIDATE_INT, $options);
+
+ if (false === $value) {
+ throw new InvalidNativeArgumentException($value, array('int (>=0, <=59)'));
+ }
+
+ parent::__construct($value);
+ }
+
+ /**
+ * Returns the current minute.
+ *
+ * @return Minute
+ */
+ public static function now()
+ {
+ $now = new \DateTime('now');
+ $minute = \intval($now->format('i'));
+
+ return new static($minute);
+ }
+}
diff --git a/src/DateTime/Month.php b/src/DateTime/Month.php
new file mode 100644
index 0000000..5fdcf75
--- /dev/null
+++ b/src/DateTime/Month.php
@@ -0,0 +1,57 @@
+format('F'));
+
+ return static::getByName($month);
+ }
+
+ /**
+ * Returns a numeric representation of the Month.
+ * 1 for January to 12 for December.
+ *
+ * @return int
+ */
+ public function getNumericValue()
+ {
+ return $this->getOrdinal() + 1;
+ }
+}
diff --git a/src/DateTime/MonthDay.php b/src/DateTime/MonthDay.php
new file mode 100644
index 0000000..13dbeb8
--- /dev/null
+++ b/src/DateTime/MonthDay.php
@@ -0,0 +1,45 @@
+ array('min_range' => self::MIN_MONTH_DAY, 'max_range' => self::MAX_MONTH_DAY)
+ );
+
+ $value = filter_var($value, FILTER_VALIDATE_INT, $options);
+
+ if (false === $value) {
+ throw new InvalidNativeArgumentException($value, array('int (>=0, <=31)'));
+ }
+
+ parent::__construct($value);
+ }
+
+ /**
+ * Returns the current month day.
+ *
+ * @return MonthDay
+ */
+ public static function now()
+ {
+ $now = new \DateTime('now');
+ $monthDay = \intval($now->format('j'));
+
+ return new static($monthDay);
+ }
+}
diff --git a/src/DateTime/Second.php b/src/DateTime/Second.php
new file mode 100644
index 0000000..ebc2a06
--- /dev/null
+++ b/src/DateTime/Second.php
@@ -0,0 +1,45 @@
+ array('min_range' => self::MIN_SECOND, 'max_range' => self::MAX_SECOND)
+ );
+
+ $value = filter_var($value, FILTER_VALIDATE_INT, $options);
+
+ if (false === $value) {
+ throw new InvalidNativeArgumentException($value, array('int (>=0, <=59)'));
+ }
+
+ parent::__construct($value);
+ }
+
+ /**
+ * Returns the current second.
+ *
+ * @return Second
+ */
+ public static function now()
+ {
+ $now = new \DateTime('now');
+ $second = \intval($now->format('s'));
+
+ return new static($second);
+ }
+}
diff --git a/src/DateTime/Time.php b/src/DateTime/Time.php
new file mode 100644
index 0000000..bc1f3a2
--- /dev/null
+++ b/src/DateTime/Time.php
@@ -0,0 +1,163 @@
+format('G'));
+ $minute = \intval($time->format('i'));
+ $second = \intval($time->format('s'));
+
+ return static::fromNative($hour, $minute, $second);
+ }
+
+ /**
+ * Returns current Time
+ *
+ * @return self
+ */
+ public static function now()
+ {
+ $time = new static(Hour::now(), Minute::now(), Second::now());
+
+ return $time;
+ }
+
+ /**
+ * Return zero time
+ *
+ * @return static
+ */
+ public static function zero()
+ {
+ $time = new static(new Hour(0), new Minute(0), new Second(0));
+
+ return $time;
+ }
+
+ /**
+ * Returns a new Time objects
+ *
+ * @param Hour $hour
+ * @param Minute $minute
+ * @param Second $second
+ */
+ public function __construct(Hour $hour, Minute $minute, Second $second)
+ {
+ $this->hour = $hour;
+ $this->minute = $minute;
+ $this->second = $second;
+ }
+
+ /**
+ * Tells whether two Time are equal by comparing their values
+ *
+ * @param ValueObjectInterface $time
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $time)
+ {
+ if (false === Util::classEquals($this, $time)) {
+ return false;
+ }
+
+ return $this->getHour()->sameValueAs($time->getHour()) && $this->getMinute()->sameValueAs($time->getMinute()) && $this->getSecond()->sameValueAs($time->getSecond());
+ }
+
+ /**
+ * Get hour
+ *
+ * @return Hour
+ */
+ public function getHour()
+ {
+ return $this->hour;
+ }
+
+ /**
+ * Get minute
+ *
+ * @return Minute
+ */
+ public function getMinute()
+ {
+ return $this->minute;
+ }
+
+ /**
+ * Get second
+ *
+ * @return Second
+ */
+ public function getSecond()
+ {
+ return $this->second;
+ }
+
+ /**
+ * Returns a native PHP \DateTime version of the current Time.
+ * Date is set to current.
+ *
+ * @return \DateTime
+ */
+ public function toNativeDateTime()
+ {
+ $hour = $this->getHour()->toNative();
+ $minute = $this->getMinute()->toNative();
+ $second = $this->getSecond()->toNative();
+
+ $time = new \DateTime('now');
+ $time->setTime($hour, $minute, $second);
+
+ return $time;
+ }
+
+ /**
+ * Returns time as string in format G:i:s
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toNativeDateTime()->format('G:i:s');
+ }
+}
diff --git a/src/DateTime/TimeZone.php b/src/DateTime/TimeZone.php
new file mode 100644
index 0000000..a24a053
--- /dev/null
+++ b/src/DateTime/TimeZone.php
@@ -0,0 +1,110 @@
+getName());
+ }
+
+ /**
+ * Returns default TimeZone
+ *
+ * @return self
+ */
+ public static function fromDefault()
+ {
+ return new static(new StringLiteral(date_default_timezone_get()));
+ }
+
+ /**
+ * Returns a new TimeZone object
+ *
+ * @param StringLiteral $name
+ * @throws InvalidTimeZoneException
+ */
+ public function __construct(StringLiteral $name)
+ {
+ if (!in_array($name->toNative(), timezone_identifiers_list())) {
+ throw new InvalidTimeZoneException($name);
+ }
+
+ $this->name = $name;
+ }
+
+ /**
+ * Returns a native PHP \DateTimeZone version of the current TimeZone.
+ *
+ * @return \DateTimeZone
+ */
+ public function toNativeDateTimeZone()
+ {
+ return new \DateTimeZone($this->getName()->toNative());
+ }
+
+ /**
+ * Tells whether two DateTimeZone are equal by comparing their names
+ *
+ * @param ValueObjectInterface $timezone
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $timezone)
+ {
+ if (false === Util::classEquals($this, $timezone)) {
+ return false;
+ }
+
+ return $this->getName()->sameValueAs($timezone->getName());
+ }
+
+ /**
+ * Returns timezone name
+ *
+ * @return StringLiteral
+ */
+ public function getName()
+ {
+ return clone $this->name;
+ }
+
+ /**
+ * Returns timezone name as string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getName()->__toString();
+ }
+}
diff --git a/src/DateTime/WeekDay.php b/src/DateTime/WeekDay.php
new file mode 100644
index 0000000..d501d0a
--- /dev/null
+++ b/src/DateTime/WeekDay.php
@@ -0,0 +1,52 @@
+format('l'));
+
+ return static::getByName($weekDay);
+ }
+
+ /**
+ * Returns a numeric representation of the WeekDay.
+ * 1 for Monday to 7 for Sunday.
+ *
+ * @return int
+ */
+ public function getNumericValue()
+ {
+ return $this->getOrdinal() + 1;
+ }
+}
diff --git a/src/DateTime/Year.php b/src/DateTime/Year.php
new file mode 100644
index 0000000..e5da23e
--- /dev/null
+++ b/src/DateTime/Year.php
@@ -0,0 +1,21 @@
+format('Y'));
+
+ return new static($year);
+ }
+}
diff --git a/src/Enum/Enum.php b/src/Enum/Enum.php
new file mode 100644
index 0000000..6ae2a16
--- /dev/null
+++ b/src/Enum/Enum.php
@@ -0,0 +1,56 @@
+toNative() === $enum->toNative();
+ }
+
+ /**
+ * Returns a native string representation of the Enum value
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return \strval($this->toNative());
+ }
+}
diff --git a/src/Exception/InvalidNativeArgumentException.php b/src/Exception/InvalidNativeArgumentException.php
new file mode 100644
index 0000000..141373c
--- /dev/null
+++ b/src/Exception/InvalidNativeArgumentException.php
@@ -0,0 +1,11 @@
+message = sprintf('Argument "%s" is invalid. Allowed types for argument are "%s".', $value, implode(', ', $allowed_types));
+ }
+}
diff --git a/src/Geography/Address.php b/src/Geography/Address.php
new file mode 100644
index 0000000..0d8a163
--- /dev/null
+++ b/src/Geography/Address.php
@@ -0,0 +1,212 @@
+name = $name;
+ $this->street = $street;
+ $this->district = $district;
+ $this->city = $city;
+ $this->region = $region;
+ $this->postalCode = $postalCode;
+ $this->country = $country;
+ }
+
+ /**
+ * Tells whether two Address are equal
+ *
+ * @param ValueObjectInterface $address
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $address)
+ {
+ if (false === Util::classEquals($this, $address)) {
+ return false;
+ }
+
+ return $this->getName()->sameValueAs($address->getName()) &&
+ $this->getStreet()->sameValueAs($address->getStreet()) &&
+ $this->getDistrict()->sameValueAs($address->getDistrict()) &&
+ $this->getCity()->sameValueAs($address->getCity()) &&
+ $this->getRegion()->sameValueAs($address->getRegion()) &&
+ $this->getPostalCode()->sameValueAs($address->getPostalCode()) &&
+ $this->getCountry()->sameValueAs($address->getCountry())
+ ;
+ }
+
+ /**
+ * Returns addressee name
+ *
+ * @return StringLiteral
+ */
+ public function getName()
+ {
+ return clone $this->name;
+ }
+
+ /**
+ * Returns street
+ *
+ * @return Street
+ */
+ public function getStreet()
+ {
+ return clone $this->street;
+ }
+
+ /**
+ * Returns district
+ *
+ * @return StringLiteral
+ */
+ public function getDistrict()
+ {
+ return clone $this->district;
+ }
+
+ /**
+ * Returns city
+ *
+ * @return StringLiteral
+ */
+ public function getCity()
+ {
+ return clone $this->city;
+ }
+
+ /**
+ * Returns region
+ *
+ * @return StringLiteral
+ */
+ public function getRegion()
+ {
+ return clone $this->region;
+ }
+
+ /**
+ * Returns postal code
+ *
+ * @return StringLiteral
+ */
+ public function getPostalCode()
+ {
+ return clone $this->postalCode;
+ }
+
+ /**
+ * Returns country
+ *
+ * @return Country
+ */
+ public function getCountry()
+ {
+ return clone $this->country;
+ }
+
+ /**
+ * Returns a string representation of the Address in US standard format.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $format = <<getName(), $this->getStreet(), $this->getCity(), $this->getRegion(), $this->getPostalCode(), $this->getCountry());
+
+ return $addressString;
+ }
+}
diff --git a/src/Geography/Continent.php b/src/Geography/Continent.php
new file mode 100644
index 0000000..daadb42
--- /dev/null
+++ b/src/Geography/Continent.php
@@ -0,0 +1,16 @@
+ 3) {
+ throw new \BadMethodCallException('You must provide 2 to 3 arguments: 1) latitude, 2) longitude, 3) valid ellipsoid type (optional)');
+ }
+
+ $coordinate = new BaseCoordinate(array($args[0], $args[1]));
+ $latitude = Latitude::fromNative($coordinate->getLatitude());
+ $longitude = Longitude::fromNative($coordinate->getLongitude());
+
+ $nativeEllipsoid = isset($args[2]) ? $args[2] : null;
+ $ellipsoid = Ellipsoid::fromNative($nativeEllipsoid);
+
+ return new static($latitude, $longitude, $ellipsoid);
+ }
+
+ /**
+ * Returns a new Coordinate object
+ *
+ * @param Latitude $latitude
+ * @param Longitude $longitude
+ * @param Ellipsoid $ellipsoid
+ */
+ public function __construct(Latitude $latitude, Longitude $longitude, Ellipsoid $ellipsoid = null)
+ {
+ if (null === $ellipsoid) {
+ $ellipsoid = Ellipsoid::WGS84();
+ }
+
+ $this->latitude = $latitude;
+ $this->longitude = $longitude;
+ $this->ellipsoid = $ellipsoid;
+ }
+
+ /**
+ * Tells whether tow Coordinate objects are equal
+ *
+ * @param ValueObjectInterface $coordinate
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $coordinate)
+ {
+ if (false === Util::classEquals($this, $coordinate)) {
+ return false;
+ }
+
+ return $this->getLatitude()->sameValueAs($coordinate->getLatitude()) &&
+ $this->getLongitude()->sameValueAs($coordinate->getLongitude()) &&
+ $this->getEllipsoid()->sameValueAs($coordinate->getEllipsoid())
+ ;
+ }
+
+ /**
+ * Returns latitude
+ *
+ * @return Latitude
+ */
+ public function getLatitude()
+ {
+ return clone $this->latitude;
+ }
+
+ /**
+ * Returns longitude
+ *
+ * @return Longitude
+ */
+ public function getLongitude()
+ {
+ return clone $this->longitude;
+ }
+
+ /**
+ * Returns ellipsoid
+ *
+ * @return Ellipsoid
+ */
+ public function getEllipsoid()
+ {
+ return $this->ellipsoid;
+ }
+
+ /**
+ * Returns a degrees/minutes/seconds representation of the coordinate
+ *
+ * @return StringLiteral
+ */
+ public function toDegreesMinutesSeconds()
+ {
+ $coordinate = static::getBaseCoordinate($this);
+ $convert = new Convert($coordinate);
+ $dms = $convert->toDegreesMinutesSeconds();
+
+ return new StringLiteral($dms);
+ }
+
+ /**
+ * Returns a decimal minutes representation of the coordinate
+ *
+ * @return StringLiteral
+ */
+ public function toDecimalMinutes()
+ {
+ $coordinate = static::getBaseCoordinate($this);
+ $convert = new Convert($coordinate);
+ $dm = $convert->toDecimalMinutes();
+
+ return new StringLiteral($dm);
+ }
+
+ /**
+ * Returns a Universal Transverse Mercator projection representation of the coordinate in meters
+ *
+ * @return StringLiteral
+ */
+ public function toUniversalTransverseMercator()
+ {
+ $coordinate = static::getBaseCoordinate($this);
+ $convert = new Convert($coordinate);
+ $utm = $convert->toUniversalTransverseMercator();
+
+ return new StringLiteral($utm);
+ }
+
+ /**
+ * Calculates the distance between two Coordinate objects
+ *
+ * @param Coordinate $coordinate
+ * @param DistanceUnit $unit
+ * @param DistanceFormula $formula
+ * @return Real
+ */
+ public function distanceFrom(Coordinate $coordinate, DistanceUnit $unit = null, DistanceFormula $formula = null)
+ {
+ if (null === $unit) {
+ $unit = DistanceUnit::METER();
+ }
+
+ if (null === $formula) {
+ $formula = DistanceFormula::FLAT();
+ }
+
+ $baseThis = static::getBaseCoordinate($this);
+ $baseCoordinate = static::getBaseCoordinate($coordinate);
+
+ $distance = new Distance();
+ $distance
+ ->setFrom($baseThis)
+ ->setTo($baseCoordinate)
+ ->in($unit->toNative())
+ ;
+
+ $value = \call_user_func(array($distance, $formula->toNative()));
+
+ return new Real($value);
+ }
+
+ /**
+ * Returns a native string version of the Coordiantes object in format "$latitude,$longitude"
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return \sprintf('%F,%F', $this->getLatitude()->toNative(), $this->getLongitude()->toNative());
+ }
+
+ /**
+ * Returns the underlying Coordinate object
+ *
+ * @param self $coordinate
+ * @return BaseCoordinate
+ */
+ protected static function getBaseCoordinate(self $coordinate)
+ {
+ $latitude = $coordinate->getLatitude()->toNative();
+ $longitude = $coordinate->getLongitude()->toNative();
+ $ellipsoid = BaseEllipsoid::createFromName($coordinate->getEllipsoid()->toNative());
+ $coordinate = new BaseCoordinate(array($latitude, $longitude), $ellipsoid);
+
+ return $coordinate;
+ }
+}
diff --git a/src/Geography/Country.php b/src/Geography/Country.php
new file mode 100644
index 0000000..9226e85
--- /dev/null
+++ b/src/Geography/Country.php
@@ -0,0 +1,85 @@
+code = $code;
+ }
+
+ /**
+ * Tells whether two Country are equal
+ *
+ * @param ValueObjectInterface $country
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $country)
+ {
+ if (false === Util::classEquals($this, $country)) {
+ return false;
+ }
+
+ return $this->getCode()->sameValueAs($country->getCode());
+ }
+
+ /**
+ * Returns country code
+ *
+ * @return CountryCode
+ */
+ public function getCode()
+ {
+ return $this->code;
+ }
+
+ /**
+ * Returns country name
+ *
+ * @return StringLiteral
+ */
+ public function getName()
+ {
+ $code = $this->getCode();
+ $name = CountryCodeName::getName($code);
+
+ return $name;
+ }
+
+ /**
+ * Returns country name as native string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getName()->toNative();
+ }
+}
diff --git a/src/Geography/CountryCode.php b/src/Geography/CountryCode.php
new file mode 100644
index 0000000..161ba34
--- /dev/null
+++ b/src/Geography/CountryCode.php
@@ -0,0 +1,253 @@
+ 'Afghanistan',
+ 'AX' => 'Åland Islands',
+ 'AL' => 'Albania',
+ 'DZ' => 'Algeria',
+ 'AD' => 'Andorra',
+ 'AO' => 'Angola',
+ 'AI' => 'Anguilla',
+ 'AQ' => 'Antarctica',
+ 'AG' => 'Antigua and Barbuda',
+ 'AR' => 'Argentina',
+ 'AM' => 'Armenia',
+ 'AW' => 'Aruba',
+ 'AU' => 'Australia',
+ 'AT' => 'Austria',
+ 'AZ' => 'Azerbaijan',
+ 'BS' => 'Bahamas',
+ 'BH' => 'Bahrain',
+ 'BD' => 'Bangladesh',
+ 'BB' => 'Barbados',
+ 'BY' => 'Belarus',
+ 'BE' => 'Belgium',
+ 'PW' => 'Belau',
+ 'BZ' => 'Belize',
+ 'BJ' => 'Benin',
+ 'BM' => 'Bermuda',
+ 'BT' => 'Bhutan',
+ 'BO' => 'Bolivia',
+ 'BQ' => 'Bonaire, Saint Eustatius and Saba',
+ 'BA' => 'Bosnia and Herzegovina',
+ 'BW' => 'Botswana',
+ 'BV' => 'Bouvet Island',
+ 'BR' => 'Brazil',
+ 'IO' => 'British Indian Ocean Territory',
+ 'VG' => 'British Virgin Islands',
+ 'BN' => 'Brunei',
+ 'BG' => 'Bulgaria',
+ 'BF' => 'Burkina Faso',
+ 'BI' => 'Burundi',
+ 'KH' => 'Cambodia',
+ 'CM' => 'Cameroon',
+ 'CA' => 'Canada',
+ 'CV' => 'Cape Verde',
+ 'KY' => 'Cayman Islands',
+ 'CF' => 'Central African Republic',
+ 'TD' => 'Chad',
+ 'CL' => 'Chile',
+ 'CN' => 'China',
+ 'CX' => 'Christmas Island',
+ 'CC' => 'Cocos (Keeling) Islands',
+ 'CO' => 'Colombia',
+ 'KM' => 'Comoros',
+ 'CG' => 'Congo (Brazzaville)',
+ 'CD' => 'Congo (Kinshasa)',
+ 'CK' => 'Cook Islands',
+ 'CR' => 'Costa Rica',
+ 'HR' => 'Croatia',
+ 'CU' => 'Cuba',
+ 'CW' => 'Curaçao',
+ 'CY' => 'Cyprus',
+ 'CZ' => 'Czech Republic',
+ 'DK' => 'Denmark',
+ 'DJ' => 'Djibouti',
+ 'DM' => 'Dominica',
+ 'DO_' => 'Dominican Republic',
+ 'EC' => 'Ecuador',
+ 'EG' => 'Egypt',
+ 'SV' => 'El Salvador',
+ 'GQ' => 'Equatorial Guinea',
+ 'ER' => 'Eritrea',
+ 'EE' => 'Estonia',
+ 'ET' => 'Ethiopia',
+ 'FK' => 'Falkland Islands',
+ 'FO' => 'Faroe Islands',
+ 'FJ' => 'Fiji',
+ 'FI' => 'Finland',
+ 'FR' => 'France',
+ 'GF' => 'French Guiana',
+ 'PF' => 'French Polynesia',
+ 'TF' => 'French Southern Territories',
+ 'GA' => 'Gabon',
+ 'GM' => 'Gambia',
+ 'GE' => 'Georgia',
+ 'DE' => 'Germany',
+ 'GH' => 'Ghana',
+ 'GI' => 'Gibraltar',
+ 'GR' => 'Greece',
+ 'GL' => 'Greenland',
+ 'GD' => 'Grenada',
+ 'GP' => 'Guadeloupe',
+ 'GT' => 'Guatemala',
+ 'GG' => 'Guernsey',
+ 'GN' => 'Guinea',
+ 'GW' => 'Guinea-Bissau',
+ 'GY' => 'Guyana',
+ 'HT' => 'Haiti',
+ 'HM' => 'Heard Island and McDonald Islands',
+ 'HN' => 'Honduras',
+ 'HK' => 'Hong Kong',
+ 'HU' => 'Hungary',
+ 'IS' => 'Iceland',
+ 'IN' => 'India',
+ 'ID' => 'Indonesia',
+ 'IR' => 'Iran',
+ 'IQ' => 'Iraq',
+ 'IE' => 'Republic of Ireland',
+ 'IM' => 'Isle of Man',
+ 'IL' => 'Israel',
+ 'IT' => 'Italy',
+ 'CI' => 'Ivory Coast',
+ 'JM' => 'Jamaica',
+ 'JP' => 'Japan',
+ 'JE' => 'Jersey',
+ 'JO' => 'Jordan',
+ 'KZ' => 'Kazakhstan',
+ 'KE' => 'Kenya',
+ 'KI' => 'Kiribati',
+ 'KW' => 'Kuwait',
+ 'KG' => 'Kyrgyzstan',
+ 'LA' => 'Laos',
+ 'LV' => 'Latvia',
+ 'LB' => 'Lebanon',
+ 'LS' => 'Lesotho',
+ 'LR' => 'Liberia',
+ 'LY' => 'Libya',
+ 'LI' => 'Liechtenstein',
+ 'LT' => 'Lithuania',
+ 'LU' => 'Luxembourg',
+ 'MO' => 'Macao S.A.R., China',
+ 'MK' => 'Macedonia',
+ 'MG' => 'Madagascar',
+ 'MW' => 'Malawi',
+ 'MY' => 'Malaysia',
+ 'MV' => 'Maldives',
+ 'ML' => 'Mali',
+ 'MT' => 'Malta',
+ 'MH' => 'Marshall Islands',
+ 'MQ' => 'Martinique',
+ 'MR' => 'Mauritania',
+ 'MU' => 'Mauritius',
+ 'YT' => 'Mayotte',
+ 'MX' => 'Mexico',
+ 'FM' => 'Micronesia',
+ 'MD' => 'Moldova',
+ 'MC' => 'Monaco',
+ 'MN' => 'Mongolia',
+ 'ME' => 'Montenegro',
+ 'MS' => 'Montserrat',
+ 'MA' => 'Morocco',
+ 'MZ' => 'Mozambique',
+ 'MM' => 'Myanmar',
+ 'NA' => 'Namibia',
+ 'NR' => 'Nauru',
+ 'NP' => 'Nepal',
+ 'NL' => 'Netherlands',
+ 'AN' => 'Netherlands Antilles',
+ 'NC' => 'New Caledonia',
+ 'NZ' => 'New Zealand',
+ 'NI' => 'Nicaragua',
+ 'NE' => 'Niger',
+ 'NG' => 'Nigeria',
+ 'NU' => 'Niue',
+ 'NF' => 'Norfolk Island',
+ 'KP' => 'North Korea',
+ 'NO' => 'Norway',
+ 'OM' => 'Oman',
+ 'PK' => 'Pakistan',
+ 'PS' => 'Palestinian Territory',
+ 'PA' => 'Panama',
+ 'PG' => 'Papua New Guinea',
+ 'PY' => 'Paraguay',
+ 'PE' => 'Peru',
+ 'PH' => 'Philippines',
+ 'PN' => 'Pitcairn',
+ 'PL' => 'Poland',
+ 'PT' => 'Portugal',
+ 'QA' => 'Qatar',
+ 'RE' => 'Reunion',
+ 'RO' => 'Romania',
+ 'RU' => 'Russia',
+ 'RW' => 'Rwanda',
+ 'BL' => 'Saint-Barthélemy',
+ 'SH' => 'Saint Helena',
+ 'KN' => 'Saint Kitts and Nevis',
+ 'LC' => 'Saint Lucia',
+ 'MF' => 'Saint Martin (French part)',
+ 'SX' => 'Saint Martin (Dutch part)',
+ 'PM' => 'Saint Pierre and Miquelon',
+ 'VC' => 'Saint Vincent and the Grenadines',
+ 'WS' => 'Samoa',
+ 'SM' => 'San Marino',
+ 'ST' => 'São Tomé and Príncipe',
+ 'SA' => 'Saudi Arabia',
+ 'SN' => 'Senegal',
+ 'RS' => 'Serbia',
+ 'SC' => 'Seychelles',
+ 'SL' => 'Sierra Leone',
+ 'SG' => 'Singapore',
+ 'SK' => 'Slovakia',
+ 'SI' => 'Slovenia',
+ 'SB' => 'Solomon Islands',
+ 'SO' => 'Somalia',
+ 'ZA' => 'South Africa',
+ 'GS' => 'South Georgia/Sandwich Islands',
+ 'KR' => 'South Korea',
+ 'SS' => 'South Sudan',
+ 'ES' => 'Spain',
+ 'LK' => 'Sri Lanka',
+ 'SD' => 'Sudan',
+ 'SR' => 'Suriname',
+ 'SJ' => 'Svalbard and Jan Mayen',
+ 'SZ' => 'Swaziland',
+ 'SE' => 'Sweden',
+ 'CH' => 'Switzerland',
+ 'SY' => 'Syria',
+ 'TW' => 'Taiwan',
+ 'TJ' => 'Tajikistan',
+ 'TZ' => 'Tanzania',
+ 'TH' => 'Thailand',
+ 'TL' => 'Timor-Leste',
+ 'TG' => 'Togo',
+ 'TK' => 'Tokelau',
+ 'TO' => 'Tonga',
+ 'TT' => 'Trinidad and Tobago',
+ 'TN' => 'Tunisia',
+ 'TR' => 'Turkey',
+ 'TM' => 'Turkmenistan',
+ 'TC' => 'Turks and Caicos Islands',
+ 'TV' => 'Tuvalu',
+ 'UG' => 'Uganda',
+ 'UA' => 'Ukraine',
+ 'AE' => 'United Arab Emirates',
+ 'GB' => 'United Kingdom',
+ 'US' => 'United States',
+ 'UY' => 'Uruguay',
+ 'UZ' => 'Uzbekistan',
+ 'VU' => 'Vanuatu',
+ 'VA' => 'Vatican',
+ 'VE' => 'Venezuela',
+ 'VN' => 'Vietnam',
+ 'WF' => 'Wallis and Futuna',
+ 'EH' => 'Western Sahara',
+ 'YE' => 'Yemen',
+ 'ZM' => 'Zambia',
+ 'ZW' => 'Zimbabwe',
+ );
+
+ /**
+ * Returns country name
+ *
+ * @param CountryCode $code
+ * @return StringLiteral
+ */
+ public static function getName(CountryCode $code)
+ {
+ $codeValue = $code->toNative();
+ $name = self::$names[$codeValue];
+
+ return new StringLiteral($name);
+ }
+}
diff --git a/src/Geography/DistanceFormula.php b/src/Geography/DistanceFormula.php
new file mode 100644
index 0000000..2fedabd
--- /dev/null
+++ b/src/Geography/DistanceFormula.php
@@ -0,0 +1,12 @@
+getLatitude();
+
+ $this->value = $latitude;
+ }
+}
diff --git a/src/Geography/Longitude.php b/src/Geography/Longitude.php
new file mode 100644
index 0000000..4e84e4b
--- /dev/null
+++ b/src/Geography/Longitude.php
@@ -0,0 +1,31 @@
+getLongitude();
+
+ $this->value = $longitude;
+ }
+}
diff --git a/src/Geography/Street.php b/src/Geography/Street.php
new file mode 100644
index 0000000..2c358b2
--- /dev/null
+++ b/src/Geography/Street.php
@@ -0,0 +1,141 @@
+name = $name;
+ $this->number = $number;
+
+ if ($elements === null) {
+ $elements = new StringLiteral('');
+ }
+ $this->elements = $elements;
+
+ if ($format === null) {
+ $format = new StringLiteral('%number% %name%');
+ }
+ $this->format = $format;
+ }
+
+ /**
+ * Tells whether two Street objects are equal
+ * @param ValueObjectInterface $street
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $street)
+ {
+ if (false === Util::classEquals($this, $street)) {
+ return false;
+ }
+
+ return $this->getName()->sameValueAs($street->getName()) &&
+ $this->getNumber()->sameValueAs($street->getNumber()) &&
+ $this->getElements()->sameValueAs($street->getElements())
+ ;
+ }
+
+ /**
+ * Returns street name
+ *
+ * @return StringLiteral
+ */
+ public function getName()
+ {
+ return clone $this->name;
+ }
+
+ /**
+ * Returns street number
+ *
+ * @return StringLiteral
+ */
+ public function getNumber()
+ {
+ return clone $this->number;
+ }
+
+ /**
+ * Returns street elements
+ * @return StringLiteral
+ */
+ public function getElements()
+ {
+ return clone $this->elements;
+ }
+
+ /**
+ * Returns a string representation of the StringLiteral in the format defined in the constructor
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $replacements = array(
+ "%name%" => $this->getName(),
+ "%number%" => $this->getNumber(),
+ "%elements%" => $this->getElements()
+ );
+
+ $streetString = str_replace(array_keys($replacements), array_values($replacements), $this->format);
+
+ return $streetString;
+ }
+}
diff --git a/src/Identity/UUID.php b/src/Identity/UUID.php
new file mode 100644
index 0000000..af26ced
--- /dev/null
+++ b/src/Identity/UUID.php
@@ -0,0 +1,73 @@
+toNative();
+
+ return $uuidString;
+ }
+
+ public function __construct($value = null)
+ {
+ $uuid_str = BaseUuid::uuid4();
+
+ if (null !== $value) {
+ $pattern = '/'.BaseUuid::VALID_PATTERN.'/';
+
+ if (! \preg_match($pattern, $value)) {
+ throw new InvalidNativeArgumentException($value, array('UUID string'));
+ }
+
+ $uuid_str = $value;
+ }
+
+ $this->value = \strval($uuid_str);
+ }
+
+ /**
+ * Tells whether two UUID are equal by comparing their values
+ *
+ * @param UUID $uuid
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $uuid)
+ {
+ if (false === Util::classEquals($this, $uuid)) {
+ return false;
+ }
+
+ return $this->toNative() === $uuid->toNative();
+ }
+}
diff --git a/src/Money/Currency.php b/src/Money/Currency.php
new file mode 100644
index 0000000..2bd1496
--- /dev/null
+++ b/src/Money/Currency.php
@@ -0,0 +1,70 @@
+code = $code;
+ $this->currency = new BaseCurrency($code->toNative());
+ }
+
+ /**
+ * Tells whether two Currency are equal by comparing their names
+ *
+ * @param ValueObjectInterface $currency
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $currency)
+ {
+ if (false === Util::classEquals($this, $currency)) {
+ return false;
+ }
+
+ return $this->getCode()->toNative() == $currency->getCode()->toNative();
+ }
+
+ /**
+ * Returns currency code
+ *
+ * @return CurrencyCode
+ */
+ public function getCode()
+ {
+ return $this->code;
+ }
+
+ /**
+ * Returns string representation of the currency
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getCode()->toNative();
+ }
+}
diff --git a/src/Money/CurrencyCode.php b/src/Money/CurrencyCode.php
new file mode 100644
index 0000000..3fa63b8
--- /dev/null
+++ b/src/Money/CurrencyCode.php
@@ -0,0 +1,169 @@
+getCode()->toNative());
+ $this->money = new BaseMoney($amount->toNative(), $baseCurrency);
+ $this->currency = $currency;
+ }
+
+ /**
+ * Tells whether two Currency are equal by comparing their amount and currency
+ *
+ * @param ValueObjectInterface $money
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $money)
+ {
+ if (false === Util::classEquals($this, $money)) {
+ return false;
+ }
+
+ return $this->getAmount()->sameValueAs($money->getAmount()) && $this->getCurrency()->sameValueAs($money->getCurrency());
+ }
+
+ /**
+ * Returns money amount
+ *
+ * @return \ValueObjects\Number\Integer
+ */
+ public function getAmount()
+ {
+ $amount = new Integer($this->money->getAmount());
+
+ return $amount;
+ }
+
+ /**
+ * Returns money currency
+ *
+ * @return Currency
+ */
+ public function getCurrency()
+ {
+ return clone $this->currency;
+ }
+
+ /**
+ * Add an integer quantity to the amount and returns a new Money object.
+ * Use a negative quantity for subtraction.
+ *
+ * @param \ValueObjects\Number\Integer $quantity Quantity to add
+ * @return Money
+ */
+ public function add(Integer $quantity)
+ {
+ $amount = new Integer($this->getAmount()->toNative() + $quantity->toNative());
+ $result = new static($amount, $this->getCurrency());
+
+ return $result;
+ }
+
+ /**
+ * Multiply the Money amount for a given number and returns a new Money object.
+ * Use 0 < Real $multipler < 1 for division.
+ *
+ * @param Real $multiplier
+ * @param mixed $rounding_mode Rounding mode of the operation. Defaults to RoundingMode::HALF_UP.
+ * @return Money
+ */
+ public function multiply(Real $multiplier, RoundingMode $rounding_mode = null)
+ {
+ if (null === $rounding_mode) {
+ $rounding_mode = RoundingMode::HALF_UP();
+ }
+
+ $amount = $this->getAmount()->toNative() * $multiplier->toNative();
+ $roundedAmount = new Integer(round($amount, 0, $rounding_mode->toNative()));
+ $result = new static($roundedAmount, $this->getCurrency());
+
+ return $result;
+ }
+
+ /**
+ * Returns a string representation of the Money value in format "CUR AMOUNT" (e.g.: EUR 1000)
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return \sprintf('%s %d', $this->getCurrency()->getCode(), $this->getAmount()->toNative());
+ }
+}
diff --git a/src/NullValue/NullValue.php b/src/NullValue/NullValue.php
new file mode 100644
index 0000000..1ec0930
--- /dev/null
+++ b/src/NullValue/NullValue.php
@@ -0,0 +1,47 @@
+toNative() * \cos($argument->toNative());
+ $imValue = $modulus->toNative() * \sin($argument->toNative());
+ $real = new Real($realValue);
+ $im = new Real($imValue);
+ $complex = new static($real, $im);
+
+ return $complex;
+ }
+
+ /**
+ * Returns a Complex object give its real and imaginary parts as parameters
+ *
+ * @param Real $real
+ * @param Real $im
+ */
+ public function __construct(Real $real, Real $im)
+ {
+ $this->real = $real;
+ $this->im = $im;
+ }
+
+ public function sameValueAs(ValueObjectInterface $complex)
+ {
+ if (false === Util::classEquals($this, $complex)) {
+ return false;
+ }
+
+ return $this->getReal()->sameValueAs($complex->getReal()) &&
+ $this->getIm()->sameValueAs($complex->getIm());
+ }
+
+ /**
+ * Returns the native value of the real and imaginary parts as an array
+ *
+ * @return array
+ */
+ public function toNative()
+ {
+ return array(
+ $this->getReal()->toNative(),
+ $this->getIm()->toNative()
+ );
+ }
+
+ /**
+ * Returns the real part of the complex number
+ *
+ * @return Real
+ */
+ public function getReal()
+ {
+ return clone $this->real;
+ }
+
+ /**
+ * Returns the imaginary part of the complex number
+ *
+ * @return Real
+ */
+ public function getIm()
+ {
+ return clone $this->im;
+ }
+
+ /**
+ * Returns the modulus (or absolute value or magnitude) of the Complex number
+ *
+ * @return Real
+ */
+ public function getModulus()
+ {
+ $real = $this->getReal()->toNative();
+ $im = $this->getIm()->toNative();
+ $mod = \sqrt(\pow($real, 2) + \pow($im, 2));
+
+ return new Real($mod);
+ }
+
+ /**
+ * Returns the argument (or phase) of the Complex number
+ *
+ * @return Real
+ */
+ public function getArgument()
+ {
+ $real = $this->getReal()->toNative();
+ $im = $this->getIm()->toNative();
+ $arg = \atan2($im, $real);
+
+ return new Real($arg);
+ }
+
+ /**
+ * Returns a native string version of the Complex object in format "${real} +|- ${complex}i"
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $format = '%g %+gi';
+ $real = $this->getReal()->toNative();
+ $im = $this->getIm()->toNative();
+ $string = \sprintf($format, $real, $im);
+
+ return \preg_replace('/(\+|-)/', '$1 ', $string);
+ }
+}
diff --git a/src/Number/Integer.php b/src/Number/Integer.php
new file mode 100644
index 0000000..b53ad82
--- /dev/null
+++ b/src/Number/Integer.php
@@ -0,0 +1,66 @@
+toNative() === $integer->toNative();
+ }
+
+ /**
+ * Returns the value of the integer number
+ *
+ * @return int
+ */
+ public function toNative()
+ {
+ $value = parent::toNative();
+
+ return \intval($value);
+ }
+
+ /**
+ * Returns a Real with the value of the Integer
+ *
+ * @return Real
+ */
+ public function toReal()
+ {
+ $value = $this->toNative();
+ $real = new Real($value);
+
+ return $real;
+ }
+}
diff --git a/src/Number/Natural.php b/src/Number/Natural.php
new file mode 100644
index 0000000..261fa36
--- /dev/null
+++ b/src/Number/Natural.php
@@ -0,0 +1,30 @@
+ array(
+ 'min_range' => 0
+ )
+ );
+
+ $value = filter_var($value, FILTER_VALIDATE_INT, $options);
+
+ if (false === $value) {
+ throw new InvalidNativeArgumentException($value, array('int (>=0)'));
+ }
+
+ parent::__construct($value);
+ }
+}
diff --git a/src/Number/NumberInterface.php b/src/Number/NumberInterface.php
new file mode 100644
index 0000000..950db61
--- /dev/null
+++ b/src/Number/NumberInterface.php
@@ -0,0 +1,13 @@
+value = $value;
+ }
+
+ /**
+ * Returns the native value of the real number
+ *
+ * @return float
+ */
+ public function toNative()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Tells whether two Real are equal by comparing their values
+ *
+ * @param ValueObjectInterface $real
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $real)
+ {
+ if (false === Util::classEquals($this, $real)) {
+ return false;
+ }
+
+ return $this->toNative() === $real->toNative();
+ }
+
+ /**
+ * Returns the integer part of the Real number as a Integer
+ *
+ * @param RoundingMode $rounding_mode Rounding mode of the conversion. Defaults to RoundingMode::HALF_UP.
+ * @return Integer
+ */
+ public function toInteger(RoundingMode $rounding_mode = null)
+ {
+ if (null === $rounding_mode) {
+ $rounding_mode = RoundingMode::HALF_UP();
+ }
+
+ $value = $this->toNative();
+ $integerValue = \round($value, 0, $rounding_mode->toNative());
+ $integer = new Integer($integerValue);
+
+ return $integer;
+ }
+
+ /**
+ * Returns the absolute integer part of the Real number as a Natural
+ *
+ * @param RoundingMode $rounding_mode Rounding mode of the conversion. Defaults to RoundingMode::HALF_UP.
+ * @return Natural
+ */
+ public function toNatural(RoundingMode $rounding_mode = null)
+ {
+ $integerValue = $this->toInteger($rounding_mode)->toNative();
+ $naturalValue = \abs($integerValue);
+ $natural = new Natural($naturalValue);
+
+ return $natural;
+ }
+
+ /**
+ * Returns the string representation of the real value
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return \strval($this->toNative());
+ }
+}
diff --git a/src/Number/RoundingMode.php b/src/Number/RoundingMode.php
new file mode 100644
index 0000000..4e20dcf
--- /dev/null
+++ b/src/Number/RoundingMode.php
@@ -0,0 +1,13 @@
+firstName = $first_name;
+ $this->middleName = $middle_name;
+ $this->lastName = $last_name;
+ }
+
+ /**
+ * Returns the first name
+ *
+ * @return StringLiteral
+ */
+ public function getFirstName()
+ {
+ return $this->firstName;
+ }
+
+ /**
+ * Returns the middle name
+ *
+ * @return StringLiteral
+ */
+ public function getMiddleName()
+ {
+ return $this->middleName;
+ }
+
+ /**
+ * Returns the last name
+ *
+ * @return StringLiteral
+ */
+ public function getLastName()
+ {
+ return $this->lastName;
+ }
+
+ /**
+ * Returns the full name
+ *
+ * @return StringLiteral
+ */
+ public function getFullName()
+ {
+ $fullNameString = $this->firstName .
+ ($this->middleName->isEmpty() ? '' : ' ' . $this->middleName) .
+ ($this->lastName->isEmpty() ? '' : ' ' . $this->lastName);
+
+ $fullName = new StringLiteral($fullNameString);
+
+ return $fullName;
+ }
+
+ /**
+ * Tells whether two names are equal by comparing their values
+ *
+ * @param ValueObjectInterface $name
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $name)
+ {
+ if (false === Util::classEquals($this, $name)) {
+ return false;
+ }
+
+ return $this->getFullName() == $name->getFullName();
+ }
+
+ /**
+ * Returns the full name
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return \strval($this->getFullName());
+ }
+}
diff --git a/src/StringLiteral/StringLiteral.php b/src/StringLiteral/StringLiteral.php
new file mode 100644
index 0000000..66b059c
--- /dev/null
+++ b/src/StringLiteral/StringLiteral.php
@@ -0,0 +1,84 @@
+value = $value;
+ }
+
+ /**
+ * Returns the value of the string
+ *
+ * @return string
+ */
+ public function toNative()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Tells whether two string literals are equal by comparing their values
+ *
+ * @param ValueObjectInterface $stringLiteral
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $stringLiteral)
+ {
+ if (false === Util::classEquals($this, $stringLiteral)) {
+ return false;
+ }
+
+ return $this->toNative() === $stringLiteral->toNative();
+ }
+
+ /**
+ * Tells whether the StringLiteral is empty
+ *
+ * @return bool
+ */
+ public function isEmpty()
+ {
+ return \strlen($this->toNative()) == 0;
+ }
+
+ /**
+ * Returns the string value itself
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toNative();
+ }
+}
diff --git a/src/Structure/Collection.php b/src/Structure/Collection.php
new file mode 100644
index 0000000..cc6be1d
--- /dev/null
+++ b/src/Structure/Collection.php
@@ -0,0 +1,127 @@
+items = $items;
+ }
+
+ /**
+ * Tells whether two Collection are equal by comparing their size and items (item order matters)
+ *
+ * @param ValueObjectInterface $collection
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $collection)
+ {
+ if (false === Util::classEquals($this, $collection) || false === $this->count()->sameValueAs($collection->count())) {
+ return false;
+ }
+
+ $arrayCollection = $collection->toArray();
+
+ foreach ($this->items as $index => $item) {
+ if (!isset($arrayCollection[$index]) || false === $item->sameValueAs($arrayCollection[$index])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the number of objects in the collection
+ *
+ * @return Natural
+ */
+ public function count()
+ {
+ return new Natural($this->items->count());
+ }
+
+ /**
+ * Tells whether the Collection contains an object
+ *
+ * @param ValueObjectInterface $object
+ * @return bool
+ */
+ public function contains(ValueObjectInterface $object)
+ {
+ foreach ($this->items as $item) {
+ if ($item->sameValueAs($object)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns a native array representation of the Collection
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->items->toArray();
+ }
+
+ /**
+ * Returns a native string representation of the Collection object
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $string = \sprintf('%s(%d)', \get_class($this), $this->count()->toNative());
+
+ return $string;
+ }
+}
diff --git a/src/Structure/Dictionary.php b/src/Structure/Dictionary.php
new file mode 100644
index 0000000..aaa124c
--- /dev/null
+++ b/src/Structure/Dictionary.php
@@ -0,0 +1,114 @@
+ $arrayValue) {
+ $key = new StringLiteral(\strval($arrayKey));
+
+ if ($arrayValue instanceof \Traversable || \is_array($arrayValue)) {
+ $value = Collection::fromNative($arrayValue);
+ } else {
+ $value = new StringLiteral(\strval($arrayValue));
+ }
+
+ $keyValuePairs[] = new KeyValuePair($key, $value);
+ }
+
+ $fixedArray = \SplFixedArray::fromArray($keyValuePairs);
+
+ return new static($fixedArray);
+ }
+
+ /**
+ * Returns a new Dictionary object
+ *
+ * @param \SplFixedArray $key_value_pairs
+ */
+ public function __construct(\SplFixedArray $key_value_pairs)
+ {
+ foreach ($key_value_pairs as $keyValuePair) {
+ if (false === $keyValuePair instanceof KeyValuePair) {
+ $type = \is_object($keyValuePair) ? \get_class($keyValuePair) : \gettype($keyValuePair);
+ throw new \InvalidArgumentException(\sprintf('Passed SplFixedArray object must contains "KeyValuePair" objects only. "%s" given.', $type));
+ }
+ }
+
+ $this->items = $key_value_pairs;
+ }
+
+ /**
+ * Returns a Collection of the keys
+ *
+ * @return Collection
+ */
+ public function keys()
+ {
+ $count = $this->count()->toNative();
+ $keysArray = new \SplFixedArray($count);
+
+ foreach ($this->items as $key => $item) {
+ $keysArray->offsetSet($key, $item->getKey());
+ }
+
+ return new Collection($keysArray);
+ }
+
+ /**
+ * Returns a Collection of the values
+ *
+ * @return Collection
+ */
+ public function values()
+ {
+ $count = $this->count()->toNative();
+ $valuesArray = new \SplFixedArray($count);
+
+ foreach ($this->items as $key => $item) {
+ $valuesArray->offsetSet($key, $item->getValue());
+ }
+
+ return new Collection($valuesArray);
+ }
+
+ /**
+ * Tells whether $object is one of the keys
+ *
+ * @param ValueObjectInterface $object
+ * @return bool
+ */
+ public function containsKey(ValueObjectInterface $object)
+ {
+ $keys = $this->keys();
+
+ return $keys->contains($object);
+ }
+
+ /**
+ * Tells whether $object is one of the values
+ *
+ * @param ValueObjectInterface $object
+ * @return bool
+ */
+ public function containsValue(ValueObjectInterface $object)
+ {
+ $values = $this->values();
+
+ return $values->contains($object);
+ }
+}
diff --git a/src/Structure/KeyValuePair.php b/src/Structure/KeyValuePair.php
new file mode 100644
index 0000000..049e79b
--- /dev/null
+++ b/src/Structure/KeyValuePair.php
@@ -0,0 +1,99 @@
+key = $key;
+ $this->value = $value;
+ }
+
+ /**
+ * Tells whether two KeyValuePair are equal
+ *
+ * @param ValueObjectInterface $keyValuePair
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $keyValuePair)
+ {
+ if (false === Util::classEquals($this, $keyValuePair)) {
+ return false;
+ }
+
+ return $this->getKey()->sameValueAs($keyValuePair->getKey()) && $this->getValue()->sameValueAs($keyValuePair->getValue());
+ }
+
+ /**
+ * Returns key
+ *
+ * @return ValueObjectInterface
+ */
+ public function getKey()
+ {
+ return clone $this->key;
+ }
+
+ /**
+ * Returns value
+ *
+ * @return ValueObjectInterface
+ */
+ public function getValue()
+ {
+ return clone $this->value;
+ }
+
+ /**
+ * Returns a string representation of the KeyValuePair in format "$key => $value"
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $string = sprintf('%s => %s', $this->getKey(), $this->getValue());
+
+ return $string;
+ }
+}
diff --git a/src/Util/Util.php b/src/Util/Util.php
new file mode 100644
index 0000000..543c3a8
--- /dev/null
+++ b/src/Util/Util.php
@@ -0,0 +1,33 @@
+value = $filteredValue;
+ }
+
+ /**
+ * Returns the local part of the email address
+ *
+ * @return StringLiteral
+ */
+ public function getLocalPart()
+ {
+ $parts = explode('@', $this->toNative());
+ $localPart = new StringLiteral($parts[0]);
+
+ return $localPart;
+ }
+
+ /**
+ * Returns the domain part of the email address
+ *
+ * @return Domain
+ */
+ public function getDomainPart()
+ {
+ $parts = \explode('@', $this->toNative());
+ $domain = \trim($parts[1], '[]');
+
+ return Domain::specifyType($domain);
+ }
+}
diff --git a/src/Web/FragmentIdentifier.php b/src/Web/FragmentIdentifier.php
new file mode 100644
index 0000000..5787903
--- /dev/null
+++ b/src/Web/FragmentIdentifier.php
@@ -0,0 +1,23 @@
+value = $value;
+ }
+}
diff --git a/src/Web/FragmentIdentifierInterface.php b/src/Web/FragmentIdentifierInterface.php
new file mode 100644
index 0000000..a4d23b1
--- /dev/null
+++ b/src/Web/FragmentIdentifierInterface.php
@@ -0,0 +1,7 @@
+ Validator::ALLOW_DNS | Validator::ALLOW_LOCAL));
+
+ if (false === $validator->isValid($value)) {
+ throw new InvalidNativeArgumentException($value, array('string (valid hostname)'));
+ }
+
+ $this->value = $value;
+ }
+}
diff --git a/src/Web/IPAddress.php b/src/Web/IPAddress.php
new file mode 100644
index 0000000..c972217
--- /dev/null
+++ b/src/Web/IPAddress.php
@@ -0,0 +1,40 @@
+value = $filteredValue;
+ }
+
+ /**
+ * Returns the version (IPv4 or IPv6) of the ip address
+ *
+ * @return IPAddressVersion
+ */
+ public function getVersion()
+ {
+ $isIPv4 = filter_var($this->toNative(), FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
+
+ if (false !== $isIPv4) {
+ return IPAddressVersion::IPV4();
+ }
+
+ return IPAddressVersion::IPV6();
+ }
+}
diff --git a/src/Web/IPAddressVersion.php b/src/Web/IPAddressVersion.php
new file mode 100644
index 0000000..2169ef3
--- /dev/null
+++ b/src/Web/IPAddressVersion.php
@@ -0,0 +1,11 @@
+value = $filteredValue;
+ }
+}
diff --git a/src/Web/IPv6Address.php b/src/Web/IPv6Address.php
new file mode 100644
index 0000000..4222725
--- /dev/null
+++ b/src/Web/IPv6Address.php
@@ -0,0 +1,24 @@
+value = $filteredValue;
+ }
+}
diff --git a/src/Web/NullFragmentIdentifier.php b/src/Web/NullFragmentIdentifier.php
new file mode 100644
index 0000000..4255077
--- /dev/null
+++ b/src/Web/NullFragmentIdentifier.php
@@ -0,0 +1,15 @@
+value = '';
+ }
+}
diff --git a/src/Web/NullPortNumber.php b/src/Web/NullPortNumber.php
new file mode 100644
index 0000000..eaaa705
--- /dev/null
+++ b/src/Web/NullPortNumber.php
@@ -0,0 +1,9 @@
+value = '';
+ }
+}
diff --git a/src/Web/Path.php b/src/Web/Path.php
new file mode 100644
index 0000000..76d631b
--- /dev/null
+++ b/src/Web/Path.php
@@ -0,0 +1,20 @@
+value = $filteredValue;
+ }
+}
diff --git a/src/Web/PortNumber.php b/src/Web/PortNumber.php
new file mode 100644
index 0000000..29db4f8
--- /dev/null
+++ b/src/Web/PortNumber.php
@@ -0,0 +1,32 @@
+ array(
+ 'min_range' => 0,
+ 'max_range' => 65535
+ )
+ );
+
+ $value = filter_var($value, FILTER_VALIDATE_INT, $options);
+
+ if (false === $value) {
+ throw new InvalidNativeArgumentException($value, array('int (>=0, <=65535)'));
+ }
+
+ parent::__construct($value);
+ }
+}
diff --git a/src/Web/PortNumberInterface.php b/src/Web/PortNumberInterface.php
new file mode 100644
index 0000000..1d94909
--- /dev/null
+++ b/src/Web/PortNumberInterface.php
@@ -0,0 +1,7 @@
+value = $value;
+ }
+
+ /**
+ * Returns a Dictionary structured representation of the query string
+ *
+ * @return Dictionary
+ */
+ public function toDictionary()
+ {
+ $value = \ltrim($this->toNative(), '?');
+ \parse_str($value, $data);
+
+ return Dictionary::fromNative($data);
+ }
+}
diff --git a/src/Web/QueryStringInterface.php b/src/Web/QueryStringInterface.php
new file mode 100644
index 0000000..9acb4b8
--- /dev/null
+++ b/src/Web/QueryStringInterface.php
@@ -0,0 +1,8 @@
+value = $value;
+ }
+}
diff --git a/src/Web/Url.php b/src/Web/Url.php
new file mode 100644
index 0000000..bede0d9
--- /dev/null
+++ b/src/Web/Url.php
@@ -0,0 +1,216 @@
+scheme = $scheme;
+ $this->user = $user;
+ $this->password = $password;
+ $this->domain = $domain;
+ $this->path = $path;
+ $this->port = $port;
+ $this->queryString = $query;
+ $this->fragmentIdentifier = $fragment;
+ }
+
+ /**
+ * Tells whether two Url are sameValueAs by comparing their components
+ *
+ * @param ValueObjectInterface $url
+ * @return bool
+ */
+ public function sameValueAs(ValueObjectInterface $url)
+ {
+ if (false === Util::classEquals($this, $url)) {
+ return false;
+ }
+
+ return $this->getScheme()->sameValueAs($url->getScheme()) &&
+ $this->getUser()->sameValueAs($url->getUser()) &&
+ $this->getPassword()->sameValueAs($url->getPassword()) &&
+ $this->getDomain()->sameValueAs($url->getDomain()) &&
+ $this->getPath()->sameValueAs($url->getPath()) &&
+ $this->getPort()->sameValueAs($url->getPort()) &&
+ $this->getQueryString()->sameValueAs($url->getQueryString()) &&
+ $this->getFragmentIdentifier()->sameValueAs($url->getFragmentIdentifier())
+ ;
+ }
+
+ /**
+ * Returns the domain of the Url
+ *
+ * @return Hostname|IPAddress
+ */
+ public function getDomain()
+ {
+ return clone $this->domain;
+ }
+
+ /**
+ * Returns the fragment identifier of the Url
+ *
+ * @return FragmentIdentifier
+ */
+ public function getFragmentIdentifier()
+ {
+ return clone $this->fragmentIdentifier;
+ }
+
+ /**
+ * Returns the password part of the Url
+ *
+ * @return StringLiteral
+ */
+ public function getPassword()
+ {
+ return clone $this->password;
+ }
+
+ /**
+ * Returns the path of the Url
+ *
+ * @return Path
+ */
+ public function getPath()
+ {
+ return clone $this->path;
+ }
+
+ /**
+ * Returns the port of the Url
+ *
+ * @return PortNumberInterface
+ */
+ public function getPort()
+ {
+ return clone $this->port;
+ }
+
+ /**
+ * Returns the query string of the Url
+ *
+ * @return QueryString
+ */
+ public function getQueryString()
+ {
+ return clone $this->queryString;
+ }
+
+ /**
+ * Returns the scheme of the Url
+ *
+ * @return SchemeName
+ */
+ public function getScheme()
+ {
+ return clone $this->scheme;
+ }
+
+ /**
+ * Returns the user part of the Url
+ *
+ * @return StringLiteral
+ */
+ public function getUser()
+ {
+ return clone $this->user;
+ }
+
+ /**
+ * Returns a string representation of the url
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $userPass = '';
+ if (false === $this->getUser()->isEmpty()) {
+ $userPass = \sprintf('%s@', $this->getUser());
+
+ if (false === $this->getPassword()->isEmpty()) {
+ $userPass = \sprintf('%s:%s@', $this->getUser(), $this->getPassword());
+ }
+ }
+
+ $port = '';
+ if (false === NullPortNumber::create()->sameValueAs($this->getPort())) {
+ $port = \sprintf(':%d', $this->getPort()->toNative());
+ }
+
+ $urlString = \sprintf('%s://%s%s%s%s%s%s', $this->getScheme(), $userPass, $this->getDomain(), $port, $this->getPath(), $this->getQueryString(), $this->getFragmentIdentifier());
+
+ return $urlString;
+ }
+}
diff --git a/tests/Climate/CelsiusTest.php b/tests/Climate/CelsiusTest.php
new file mode 100644
index 0000000..ab2a976
--- /dev/null
+++ b/tests/Climate/CelsiusTest.php
@@ -0,0 +1,37 @@
+assertEquals(10, $temperature->toCelsius()->toNative());
+ }
+
+ /**
+ * @dataProvider temperatureProvider
+ */
+ public function testToKelvin(Celsius $temperature)
+ {
+ $this->assertEquals(10 + 273.15, $temperature->toKelvin()->toNative());
+ }
+
+ /**
+ * @dataProvider temperatureProvider
+ */
+ public function testToFahrenheit(Celsius $temperature)
+ {
+ $this->assertEquals(10 * 1.8 + 32, $temperature->toFahrenheit()->toNative());
+ }
+}
diff --git a/tests/Climate/FahrenheitTest.php b/tests/Climate/FahrenheitTest.php
new file mode 100644
index 0000000..9b6ecd4
--- /dev/null
+++ b/tests/Climate/FahrenheitTest.php
@@ -0,0 +1,37 @@
+assertEquals((10 - 32) / 1.8, $temperature->toCelsius()->toNative());
+ }
+
+ /**
+ * @dataProvider temperatureProvider
+ */
+ public function testToKelvin(Fahrenheit $temperature)
+ {
+ $this->assertEquals($temperature->toCelsius()->toNative() + 273.15, $temperature->toKelvin()->toNative());
+ }
+
+ /**
+ * @dataProvider temperatureProvider
+ */
+ public function testToFahrenheit(Fahrenheit $temperature)
+ {
+ $this->assertEquals(10, $temperature->toFahrenheit()->toNative());
+ }
+}
diff --git a/tests/Climate/KelvinTest.php b/tests/Climate/KelvinTest.php
new file mode 100644
index 0000000..01f6e0e
--- /dev/null
+++ b/tests/Climate/KelvinTest.php
@@ -0,0 +1,37 @@
+assertEquals(10 - 273.15, $temperature->toCelsius()->toNative());
+ }
+
+ /**
+ * @dataProvider temperatureProvider
+ */
+ public function testToKelvin(Kelvin $temperature)
+ {
+ $this->assertEquals(10, $temperature->toKelvin()->toNative());
+ }
+
+ /**
+ * @dataProvider temperatureProvider
+ */
+ public function testToFahrenheit(Kelvin $temperature)
+ {
+ $this->assertEquals($temperature->toCelsius()->toNative() * 1.8 + 32, $temperature->toFahrenheit()->toNative());
+ }
+}
diff --git a/tests/Climate/RelativeHumidityTest.php b/tests/Climate/RelativeHumidityTest.php
new file mode 100644
index 0000000..b53fa0c
--- /dev/null
+++ b/tests/Climate/RelativeHumidityTest.php
@@ -0,0 +1,25 @@
+assertTrue($fromNativeRelHum->sameValueAs($constructedRelHum));
+ }
+
+ /**
+ * @expectedException \ValueObjects\Exception\InvalidNativeArgumentException
+ */
+ public function testInvalidRelativeHumidity()
+ {
+ new RelativeHumidity(128);
+ }
+}
diff --git a/tests/DateTime/DateTest.php b/tests/DateTime/DateTest.php
new file mode 100644
index 0000000..1c9c9ed
--- /dev/null
+++ b/tests/DateTime/DateTest.php
@@ -0,0 +1,94 @@
+assertTrue($fromNativeDate->sameValueAs($constructedDate));
+ }
+
+ public function testFromNativeDateTime()
+ {
+ $nativeDate = new \DateTime();
+ $nativeDate->setDate(2013, 12, 3);
+ $dateFromNative = Date::fromNativeDateTime($nativeDate);
+ $constructedDate = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+
+ $this->assertTrue($dateFromNative->sameValueAs($constructedDate));
+ }
+
+ public function testNow()
+ {
+ $date = Date::now();
+ $this->assertEquals(date('Y-n-j'), \strval($date));
+ }
+
+ /** @expectedException ValueObjects\DateTime\Exception\InvalidDateException */
+ public function testAlmostValidDateException()
+ {
+ new Date(new Year(2013), Month::FEBRUARY(), new MonthDay(31));
+ }
+
+ public function testSameValueAs()
+ {
+ $date1 = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $date2 = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $date3 = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(5));
+
+ $this->assertTrue($date1->sameValueAs($date2));
+ $this->assertFalse($date1->sameValueAs($date3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($date1->sameValueAs($mock));
+ }
+
+ public function testGetYear()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $year = new Year(2013);
+
+ $this->assertTrue($year->sameValueAs($date->getYear()));
+ }
+
+ public function testGetMonth()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $month = Month::DECEMBER();
+
+ $this->assertTrue($month->sameValueAs($date->getMonth()));
+ }
+
+ public function testGetDay()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $day = new MonthDay(3);
+
+ $this->assertTrue($day->sameValueAs($date->getDay()));
+ }
+
+ public function testToNativeDateTime()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $nativeDate = \DateTime::createFromFormat('Y-n-j H:i:s', '2013-12-3 00:00:00');
+
+ $this->assertEquals($nativeDate, $date->toNativeDateTime());
+ }
+
+ public function testToString()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $this->assertEquals('2013-12-3', $date->__toString());
+ }
+
+}
diff --git a/tests/DateTime/DateTimeTest.php b/tests/DateTime/DateTimeTest.php
new file mode 100644
index 0000000..258cbc6
--- /dev/null
+++ b/tests/DateTime/DateTimeTest.php
@@ -0,0 +1,111 @@
+assertTrue($fromNativeDateTime->sameValueAs($constructedDateTime));
+ }
+
+ public function testFromNativeDateTime()
+ {
+ $nativeDateTime = new \DateTime();
+ $nativeDateTime->setDate(2013, 12, 6)->setTime(20, 50, 10);
+ $dateTimeFromNative = DateTime::fromNativeDateTime($nativeDateTime);
+
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(6));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $constructedDateTime = new DateTime($date, $time);
+
+ $this->assertTrue($dateTimeFromNative->sameValueAs($constructedDateTime));
+ }
+
+ public function testNow()
+ {
+ $dateTime = DateTime::now();
+ $this->assertEquals(date('Y-n-j G:i:s'), \strval($dateTime));
+ }
+
+ public function testNullTime()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(21));
+ $dateTime = new DateTime($date);
+ $this->assertTrue(Time::zero()->sameValueAs($dateTime->getTime()));
+ }
+
+ public function testSameValueAs()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+
+ $date3 = new Date(new Year(2014), Month::MARCH(), new MonthDay(5));
+ $time3 = new Time(new Hour(10), new Minute(52), new Second(40));
+
+ $dateTime1 = new DateTime($date, $time);
+ $dateTime2 = new DateTime($date, $time);
+ $dateTime3 = new DateTime($date3, $time3);
+
+ $this->assertTrue($dateTime1->sameValueAs($dateTime2));
+ $this->assertFalse($dateTime1->sameValueAs($dateTime3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($dateTime1->sameValueAs($mock));
+ }
+
+ public function testGetDate()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $dateTime = new DateTime($date, $time);
+
+ $this->assertTrue($date->sameValueAs($dateTime->getDate()));
+ }
+
+ public function testGetTime()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $dateTime = new DateTime($date, $time);
+
+ $this->assertTrue($time->sameValueAs($dateTime->getTime()));
+ }
+
+ public function testToNativeDateTime()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $dateTime = new DateTime($date, $time);
+ $nativeDateTime = \DateTime::createFromFormat('Y-n-j H:i:s', '2013-12-3 20:50:10');
+
+ $this->assertEquals($nativeDateTime, $dateTime->toNativeDateTime());
+ }
+
+ public function testToString()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $dateTime = new DateTime($date, $time);
+
+ $this->assertEquals('2013-12-3 20:50:10', $dateTime->__toString());
+ }
+
+}
diff --git a/tests/DateTime/DateTimeWithTimeZoneTest.php b/tests/DateTime/DateTimeWithTimeZoneTest.php
new file mode 100644
index 0000000..5e927ef
--- /dev/null
+++ b/tests/DateTime/DateTimeWithTimeZoneTest.php
@@ -0,0 +1,140 @@
+assertTrue($fromNativeDateTimeWithTz->sameValueAs($constructedDateTimeWithTz));
+ }
+
+ public function testFromNativeDateTime()
+ {
+ $nativeDateTime = new \DateTime();
+ $nativeDateTime->setTimeZone(new \DateTimeZone('Europe/Madrid'))->setDate(2013, 12, 6)->setTime(20, 50, 10);
+ $dateTimeWithTzFromNative = DateTimeWithTimeZone::fromNativeDateTime($nativeDateTime);
+
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(6));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $timezone = new TimeZone(new StringLiteral('Europe/Madrid'));
+ $constructedDateTimeWithTz = new DateTimeWithTimeZone(new DateTime($date, $time), $timezone);
+
+ $this->assertTrue($dateTimeWithTzFromNative->sameValueAs($constructedDateTimeWithTz));
+ }
+
+ public function testNow()
+ {
+ $dateTimeWithTz = DateTimeWithTimeZone::now();
+ $this->assertEquals(date('Y-n-j G:i:s e'), \strval($dateTimeWithTz));
+ }
+
+ public function testSameValueAs()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $timeZone = new TimeZone(new StringLiteral('Europe/Madrid'));
+
+ $date3 = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time3 = new Time(new Hour(20), new Minute(50), new Second(10));
+ $timeZone3 = new TimeZone(new StringLiteral('Europe/London'));
+
+ $dateTimeWithTz1 = new DateTimeWithTimeZone(new DateTime($date, $time), $timeZone);
+ $dateTimeWithTz2 = new DateTimeWithTimeZone(new DateTime($date, $time), $timeZone);
+ $dateTimeWithTz3 = new DateTimeWithTimeZone(new DateTime($date3, $time3), $timeZone3);
+
+ $this->assertTrue($dateTimeWithTz1->sameValueAs($dateTimeWithTz2));
+ $this->assertFalse($dateTimeWithTz1->sameValueAs($dateTimeWithTz3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($dateTimeWithTz1->sameValueAs($mock));
+ }
+
+ public function testSameTimestampAs()
+ {
+ $date1 = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time1 = new Time(new Hour(20), new Minute(50), new Second(10));
+ $timeZone1 = new TimeZone(new StringLiteral('Europe/Madrid'));
+
+ $date2 = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time2 = new Time(new Hour(19), new Minute(50), new Second(10));
+ $timeZone2 = new TimeZone(new StringLiteral('Europe/London'));
+
+ $dateTimeWithTz1 = new DateTimeWithTimeZone(new DateTime($date1, $time1), $timeZone1);
+ $dateTimeWithTz2 = new DateTimeWithTimeZone(new DateTime($date2, $time2), $timeZone2);
+
+ $this->assertTrue($dateTimeWithTz1->sameTimestampAs($dateTimeWithTz2));
+ $this->assertFalse($dateTimeWithTz1->sameValueAs($dateTimeWithTz2));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($dateTimeWithTz1->sameTimestampAs($mock));
+ }
+
+ public function testGetDateTime()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $dateTime = new DateTime($date, $time);
+ $timeZone = new TimeZone(new StringLiteral('Europe/Madrid'));
+ $dateTimeWithTz = new DateTimeWithTimeZone($dateTime, $timeZone);
+
+ $this->assertTrue($dateTime->sameValueAs($dateTimeWithTz->getDateTime()));
+ }
+
+ public function testGetTimeZone()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $dateTime = new DateTime($date, $time);
+ $timeZone = new TimeZone(new StringLiteral('Europe/Madrid'));
+ $dateTimeWithTz = new DateTimeWithTimeZone($dateTime, $timeZone);
+
+ $this->assertTrue($timeZone->sameValueAs($dateTimeWithTz->getTimeZone()));
+ }
+
+ public function testToNativeDateTime()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $dateTime = new DateTime($date, $time);
+ $timeZone = new TimeZone(new StringLiteral('Europe/Madrid'));
+ $dateTimeWithTz = new DateTimeWithTimeZone($dateTime, $timeZone);
+ $nativeDateTime = \DateTime::createFromFormat('Y-n-j H:i:s e', '2013-12-3 20:50:10 Europe/Madrid');
+
+ $this->assertEquals($nativeDateTime, $dateTimeWithTz->toNativeDateTime());
+ }
+
+ public function testToString()
+ {
+ $date = new Date(new Year(2013), Month::DECEMBER(), new MonthDay(3));
+ $time = new Time(new Hour(20), new Minute(50), new Second(10));
+ $dateTime = new DateTime($date, $time);
+ $timeZone = new TimeZone(new StringLiteral('Europe/Madrid'));
+ $dateTimeWithTz = new DateTimeWithTimeZone($dateTime, $timeZone);
+
+ $this->assertEquals('2013-12-3 20:50:10 Europe/Madrid', $dateTimeWithTz->__toString());
+ }
+}
diff --git a/tests/DateTime/HourTest.php b/tests/DateTime/HourTest.php
new file mode 100644
index 0000000..0b7c5ee
--- /dev/null
+++ b/tests/DateTime/HourTest.php
@@ -0,0 +1,30 @@
+assertTrue($fromNativeHour->sameValueAs($constructedHour));
+ }
+
+ public function testNow()
+ {
+ $hour = Hour::now();
+ $this->assertEquals(date('G'), $hour->toNative());
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidHour()
+ {
+ new Hour(24);
+ }
+
+}
diff --git a/tests/DateTime/MinuteTest.php b/tests/DateTime/MinuteTest.php
new file mode 100644
index 0000000..df8b0ef
--- /dev/null
+++ b/tests/DateTime/MinuteTest.php
@@ -0,0 +1,30 @@
+assertTrue($fromNativeMinute->sameValueAs($constructedMinute));
+ }
+
+ public function testNow()
+ {
+ $minute = Minute::now();
+ $this->assertEquals(\intval(date('i')), $minute->toNative());
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidMinute()
+ {
+ new Minute(60);
+ }
+
+}
diff --git a/tests/DateTime/MonthDayTest.php b/tests/DateTime/MonthDayTest.php
new file mode 100644
index 0000000..0b551b8
--- /dev/null
+++ b/tests/DateTime/MonthDayTest.php
@@ -0,0 +1,30 @@
+assertTrue($fromNativeMonthDay->sameValueAs($constructedMonthDay));
+ }
+
+ public function testNow()
+ {
+ $monthDay = MonthDay::now();
+ $this->assertEquals(date('j'), $monthDay->toNative());
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidMonthDay()
+ {
+ new MonthDay(32);
+ }
+
+}
diff --git a/tests/DateTime/MonthTest.php b/tests/DateTime/MonthTest.php
new file mode 100644
index 0000000..36bed1a
--- /dev/null
+++ b/tests/DateTime/MonthTest.php
@@ -0,0 +1,33 @@
+assertEquals(date('F'), $month->toNative());
+ }
+
+ public function testFromNativeDateTime()
+ {
+ $nativeDateTime = new \DateTime();
+ $nativeDateTime->setDate(2013, 12, 1);
+
+ $month = Month::fromNativeDateTime($nativeDateTime);
+
+ $this->assertEquals('December', $month->toNative());
+ }
+
+ public function testGetNumericValue()
+ {
+ $month = Month::APRIL();
+
+ $this->assertEquals(4, $month->getNumericValue());
+ }
+
+}
diff --git a/tests/DateTime/SecondTest.php b/tests/DateTime/SecondTest.php
new file mode 100644
index 0000000..24eff83
--- /dev/null
+++ b/tests/DateTime/SecondTest.php
@@ -0,0 +1,30 @@
+assertTrue($fromNativeSecond->sameValueAs($constructedSecond));
+ }
+
+ public function testNow()
+ {
+ $second = Second::now();
+ $this->assertEquals(\intval(date('s')), $second->toNative());
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidSecond()
+ {
+ new Second(60);
+ }
+
+}
diff --git a/tests/DateTime/TimeTest.php b/tests/DateTime/TimeTest.php
new file mode 100644
index 0000000..61aac5f
--- /dev/null
+++ b/tests/DateTime/TimeTest.php
@@ -0,0 +1,94 @@
+assertTrue($fromNativeTime->sameValueAs($constructedTime));
+ }
+
+ public function testFromNativeDateTime()
+ {
+ $nativeTime = new \DateTime();
+ $nativeTime->setTime(20, 10, 34);
+ $timeFromNative = Time::fromNativeDateTime($nativeTime);
+ $constructedTime = new Time(new Hour(20), new Minute(10), new Second(34));
+
+ $this->assertTrue($timeFromNative->sameValueAs($constructedTime));
+ }
+
+ public function testNow()
+ {
+ $time = Time::now();
+ $this->assertEquals(date('G:i:s'), \strval($time));
+ }
+
+ public function testZero()
+ {
+ $time = Time::zero();
+ $this->assertEquals('0:00:00', \strval($time));
+ }
+
+ public function testSameValueAs()
+ {
+ $time1 = new Time(new Hour(20), new Minute(10), new Second(34));
+ $time2 = new Time(new Hour(20), new Minute(10), new Second(34));
+ $time3 = new Time(new Hour(20), new Minute(1), new Second(10));
+
+ $this->assertTrue($time1->sameValueAs($time2));
+ $this->assertFalse($time1->sameValueAs($time3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($time1->sameValueAs($mock));
+ }
+
+ public function testGetHour()
+ {
+ $time = new Time(new Hour(20), new Minute(10), new Second(34));
+ $hour = new Hour(20);
+
+ $this->assertTrue($hour->sameValueAs($time->getHour()));
+ }
+
+ public function testGetMinute()
+ {
+ $time = new Time(new Hour(20), new Minute(10), new Second(34));
+ $minute = new Minute(10);
+
+ $this->assertTrue($minute->sameValueAs($time->getMinute()));
+ }
+
+ public function testGetSecond()
+ {
+ $time = new Time(new Hour(20), new Minute(10), new Second(34));
+ $day = new Second(34);
+
+ $this->assertTrue($day->sameValueAs($time->getSecond()));
+ }
+
+ public function testToNativeDateTime()
+ {
+ $time = new Time(new Hour(20), new Minute(10), new Second(34));
+ $nativeTime = \DateTime::createFromFormat('H:i:s', '20:10:34');
+
+ $this->assertEquals($nativeTime, $time->toNativeDateTime());
+ }
+
+ public function testToString()
+ {
+ $time = new Time(new Hour(20), new Minute(10), new Second(34));
+ $this->assertEquals('20:10:34', $time->__toString());
+ }
+
+}
diff --git a/tests/DateTime/TimeZoneTest.php b/tests/DateTime/TimeZoneTest.php
new file mode 100644
index 0000000..01b67a6
--- /dev/null
+++ b/tests/DateTime/TimeZoneTest.php
@@ -0,0 +1,78 @@
+assertTrue($fromNativeTimeZone->sameValueAs($constructedTimeZone));
+ }
+
+ public function testFromNativeDateTimeZone()
+ {
+ $nativeTimeZone = new \DateTimeZone('Europe/Madrid');
+ $timeZoneFromNative = TimeZone::fromNativeDateTimeZone($nativeTimeZone);
+
+ $constructedTimeZone = new TimeZone(new StringLiteral('Europe/Madrid'));
+
+ $this->assertTrue($timeZoneFromNative->sameValueAs($constructedTimeZone));
+ }
+
+ public function testDefaultTz()
+ {
+ $timeZone = TimeZone::fromDefault();
+ $this->assertEquals(date_default_timezone_get(), \strval($timeZone));
+ }
+
+ public function testSameValueAs()
+ {
+ $timeZone1 = new TimeZone(new StringLiteral('Europe/Madrid'));
+ $timeZone2 = new TimeZone(new StringLiteral('Europe/Madrid'));
+ $timeZone3 = new TimeZone(new StringLiteral('Europe/Berlin'));
+
+ $this->assertTrue($timeZone1->sameValueAs($timeZone2));
+ $this->assertFalse($timeZone1->sameValueAs($timeZone3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($timeZone1->sameValueAs($mock));
+ }
+
+ public function testGetName()
+ {
+ $name = new StringLiteral('Europe/Madrid');
+ $timeZone = new TimeZone($name);
+
+ $this->assertTrue($name->sameValueAs($timeZone->getName()));
+ }
+
+ public function testToNativeDateTimeZone()
+ {
+ $nativeTimeZone = new \DateTimeZone('Europe/Madrid');
+ $timeZone = new TimeZone(new StringLiteral('Europe/Madrid'));
+
+ $this->assertEquals($nativeTimeZone, $timeZone->toNativeDateTimeZone());
+ }
+
+ public function testToString()
+ {
+ $timeZone = new TimeZone(new StringLiteral('Europe/Madrid'));
+
+ $this->assertEquals('Europe/Madrid', $timeZone->__toString());
+ }
+
+ /**
+ * @expectedException \ValueObjects\DateTime\Exception\InvalidTimeZoneException
+ */
+ public function testExceptionOnInvalidTimeZoneName()
+ {
+ $timeZone = new TimeZone(new StringLiteral('Mars/Phobos'));
+ }
+}
diff --git a/tests/DateTime/WeekDayTest.php b/tests/DateTime/WeekDayTest.php
new file mode 100644
index 0000000..a26b926
--- /dev/null
+++ b/tests/DateTime/WeekDayTest.php
@@ -0,0 +1,33 @@
+assertEquals(date('l'), $weekDay->toNative());
+ }
+
+ public function testFromNativeDateTime()
+ {
+ $nativeDateTime = new \DateTime();
+ $nativeDateTime->setDate(2013, 12, 14);
+
+ $weekDay = WeekDay::fromNativeDateTime($nativeDateTime);
+
+ $this->assertEquals('Saturday', $weekDay->toNative());
+ }
+
+ public function testGetNumericValue()
+ {
+ $weekDay = WeekDay::SATURDAY();
+
+ $this->assertEquals(6, $weekDay->getNumericValue());
+ }
+
+}
diff --git a/tests/DateTime/YearTest.php b/tests/DateTime/YearTest.php
new file mode 100644
index 0000000..2f7af77
--- /dev/null
+++ b/tests/DateTime/YearTest.php
@@ -0,0 +1,16 @@
+assertEquals(date('Y'), $year->toNative());
+ }
+
+}
diff --git a/tests/Enum/EnumTest.php b/tests/Enum/EnumTest.php
new file mode 100644
index 0000000..9e5f1e4
--- /dev/null
+++ b/tests/Enum/EnumTest.php
@@ -0,0 +1,27 @@
+getMock('ValueObjects\Enum\Enum', array(), array(), '', false);
+ $stub2 = $this->getMock('ValueObjects\Enum\Enum', array(), array(), '', false);
+
+ $stub1->expects($this->any())
+ ->method('sameValueAs')
+ ->will($this->returnValue(true));
+
+ $this->assertTrue($stub1->sameValueAs($stub2));
+ }
+
+ public function testToString()
+ {
+ $stub = $this->getMock('ValueObjects\Enum\Enum', array(), array(), '', false);
+
+ $this->assertEquals('', $stub->__toString());
+ }
+}
diff --git a/tests/Geography/AddressTest.php b/tests/Geography/AddressTest.php
new file mode 100644
index 0000000..6380482
--- /dev/null
+++ b/tests/Geography/AddressTest.php
@@ -0,0 +1,125 @@
+address = new Address(
+ new StringLiteral('Nicolò Pignatelli'),
+ new Street(new StringLiteral('via Manara'), new StringLiteral('3')),
+ new StringLiteral(''),
+ new StringLiteral('Altamura'),
+ new StringLiteral('BARI'),
+ new StringLiteral('70022'),
+ new Country(CountryCode::IT())
+ );
+ }
+
+ public function testFromNative()
+ {
+ $fromNativeAddress = Address::fromNative('Nicolò Pignatelli', 'via Manara', '3', '', 'Altamura', 'BARI', '70022', 'IT');
+ $this->assertTrue($this->address->sameValueAs($fromNativeAddress));
+ }
+
+ /** @expectedException \BadMethodCallException */
+ public function testInvalidFromNative()
+ {
+ Address::fromNative('invalid');
+ }
+
+ public function testSameValueAs()
+ {
+ $address2 = new Address(
+ new StringLiteral('Nicolò Pignatelli'),
+ new Street(new StringLiteral('via Manara'), new StringLiteral('3')),
+ new StringLiteral(''),
+ new StringLiteral('Altamura'),
+ new StringLiteral('BARI'),
+ new StringLiteral('70022'),
+ new Country(CountryCode::IT())
+ );
+
+ $address3 = new Address(
+ new StringLiteral('Nicolò Pignatelli'),
+ new Street(new StringLiteral('SP159'), new StringLiteral('km 4')),
+ new StringLiteral(''),
+ new StringLiteral('Altamura'),
+ new StringLiteral('BARI'),
+ new StringLiteral('70022'),
+ new Country(CountryCode::IT())
+ );
+
+ $this->assertTrue($this->address->sameValueAs($address2));
+ $this->assertTrue($address2->sameValueAs($this->address));
+ $this->assertFalse($this->address->sameValueAs($address3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($this->address->sameValueAs($mock));
+ }
+
+ public function testGetName()
+ {
+ $name = new StringLiteral('Nicolò Pignatelli');
+ $this->assertTrue($this->address->getName()->sameValueAs($name));
+ }
+
+ public function testGetStreet()
+ {
+ $street = new Street(new StringLiteral('via Manara'), new StringLiteral('3'));
+ $this->assertTrue($this->address->getStreet()->sameValueAs($street));
+ }
+
+ public function testGetDistrict()
+ {
+ $district = new StringLiteral('');
+ $this->assertTrue($this->address->getDistrict()->sameValueAs($district));
+ }
+
+ public function testGetCity()
+ {
+ $city = new StringLiteral('Altamura');
+ $this->assertTrue($this->address->getCity()->sameValueAs($city));
+ }
+
+ public function testGetRegion()
+ {
+ $region = new StringLiteral('BARI');
+ $this->assertTrue($this->address->getRegion()->sameValueAs($region));
+ }
+
+ public function testGetPostalCode()
+ {
+ $code = new StringLiteral('70022');
+ $this->assertTrue($this->address->getPostalCode()->sameValueAs($code));
+ }
+
+ public function testGetCountry()
+ {
+ $country = new Country(CountryCode::IT());
+ $this->assertTrue($this->address->getCountry()->sameValueAs($country));
+ }
+
+ public function testToString()
+ {
+ $addressString = <<assertSame($addressString, $this->address->__toString());
+ }
+}
diff --git a/tests/Geography/CoordinateTest.php b/tests/Geography/CoordinateTest.php
new file mode 100644
index 0000000..c6c5fd8
--- /dev/null
+++ b/tests/Geography/CoordinateTest.php
@@ -0,0 +1,113 @@
+coordinate = new Coordinate(
+ new Latitude(40.829137),
+ new Longitude(16.555838)
+ );
+ }
+
+ public function testNullConstructorEllipsoid()
+ {
+ $this->assertTrue($this->coordinate->getEllipsoid()->sameValueAs(Ellipsoid::WGS84()));
+ }
+
+ public function testFromNative()
+ {
+ $fromNativeCoordinate = Coordinate::fromNative(40.829137, 16.555838, 'WGS84');
+ $this->assertTrue($this->coordinate->sameValueAs($fromNativeCoordinate));
+ }
+
+ /** @expectedException \BadMethodCallException */
+ public function testInvalidFromNative()
+ {
+ Coordinate::fromNative(40.829137);
+ }
+
+ public function testSameValueAs()
+ {
+ $coordinate2 = new Coordinate(
+ new Latitude(40.829137),
+ new Longitude(16.555838)
+ );
+ $coordinate3 = new Coordinate(
+ new Latitude(40.829137),
+ new Longitude(16.555838),
+ Ellipsoid::WGS60()
+ );
+
+ $this->assertTrue($this->coordinate->sameValueAs($coordinate2));
+ $this->assertTrue($coordinate2->sameValueAs($this->coordinate));
+ $this->assertFalse($this->coordinate->sameValueAs($coordinate3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($this->coordinate->sameValueAs($mock));
+ }
+
+ public function getLatitude()
+ {
+ $latitude = new Latitude(40.829137);
+ $this->assertTrue($this->coordinate->getLatitude()->sameValueAs($latitude));
+ }
+
+ public function getLongitude()
+ {
+ $longitude = new Longitude(16.555838);
+ $this->assertTrue($this->coordinate->getLongitude()->sameValueAs($longitude));
+ }
+
+ public function getEllipsoid()
+ {
+ $ellipsoid = Ellipsoid::WGS84();
+ $this->assertTrue($this->coordinate->getEllipsoid()->sameValueAs($ellipsoid));
+ }
+
+ public function testToDegreesMinutesSeconds()
+ {
+ $dms = new StringLiteral('40°49′45″N, 16°33′21″E');
+ $this->assertTrue($this->coordinate->toDegreesMinutesSeconds()->sameValueAs($dms));
+ }
+
+ public function testToDecimalMinutes()
+ {
+ $dm = new StringLiteral('40 49.74822N, 16 33.35028E');
+ $this->assertTrue($this->coordinate->toDecimalMinutes()->sameValueAs($dm));
+ }
+
+ public function testToUniversalTransverseMercator()
+ {
+ $utm = new StringLiteral('33T 631188 4520953');
+ $this->assertTrue($this->coordinate->toUniversalTransverseMercator()->sameValueAs($utm));
+ }
+
+ public function testDistanceFrom()
+ {
+ $newYork = new Coordinate(
+ new Latitude(41.145556),
+ new Longitude(-73.995)
+ );
+
+ $distance = $this->coordinate->distanceFrom($newYork);
+ $this->assertSame(7609068.4225575, $distance->toNative());
+ }
+
+ public function testToString()
+ {
+ $this->assertSame('40.829137,16.555838', $this->coordinate->__toString());
+ }
+}
diff --git a/tests/Geography/CountryCodeNameTest.php b/tests/Geography/CountryCodeNameTest.php
new file mode 100644
index 0000000..40e4673
--- /dev/null
+++ b/tests/Geography/CountryCodeNameTest.php
@@ -0,0 +1,20 @@
+assertTrue($name->sameValueAs($expectedString));
+ }
+}
diff --git a/tests/Geography/CountryTest.php b/tests/Geography/CountryTest.php
new file mode 100644
index 0000000..53a15b7
--- /dev/null
+++ b/tests/Geography/CountryTest.php
@@ -0,0 +1,51 @@
+assertTrue($constructedCountry->sameValueAs($fromNativeCountry));
+ }
+
+ public function testSameValueAs()
+ {
+ $country1 = new Country(CountryCode::IT());
+ $country2 = new Country(CountryCode::IT());
+ $country3 = new Country(CountryCode::US());
+
+ $this->assertTrue($country1->sameValueAs($country2));
+ $this->assertFalse($country1->sameValueAs($country3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($country1->sameValueAs($mock));
+ }
+
+ public function testGetCode()
+ {
+ $italy = new Country(CountryCode::IT());
+ $this->assertTrue($italy->getCode()->sameValueAs(CountryCode::IT()));
+ }
+
+ public function testGetName()
+ {
+ $italy = new Country(CountryCode::IT());
+ $name = new StringLiteral('Italy');
+ $this->assertTrue($italy->getName()->sameValueAs($name));
+ }
+
+ public function testToString()
+ {
+ $italy = new Country(CountryCode::IT());
+ $this->assertSame('Italy', $italy->__toString());
+ }
+}
diff --git a/tests/Geography/LatitudeTest.php b/tests/Geography/LatitudeTest.php
new file mode 100644
index 0000000..b250652
--- /dev/null
+++ b/tests/Geography/LatitudeTest.php
@@ -0,0 +1,26 @@
+assertEquals(90, $latitude->toNative());
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidLatitude()
+ {
+ new Latitude('invalid');
+ }
+}
diff --git a/tests/Geography/LongitudeTest.php b/tests/Geography/LongitudeTest.php
new file mode 100644
index 0000000..dd9ba41
--- /dev/null
+++ b/tests/Geography/LongitudeTest.php
@@ -0,0 +1,26 @@
+assertEquals(-179, $longitude->toNative());
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidLongitude()
+ {
+ new Longitude('invalid');
+ }
+}
diff --git a/tests/Geography/StreetTest.php b/tests/Geography/StreetTest.php
new file mode 100644
index 0000000..93786da
--- /dev/null
+++ b/tests/Geography/StreetTest.php
@@ -0,0 +1,65 @@
+street = new Street(new StringLiteral('Abbey Rd'), new StringLiteral('3'), new StringLiteral('Building A'), new StringLiteral('%number% %name%, %elements%'));
+ }
+
+ public function testFromNative()
+ {
+ $fromNativeStreet = Street::fromNative('Abbey Rd', '3', 'Building A');
+ $this->assertTrue($this->street->sameValueAs($fromNativeStreet));
+ }
+
+ /** @expectedException \BadMethodCallException */
+ public function testInvalidFromNative()
+ {
+ Street::fromNative('Abbey Rd');
+ }
+
+ public function testSameValueAs()
+ {
+ $street2 = new Street(new StringLiteral('Abbey Rd'), new StringLiteral('3'), new StringLiteral('Building A'));
+ $street3 = new Street(new StringLiteral('Orchard Road'), new StringLiteral(''));
+
+ $this->assertTrue($this->street->sameValueAs($street2));
+ $this->assertTrue($street2->sameValueAs($this->street));
+ $this->assertFalse($this->street->sameValueAs($street3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($this->street->sameValueAs($mock));
+ }
+
+ public function testGetName()
+ {
+ $name = new StringLiteral('Abbey Rd');
+ $this->assertTrue($this->street->getName()->sameValueAs($name));
+ }
+
+ public function testGetNumber()
+ {
+ $number = new StringLiteral('3');
+ $this->assertTrue($this->street->getNumber()->sameValueAs($number));
+ }
+
+ public function testGetElements()
+ {
+ $elements = new StringLiteral('Building A');
+ $this->assertTrue($this->street->getElements()->sameValueAs($elements));
+ }
+
+ public function testToString()
+ {
+ $this->assertSame('3 Abbey Rd, Building A', $this->street->__toString());
+ }
+}
diff --git a/tests/Identity/UUIDTest.php b/tests/Identity/UUIDTest.php
new file mode 100644
index 0000000..e23d605
--- /dev/null
+++ b/tests/Identity/UUIDTest.php
@@ -0,0 +1,43 @@
+assertRegexp('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/', $uuidString);
+ }
+
+ public function testFromNative()
+ {
+ $uuid1 = new UUID();
+ $uuid2 = UUID::fromNative($uuid1->toNative());
+
+ $this->assertTrue($uuid1->sameValueAs($uuid2));
+ }
+
+ public function testSameValueAs()
+ {
+ $uuid1 = new UUID();
+ $uuid2 = clone $uuid1;
+ $uuid3 = new UUID();
+
+ $this->assertTrue($uuid1->sameValueAs($uuid2));
+ $this->assertFalse($uuid1->sameValueAs($uuid3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($uuid1->sameValueAs($mock));
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalid()
+ {
+ new UUID('invalid');
+ }
+}
diff --git a/tests/Money/CurrencyTest.php b/tests/Money/CurrencyTest.php
new file mode 100644
index 0000000..17b3df6
--- /dev/null
+++ b/tests/Money/CurrencyTest.php
@@ -0,0 +1,47 @@
+assertTrue($fromNativeCurrency->sameValueAs($constructedCurrency));
+ }
+
+ public function testSameValueAs()
+ {
+ $eur1 = new Currency(CurrencyCode::EUR());
+ $eur2 = new Currency(CurrencyCode::EUR());
+ $usd = new Currency(CurrencyCode::USD());
+
+ $this->assertTrue($eur1->sameValueAs($eur2));
+ $this->assertTrue($eur2->sameValueAs($eur1));
+ $this->assertFalse($eur1->sameValueAs($usd));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($eur1->sameValueAs($mock));
+ }
+
+ public function testGetCode()
+ {
+ $cad = new Currency(CurrencyCode::CAD());
+
+ $this->assertInstanceOf('\ValueObjects\Money\CurrencyCode', $cad->getCode());
+ $this->assertSame('CAD', $cad->getCode()->toNative());
+ }
+
+ public function testToString()
+ {
+ $eur = new Currency(CurrencyCode::EUR());
+
+ $this->assertSame('EUR', $eur->__toString());
+ }
+}
diff --git a/tests/Money/MoneyTest.php b/tests/Money/MoneyTest.php
new file mode 100644
index 0000000..ca118e3
--- /dev/null
+++ b/tests/Money/MoneyTest.php
@@ -0,0 +1,110 @@
+assertTrue($fromNativeMoney->sameValueAs($constructedMoney));
+ }
+
+ public function testSameValueAs()
+ {
+ $eur = new Currency(CurrencyCode::EUR());
+ $usd = new Currency(CurrencyCode::USD());
+
+ $money1 = new Money(new Integer(1200), $eur);
+ $money2 = new Money(new Integer(1200), $eur);
+ $money3 = new Money(new Integer(34607), $usd);
+
+ $this->assertTrue($money1->sameValueAs($money2));
+ $this->assertTrue($money2->sameValueAs($money1));
+ $this->assertFalse($money1->sameValueAs($money3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($money1->sameValueAs($mock));
+ }
+
+ public function testGetAmount()
+ {
+ $eur = new Currency(CurrencyCode::EUR());
+ $money = new Money(new Integer(1200), $eur);
+ $amount = $money->getAmount();
+
+ $this->assertInstanceOf('\ValueObjects\Number\Integer', $amount);
+ $this->assertSame(1200, $amount->toNative());
+ }
+
+ public function testGetCurrency()
+ {
+ $eur = new Currency(CurrencyCode::EUR());
+ $money = new Money(new Integer(1200), $eur);
+ $currency = $money->getCurrency();
+
+ $this->assertInstanceOf('\ValueObjects\Money\Currency', $currency);
+ $this->assertSame('EUR', $currency->getCode()->toNative());
+ }
+
+ public function testAdd()
+ {
+ $eur = new Currency(CurrencyCode::EUR());
+ $money = new Money(new Integer(1200), $eur);
+ $addendum = new Integer(156);
+
+ $addedMoney = $money->add($addendum);
+
+ $this->assertEquals(1356, $addedMoney->getAmount()->toNative());
+ }
+
+ public function testAddNegative()
+ {
+ $eur = new Currency(CurrencyCode::EUR());
+ $money = new Money(new Integer(1200), $eur);
+ $addendum = new Integer(-120);
+
+ $addedMoney = $money->add($addendum);
+
+ $this->assertEquals(1080, $addedMoney->getAmount()->toNative());
+ }
+
+ public function testMultiply()
+ {
+ $eur = new Currency(CurrencyCode::EUR());
+ $money = new Money(new Integer(1200), $eur);
+ $multiplier = new Real(1.2);
+
+ $addedMoney = $money->multiply($multiplier);
+
+ $this->assertEquals(1440, $addedMoney->getAmount()->toNative());
+ }
+
+ public function testMultiplyInverse()
+ {
+ $eur = new Currency(CurrencyCode::EUR());
+ $money = new Money(new Integer(1200), $eur);
+ $multiplier = new Real(0.3);
+
+ $addedMoney = $money->multiply($multiplier);
+
+ $this->assertEquals(360, $addedMoney->getAmount()->toNative());
+ }
+
+ public function testToString()
+ {
+ $eur = new Currency(CurrencyCode::EUR());
+ $money = new Money(new Integer(1200), $eur);
+
+ $this->assertSame('EUR 1200', $money->__toString());
+ }
+}
diff --git a/tests/NullValue/NullValueTest.php b/tests/NullValue/NullValueTest.php
new file mode 100644
index 0000000..f173b7a
--- /dev/null
+++ b/tests/NullValue/NullValueTest.php
@@ -0,0 +1,36 @@
+assertTrue($null1->sameValueAs($null2));
+ }
+
+ public function testCreate()
+ {
+ $null = NullValue::create();
+
+ $this->assertInstanceOf('ValueObjects\NullValue\NullValue', $null);
+ }
+
+ public function testToString()
+ {
+ $foo = new NullValue();
+ $this->assertSame('', $foo->__toString());
+ }
+}
diff --git a/tests/Number/ComplexTest.php b/tests/Number/ComplexTest.php
new file mode 100644
index 0000000..1979b9a
--- /dev/null
+++ b/tests/Number/ComplexTest.php
@@ -0,0 +1,88 @@
+complex = new Complex(new Real(2.05), new Real(3.2));
+ }
+
+ public function testFromNative()
+ {
+ $fromNativeComplex = Complex::fromNative(2.05, 3.2);
+
+ $this->assertTrue($fromNativeComplex->sameValueAs($this->complex));
+ }
+
+ public function testFromNativeWithWrongNumberOfArgsThrowsError()
+ {
+ $this->setExpectedException('BadMethodCallException');
+ $fromNativeComplex = Complex::fromNative(2.05);
+ }
+
+ public function testFromPolar()
+ {
+ $mod = new Real(3.800328933132);
+ $arg = new Real(1.0010398733119);
+ $fromPolar = Complex::fromPolar($mod, $arg);
+
+ $nativeModulus = $this->complex->getModulus();
+ $nativeArgument = $this->complex->getArgument();
+
+ $this->assertTrue($nativeModulus->sameValueAs($fromPolar->getModulus()));
+ $this->assertTrue($nativeArgument->sameValueAs($fromPolar->getArgument()));
+ }
+
+ public function testToNative()
+ {
+ $this->assertEquals(array(2.05, 3.2), $this->complex->toNative());
+ }
+
+ public function testGetReal()
+ {
+ $real = new Real(2.05);
+
+ $this->assertTrue($real->sameValueAs($this->complex->getReal()));
+ }
+
+ public function testGetIm()
+ {
+ $im = new Real(3.2);
+
+ $this->assertTrue($im->sameValueAs($this->complex->getIm()));
+ }
+
+ public function testGetModulus()
+ {
+ $mod = new Real(3.800328933132);
+
+ $this->assertTrue($mod->sameValueAs($this->complex->getModulus()));
+ }
+
+ public function testGetArgument()
+ {
+ $arg = new Real(1.0010398733119);
+
+ $this->assertTrue($arg->sameValueAs($this->complex->getArgument()));
+ }
+
+ public function testToString()
+ {
+ $complex = new Complex(new Real(2.034), new Real(-1.4));
+ $this->assertEquals('2.034 - 1.4i', $complex->__toString());
+ }
+
+ public function testNotSameValue()
+ {
+ $this->assertFalse($this->complex->sameValueAs(new Real(2.035)));
+ }
+}
diff --git a/tests/Number/IntegerTest.php b/tests/Number/IntegerTest.php
new file mode 100644
index 0000000..9cbfc63
--- /dev/null
+++ b/tests/Number/IntegerTest.php
@@ -0,0 +1,57 @@
+assertSame(5, $integer->toNative());
+ }
+
+ public function testSameValueAs()
+ {
+ $integer1 = new Integer(3);
+ $integer2 = new Integer(3);
+ $integer3 = new Integer(45);
+
+ $this->assertTrue($integer1->sameValueAs($integer2));
+ $this->assertTrue($integer2->sameValueAs($integer1));
+ $this->assertFalse($integer1->sameValueAs($integer3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($integer1->sameValueAs($mock));
+ }
+
+ public function testToString()
+ {
+ $integer = new Integer(87);
+ $this->assertSame('87', $integer->__toString());
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidNativeArgument()
+ {
+ new Integer(23.4);
+ }
+
+ public function testZeroToString()
+ {
+ $zero = new Integer(0);
+ $this->assertSame('0', $zero->__toString());
+ }
+
+ public function testToReal()
+ {
+ $integer = new Integer(5);
+ $nativeReal = new Real(5);
+ $real = $integer->toReal();
+
+ $this->assertTrue($real->sameValueAs($nativeReal));
+ }
+}
diff --git a/tests/Number/NaturalTest.php b/tests/Number/NaturalTest.php
new file mode 100644
index 0000000..b3398f4
--- /dev/null
+++ b/tests/Number/NaturalTest.php
@@ -0,0 +1,15 @@
+assertTrue($fromNativeReal->sameValueAs($constructedReal));
+ }
+
+ public function testToNative()
+ {
+ $real = new Real(3.4);
+ $this->assertEquals(3.4, $real->toNative());
+ }
+
+ public function testSameValueAs()
+ {
+ $real1 = new Real(5.64);
+ $real2 = new Real(5.64);
+ $real3 = new Real(6.01);
+
+ $this->assertTrue($real1->sameValueAs($real2));
+ $this->assertTrue($real2->sameValueAs($real1));
+ $this->assertFalse($real1->sameValueAs($real3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($real1->sameValueAs($mock));
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidNativeArgument()
+ {
+ new Real('invalid');
+ }
+
+ public function testToInteger()
+ {
+ $real = new Real(3.14);
+ $nativeInteger = new Integer(3);
+ $integer = $real->toInteger();
+
+ $this->assertTrue($integer->sameValueAs($nativeInteger));
+ }
+
+ public function testToNatural()
+ {
+ $real = new Real(3.14);
+ $nativeNatural = new Natural(3);
+ $natural = $real->toNatural();
+
+ $this->assertTrue($natural->sameValueAs($nativeNatural));
+ }
+
+ public function testToString()
+ {
+ $real = new Real(.7);
+ $this->assertEquals('.7', $real->__toString());
+ }
+}
diff --git a/tests/Person/AgeTest.php b/tests/Person/AgeTest.php
new file mode 100644
index 0000000..be37837
--- /dev/null
+++ b/tests/Person/AgeTest.php
@@ -0,0 +1,35 @@
+assertEquals(25, $age->toNative());
+ }
+
+ public function testSameValueAs()
+ {
+ $age1 = new Age(33);
+ $age2 = new Age(33);
+ $age3 = new Age(66);
+
+ $this->assertTrue($age1->sameValueAs($age2));
+ $this->assertTrue($age2->sameValueAs($age1));
+ $this->assertFalse($age1->sameValueAs($age3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($age1->sameValueAs($mock));
+ }
+
+ public function testToString()
+ {
+ $age = new Age(54);
+ $this->assertEquals('54', $age->__toString());
+ }
+}
diff --git a/tests/Person/GenderTest.php b/tests/Person/GenderTest.php
new file mode 100644
index 0000000..240e16d
--- /dev/null
+++ b/tests/Person/GenderTest.php
@@ -0,0 +1,35 @@
+assertEquals(Gender::FEMALE, $gender->toNative());
+ }
+
+ public function testSameValueAs()
+ {
+ $male1 = Gender::MALE();
+ $male2 = Gender::MALE();
+ $other = Gender::OTHER();
+
+ $this->assertTrue($male1->sameValueAs($male2));
+ $this->assertTrue($male2->sameValueAs($male1));
+ $this->assertFalse($male1->sameValueAs($other));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($male1->sameValueAs($mock));
+ }
+
+ public function testToString()
+ {
+ $sex = Gender::FEMALE();
+ $this->assertEquals('female', $sex->__toString());
+ }
+}
diff --git a/tests/Person/NameTest.php b/tests/Person/NameTest.php
new file mode 100644
index 0000000..ee90be8
--- /dev/null
+++ b/tests/Person/NameTest.php
@@ -0,0 +1,69 @@
+name = new Name(new StringLiteral('foo'), new StringLiteral('bar'), new StringLiteral('baz'));
+ }
+
+ public function testFromNative()
+ {
+ $fromNativeName = Name::fromNative('foo', 'bar', 'baz');
+
+ $this->assertTrue($fromNativeName->sameValueAs($this->name));
+ }
+
+ public function testGetFirstName()
+ {
+ $this->assertEquals('foo', $this->name->getFirstName());
+ }
+
+ public function testGetMiddleName()
+ {
+ $this->assertEquals('bar', $this->name->getMiddleName());
+ }
+
+ public function testGetLastName()
+ {
+ $this->assertEquals('baz', $this->name->getLastName());
+ }
+
+ public function testGetFullName()
+ {
+ $this->assertEquals('foo bar baz', $this->name->getFullName());
+ }
+
+ public function testEmptyFullName()
+ {
+ $name = new Name(new StringLiteral(''), new StringLiteral(''), new StringLiteral(''));
+
+ $this->assertEquals('', $name->getFullName());
+ }
+
+ public function testSameValueAs()
+ {
+ $name2 = new Name(new StringLiteral('foo'), new StringLiteral('bar'), new StringLiteral('baz'));
+ $name3 = new Name(new StringLiteral('foo'), new StringLiteral(''), new StringLiteral('baz'));
+
+ $this->assertTrue($this->name->sameValueAs($name2));
+ $this->assertTrue($name2->sameValueAs($this->name));
+ $this->assertFalse($this->name->sameValueAs($name3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($this->name->sameValueAs($mock));
+ }
+
+ public function testToString()
+ {
+ $this->assertEquals('foo bar baz', $this->name->__toString());
+ }
+}
diff --git a/tests/StringLiteral/StringLiteralTest.php b/tests/StringLiteral/StringLiteralTest.php
new file mode 100644
index 0000000..fa1d1cf
--- /dev/null
+++ b/tests/StringLiteral/StringLiteralTest.php
@@ -0,0 +1,56 @@
+assertTrue($string->sameValueAs($constructedString));
+ }
+
+ public function testToNative()
+ {
+ $string = new StringLiteral('foo');
+ $this->assertEquals('foo', $string->toNative());
+ }
+
+ public function testSameValueAs()
+ {
+ $foo1 = new StringLiteral('foo');
+ $foo2 = new StringLiteral('foo');
+ $bar = new StringLiteral('bar');
+
+ $this->assertTrue($foo1->sameValueAs($foo2));
+ $this->assertTrue($foo2->sameValueAs($foo1));
+ $this->assertFalse($foo1->sameValueAs($bar));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($foo1->sameValueAs($mock));
+ }
+
+ /** @expectedException \ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidNativeArgument()
+ {
+ new StringLiteral(12);
+ }
+
+ public function testIsEmpty()
+ {
+ $string = new StringLiteral('');
+
+ $this->assertTrue($string->isEmpty());
+ }
+
+ public function testToString()
+ {
+ $foo = new StringLiteral('foo');
+ $this->assertEquals('foo', $foo->__toString());
+ }
+}
diff --git a/tests/Structure/CollectionTest.php b/tests/Structure/CollectionTest.php
new file mode 100644
index 0000000..3bd357b
--- /dev/null
+++ b/tests/Structure/CollectionTest.php
@@ -0,0 +1,114 @@
+offsetSet(0, new StringLiteral('one'));
+ $array->offsetSet(1, new StringLiteral('two'));
+ $array->offsetSet(2, new Integer(3));
+
+ $this->collection = new Collection($array);
+ }
+
+ /** @expectedException \InvalidArgumentException */
+ public function testInvalidArgument()
+ {
+ $array = \SplFixedArray::fromArray(array('one', 'two', 'three'));
+
+ new Collection($array);
+ }
+
+ public function testFromNative()
+ {
+ $array = \SplFixedArray::fromArray(array(
+ 'one',
+ 'two',
+ array(1, 2)
+ ));
+ $fromNativeCollection = Collection::fromNative($array);
+
+ $innerArray = new Collection(
+ \SplFixedArray::fromArray(array(
+ new StringLiteral('1'),
+ new StringLiteral('2')
+ ))
+ );
+ $array = \SplFixedArray::fromArray(array(
+ new StringLiteral('one'),
+ new StringLiteral('two'),
+ $innerArray
+ ));
+ $constructedCollection = new Collection($array);
+
+ $this->assertTrue($fromNativeCollection->sameValueAs($constructedCollection));
+ }
+
+ public function testSameValueAs()
+ {
+ $array = \SplFixedArray::fromArray(array(
+ new StringLiteral('one'),
+ new StringLiteral('two'),
+ new Integer(3)
+ ));
+ $collection2 = new Collection($array);
+
+ $array = \SplFixedArray::fromArray(array(
+ 'one',
+ 'two',
+ array(1, 2)
+ ));
+ $collection3 = Collection::fromNative($array);
+
+ $this->assertTrue($this->collection->sameValueAs($collection2));
+ $this->assertTrue($collection2->sameValueAs($this->collection));
+ $this->assertFalse($this->collection->sameValueAs($collection3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($this->collection->sameValueAs($mock));
+ }
+
+ public function testCount()
+ {
+ $three = new Natural(3);
+
+ $this->assertTrue($this->collection->count()->sameValueAs($three));
+ }
+
+ public function testContains()
+ {
+ $one = new StringLiteral('one');
+ $ten = new StringLiteral('ten');
+
+ $this->assertTrue($this->collection->contains($one));
+ $this->assertFalse($this->collection->contains($ten));
+ }
+
+ public function testToArray()
+ {
+ $array = array(
+ new StringLiteral('one'),
+ new StringLiteral('two'),
+ new Integer(3)
+ );
+
+ $this->assertEquals($array, $this->collection->toArray());
+ }
+
+ public function testToString()
+ {
+ $this->assertEquals('ValueObjects\Structure\Collection(3)', $this->collection->__toString());
+ }
+}
diff --git a/tests/Structure/DictionaryTest.php b/tests/Structure/DictionaryTest.php
new file mode 100644
index 0000000..e0ea811
--- /dev/null
+++ b/tests/Structure/DictionaryTest.php
@@ -0,0 +1,97 @@
+dictionary = new Dictionary($array);
+ }
+
+ public function testFromNative()
+ {
+ $constructedArray = \SplFixedArray::fromArray(array(
+ new KeyValuePair(new StringLiteral('0'), new StringLiteral('zero')),
+ new KeyValuePair(new StringLiteral('1'), new StringLiteral('one')),
+ new KeyValuePair(new StringLiteral('2'), new StringLiteral('two')),
+ ));
+
+ $fromNativeArray = \SplFixedArray::fromArray(array(
+ 'zero',
+ 'one',
+ 'two'
+ ));
+
+ $constructedDictionary = new Dictionary($constructedArray);
+ $fromNativeDictionary = Dictionary::fromNative($fromNativeArray);
+
+ $this->assertTrue($constructedDictionary->sameValueAs($fromNativeDictionary));
+ }
+
+ /** @expectedException \InvalidArgumentException */
+ public function testInvalidArgument()
+ {
+ $array = \SplFixedArray::fromArray(array('one', 'two', 'three'));
+
+ new Dictionary($array);
+ }
+
+ public function testKeys()
+ {
+ $array = \SplFixedArray::fromArray(array(
+ new Integer(0),
+ new Integer(1),
+ new Integer(2)
+ ));
+ $keys = new Collection($array);
+
+ $this->assertTrue($this->dictionary->keys()->sameValueAs($keys));
+ }
+
+ public function testValues()
+ {
+ $array = \SplFixedArray::fromArray(array(
+ new StringLiteral('zero'),
+ new StringLiteral('one'),
+ new StringLiteral('two')
+ ));
+ $values = new Collection($array);
+
+ $this->assertTrue($this->dictionary->values()->sameValueAs($values));
+ }
+
+ public function testContainsKey()
+ {
+ $one = new Integer(1);
+ $ten = new Integer(10);
+
+ $this->assertTrue($this->dictionary->containsKey($one));
+ $this->assertFalse($this->dictionary->containsKey($ten));
+ }
+
+ public function testContainsValue()
+ {
+ $one = new StringLiteral('one');
+ $ten = new StringLiteral('ten');
+
+ $this->assertTrue($this->dictionary->containsValue($one));
+ $this->assertFalse($this->dictionary->containsValue($ten));
+ }
+}
diff --git a/tests/Structure/KeyValuePairTest.php b/tests/Structure/KeyValuePairTest.php
new file mode 100644
index 0000000..30bac38
--- /dev/null
+++ b/tests/Structure/KeyValuePairTest.php
@@ -0,0 +1,58 @@
+keyValuePair = new KeyValuePair(new StringLiteral('key'), new StringLiteral('value'));
+ }
+
+ public function testFromNative()
+ {
+ $fromNativePair = KeyValuePair::fromNative('key', 'value');
+ $this->assertTrue($this->keyValuePair->sameValueAs($fromNativePair));
+ }
+
+ /** @expectedException \BadMethodCallException */
+ public function testInvalidFromNative()
+ {
+ KeyValuePair::fromNative('key', 'value', 'invalid');
+ }
+
+ public function testSameValueAs()
+ {
+ $keyValuePair2 = new KeyValuePair(new StringLiteral('key'), new StringLiteral('value'));
+ $keyValuePair3 = new KeyValuePair(new StringLiteral('foo'), new StringLiteral('bar'));
+
+ $this->assertTrue($this->keyValuePair->sameValueAs($keyValuePair2));
+ $this->assertTrue($keyValuePair2->sameValueAs($this->keyValuePair));
+ $this->assertFalse($this->keyValuePair->sameValueAs($keyValuePair3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($this->keyValuePair->sameValueAs($mock));
+ }
+
+ public function testGetKey()
+ {
+ $this->assertEquals('key', $this->keyValuePair->getKey());
+ }
+
+ public function testGetValue()
+ {
+ $this->assertEquals('value', $this->keyValuePair->getValue());
+ }
+
+ public function testToString()
+ {
+ $this->assertEquals('key => value', $this->keyValuePair->__toString());
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 0000000..c094ee1
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,7 @@
+assertTrue(Util::classEquals($util1, $util2));
+ $this->assertFalse(Util::classEquals($util1, $this));
+ }
+
+ public function testGetClassAsString()
+ {
+ $util = new Util();
+ $this->assertEquals('ValueObjects\Util\Util', Util::getClassAsString($util));
+ }
+
+}
diff --git a/tests/Web/DomainTest.php b/tests/Web/DomainTest.php
new file mode 100644
index 0000000..66a86ff
--- /dev/null
+++ b/tests/Web/DomainTest.php
@@ -0,0 +1,18 @@
+assertInstanceOf('ValueObjects\Web\IPAddress', $ip);
+ $this->assertInstanceOf('ValueObjects\Web\Hostname', $hostname);
+ }
+}
diff --git a/tests/Web/EmailAddressTest.php b/tests/Web/EmailAddressTest.php
new file mode 100644
index 0000000..ef00cb8
--- /dev/null
+++ b/tests/Web/EmailAddressTest.php
@@ -0,0 +1,41 @@
+assertInstanceOf('ValueObjects\Web\EmailAddress', $email1);
+
+ $email2 = new EmailAddress('foo@[120.0.0.1]');
+ $this->assertInstanceOf('ValueObjects\Web\EmailAddress', $email2);
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidEmailAddress()
+ {
+ new EmailAddress('invalid');
+ }
+
+ public function testGetLocalPart()
+ {
+ $email = new EmailAddress('foo@bar.baz');
+ $localPart = $email->getLocalPart();
+
+ $this->assertEquals('foo', $localPart->toNative());
+ }
+
+ public function testGetDomainPart()
+ {
+ $email = new EmailAddress('foo@bar.com');
+ $domainPart = $email->getDomainPart();
+
+ $this->assertEquals('bar.com', $domainPart->toNative());
+ $this->assertInstanceOf('ValueObjects\Web\Domain', $domainPart);
+ }
+}
diff --git a/tests/Web/FragmentIdentifierTest.php b/tests/Web/FragmentIdentifierTest.php
new file mode 100644
index 0000000..e1f1e73
--- /dev/null
+++ b/tests/Web/FragmentIdentifierTest.php
@@ -0,0 +1,30 @@
+assertInstanceOf('ValueObjects\Web\FragmentIdentifier', $fragment);
+ }
+
+ public function testNullFragmentIdentifier()
+ {
+ $fragment = new NullFragmentIdentifier();
+
+ $this->assertInstanceOf('ValueObjects\Web\FragmentIdentifier', $fragment);
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidFragmentIdentifier()
+ {
+ new FragmentIdentifier('invalìd');
+ }
+}
diff --git a/tests/Web/HostnameTest.php b/tests/Web/HostnameTest.php
new file mode 100644
index 0000000..f1c315e
--- /dev/null
+++ b/tests/Web/HostnameTest.php
@@ -0,0 +1,15 @@
+assertSame(IPAddressVersion::IPV4(), $ip4->getVersion());
+
+ $ip6 = new IPAddress('::1');
+ $this->assertSame(IPAddressVersion::IPV6(), $ip6->getVersion());
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidIPAddress()
+ {
+ new IPAddress('invalid');
+ }
+}
diff --git a/tests/Web/IPv4AddressTest.php b/tests/Web/IPv4AddressTest.php
new file mode 100644
index 0000000..ec57509
--- /dev/null
+++ b/tests/Web/IPv4AddressTest.php
@@ -0,0 +1,22 @@
+assertInstanceOf('ValueObjects\Web\IPv4Address', $ip);
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidIPv4Address()
+ {
+ new IPv4Address('::1');
+ }
+}
diff --git a/tests/Web/IPv6AddressTest.php b/tests/Web/IPv6AddressTest.php
new file mode 100644
index 0000000..a36f1b4
--- /dev/null
+++ b/tests/Web/IPv6AddressTest.php
@@ -0,0 +1,22 @@
+assertInstanceOf('ValueObjects\Web\IPv6Address', $ip);
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidIPv6Address()
+ {
+ new IPv6Address('127.0.0.1');
+ }
+}
diff --git a/tests/Web/PathTest.php b/tests/Web/PathTest.php
new file mode 100644
index 0000000..647f09f
--- /dev/null
+++ b/tests/Web/PathTest.php
@@ -0,0 +1,22 @@
+assertEquals($pathString, $path->toNative());
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidPath()
+ {
+ new Path('//valid?');
+ }
+}
diff --git a/tests/Web/PortNumberTest.php b/tests/Web/PortNumberTest.php
new file mode 100644
index 0000000..432914c
--- /dev/null
+++ b/tests/Web/PortNumberTest.php
@@ -0,0 +1,22 @@
+assertInstanceOf('ValueObjects\Web\PortNumber', $port);
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidPortNumber()
+ {
+ new PortNumber(65536);
+ }
+}
diff --git a/tests/Web/QueryStringTest.php b/tests/Web/QueryStringTest.php
new file mode 100644
index 0000000..3a91003
--- /dev/null
+++ b/tests/Web/QueryStringTest.php
@@ -0,0 +1,53 @@
+assertInstanceOf('ValueObjects\Web\QueryString', $query);
+ }
+
+ public function testEmptyQueryString()
+ {
+ $query = new NullQueryString();
+
+ $this->assertInstanceOf('ValueObjects\Web\QueryString', $query);
+
+ $dictionary = $query->toDictionary();
+ $this->assertInstanceOf('ValueObjects\Structure\Dictionary', $dictionary);
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidQueryString()
+ {
+ new QueryString('invalìd');
+ }
+
+ public function testToDictionary()
+ {
+ $query = new QueryString('?foo=bar&array[]=one&array[]=two');
+ $dictionary = $query->toDictionary();
+
+ $this->assertInstanceOf('ValueObjects\Structure\Dictionary', $dictionary);
+
+ $array = array(
+ 'foo' => 'bar',
+ 'array' => array(
+ 'one',
+ 'two'
+ )
+ );
+ $expectedDictionary = Dictionary::fromNative($array);
+
+ $this->assertTrue($expectedDictionary->sameValueAs($dictionary));
+ }
+}
diff --git a/tests/Web/SchemeNameTest.php b/tests/Web/SchemeNameTest.php
new file mode 100644
index 0000000..d1c5dca
--- /dev/null
+++ b/tests/Web/SchemeNameTest.php
@@ -0,0 +1,21 @@
+assertInstanceOf('ValueObjects\Web\SchemeName', $scheme);
+ }
+
+ /** @expectedException ValueObjects\Exception\InvalidNativeArgumentException */
+ public function testInvalidSchemeName()
+ {
+ new SchemeName('ht*tp');
+ }
+}
diff --git a/tests/Web/UrlTest.php b/tests/Web/UrlTest.php
new file mode 100644
index 0000000..362466c
--- /dev/null
+++ b/tests/Web/UrlTest.php
@@ -0,0 +1,181 @@
+url = new Url(
+ new SchemeName('http'),
+ new StringLiteral('user'),
+ new StringLiteral('pass'),
+ new Hostname('foo.com'),
+ new PortNumber(80),
+ new Path('/bar'),
+ new QueryString('?querystring'),
+ new FragmentIdentifier('#fragmentidentifier')
+ );
+ }
+
+ public function testFromNative()
+ {
+ $nativeUrlString = 'http://user:pass@foo.com:80/bar?querystring#fragmentidentifier';
+ $fromNativeUrl = Url::fromNative($nativeUrlString);
+
+ $this->assertTrue($this->url->sameValueAs($fromNativeUrl));
+
+ $nativeUrlString = 'http://www.test.com';
+ $fromNativeUrl = Url::fromNative($nativeUrlString);
+
+ $this->assertSame($nativeUrlString, $fromNativeUrl->__toString());
+
+ $nativeUrlString = 'http://www.test.com/bar';
+ $fromNativeUrl = Url::fromNative($nativeUrlString);
+
+ $this->assertSame($nativeUrlString, $fromNativeUrl->__toString());
+
+ $nativeUrlString = 'http://www.test.com/?querystring';
+ $fromNativeUrl = Url::fromNative($nativeUrlString);
+
+ $this->assertSame($nativeUrlString, $fromNativeUrl->__toString());
+
+ $nativeUrlString = 'http://www.test.com/#fragmentidentifier';
+ $fromNativeUrl = Url::fromNative($nativeUrlString);
+
+ $this->assertSame($nativeUrlString, $fromNativeUrl->__toString());
+ }
+
+ public function testSameValueAs()
+ {
+ $url2 = new Url(
+ new SchemeName('http'),
+ new StringLiteral('user'),
+ new StringLiteral('pass'),
+ new Hostname('foo.com'),
+ new PortNumber(80),
+ new Path('/bar'),
+ new QueryString('?querystring'),
+ new FragmentIdentifier('#fragmentidentifier')
+ );
+
+ $url3 = new Url(
+ new SchemeName('git+ssh'),
+ new StringLiteral(''),
+ new StringLiteral(''),
+ new Hostname('github.com'),
+ new NullPortNumber(),
+ new Path('/nicolopignatelli/valueobjects'),
+ new QueryString('?querystring'),
+ new FragmentIdentifier('#fragmentidentifier')
+ );
+
+ $this->assertTrue($this->url->sameValueAs($url2));
+ $this->assertTrue($url2->sameValueAs($this->url));
+ $this->assertFalse($this->url->sameValueAs($url3));
+
+ $mock = $this->getMock('ValueObjects\ValueObjectInterface');
+ $this->assertFalse($this->url->sameValueAs($mock));
+ }
+
+ public function testGetDomain()
+ {
+ $domain = new Hostname('foo.com');
+ $this->assertTrue($this->url->getDomain()->sameValueAs($domain));
+ }
+
+ public function testGetFragmentIdentifier()
+ {
+ $fragment = new FragmentIdentifier('#fragmentidentifier');
+ $this->assertTrue($this->url->getFragmentIdentifier()->sameValueAs($fragment));
+ }
+
+ public function testGetPassword()
+ {
+ $password = new StringLiteral('pass');
+ $this->assertTrue($this->url->getPassword()->sameValueAs($password));
+ }
+
+ public function testGetPath()
+ {
+ $path = new Path('/bar');
+ $this->assertTrue($this->url->getPath()->sameValueAs($path));
+ }
+
+ public function testGetPort()
+ {
+ $port = new PortNumber(80);
+ $this->assertTrue($this->url->getPort()->sameValueAs($port));
+ }
+
+ public function testGetQueryString()
+ {
+ $queryString = new QueryString('?querystring');
+ $this->assertTrue($this->url->getQueryString()->sameValueAs($queryString));
+ }
+
+ public function testGetScheme()
+ {
+ $scheme = new SchemeName('http');
+ $this->assertTrue($this->url->getScheme()->sameValueAs($scheme));
+ }
+
+ public function testGetUser()
+ {
+ $user = new StringLiteral('user');
+ $this->assertTrue($this->url->getUser()->sameValueAs($user));
+ }
+
+ public function testToString()
+ {
+ $this->assertSame('http://user:pass@foo.com:80/bar?querystring#fragmentidentifier', $this->url->__toString());
+ }
+
+ public function testAuthlessUrlToString()
+ {
+ $nativeUrlString = 'http://foo.com:80/bar?querystring#fragmentidentifier';
+ $authlessUrl = new Url(
+ new SchemeName('http'),
+ new StringLiteral(''),
+ new StringLiteral(''),
+ new Hostname('foo.com'),
+ new PortNumber(80),
+ new Path('/bar'),
+ new QueryString('?querystring'),
+ new FragmentIdentifier('#fragmentidentifier')
+ );
+ $this->assertSame($nativeUrlString, $authlessUrl->__toString());
+
+ $fromNativeUrl = Url::fromNative($nativeUrlString);
+ $this->assertSame($nativeUrlString, Url::fromNative($authlessUrl)->__toString());
+ }
+
+ public function testNullPortUrlToString()
+ {
+ $nullPortUrl = new Url(
+ new SchemeName('http'),
+ new StringLiteral('user'),
+ new StringLiteral(''),
+ new Hostname('foo.com'),
+ new NullPortNumber(),
+ new Path('/bar'),
+ new QueryString('?querystring'),
+ new FragmentIdentifier('#fragmentidentifier')
+ );
+ $this->assertSame('http://user@foo.com/bar?querystring#fragmentidentifier', $nullPortUrl->__toString());
+ }
+}