From 6949992246f525c155294023ef0abe4338e0b899 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Thu, 16 Apr 2015 12:10:01 +0300 Subject: [PATCH] Simplified tests directory structure a bit --- phpunit.xml.dist | 4 +- tests/.gitignore | 2 + tests/README.md | 20 +- tests/TestCase.php | 100 ++ tests/assets/.gitignore | 3 + tests/bootstrap.php | 22 + tests/data/ar/ActiveRecord.php | 24 + tests/data/ar/Animal.php | 50 + tests/data/ar/Cat.php | 32 + tests/data/ar/Category.php | 43 + tests/data/ar/Customer.php | 87 ++ tests/data/ar/CustomerQuery.php | 18 + tests/data/ar/Dog.php | 32 + tests/data/ar/Item.php | 23 + tests/data/ar/NullValues.php | 20 + tests/data/ar/Order.php | 129 +++ tests/data/ar/OrderItem.php | 29 + tests/data/ar/OrderItemWithNullFK.php | 20 + tests/data/ar/OrderWithNullFK.php | 21 + tests/data/ar/Profile.php | 21 + tests/data/ar/Type.php | 32 + tests/data/base/InvalidRulesModel.php | 17 + tests/data/base/Singer.php | 24 + tests/data/base/Speaker.php | 45 + tests/data/config.php | 53 + .../console/controllers/fixtures/FirstFixture.php | 19 + .../controllers/fixtures/FixtureStorage.php | 21 + .../console/controllers/fixtures/GlobalFixture.php | 20 + .../console/controllers/fixtures/SecondFixture.php | 19 + tests/data/cubrid.sql | 176 +++ tests/data/i18n/messages/de-DE/test.php | 9 + tests/data/i18n/messages/de/test.php | 7 + tests/data/i18n/messages/en-US/test.php | 7 + tests/data/i18n/messages/ru/test.php | 8 + tests/data/i18n/test.mo | Bin 0 -> 1426 bytes tests/data/i18n/test.po | 64 ++ tests/data/mssql.sql | 159 +++ tests/data/mysql.sql | 210 ++++ tests/data/oci.sql | 280 +++++ tests/data/postgres.sql | 210 ++++ tests/data/sqlite.sql | 189 ++++ tests/data/travis/README.md | 12 + tests/data/travis/apc-setup.sh | 8 + tests/data/travis/cubrid-setup.sh | 79 ++ tests/data/travis/cubrid-solo.rb | 5 + tests/data/travis/memcache-setup.sh | 9 + tests/data/validators/TestValidator.php | 43 + .../validators/models/FakedValidationModel.php | 66 ++ .../validators/models/ValidatorTestMainModel.php | 20 + .../validators/models/ValidatorTestRefModel.php | 22 + tests/data/views/layout.php | 20 + tests/data/views/rawlayout.php | 3 + tests/data/views/simple.php | 1 + tests/data/web/assets/.gitignore | 2 + tests/data/web/data.txt | 1 + tests/framework/BaseYiiTest.php | 63 ++ tests/framework/ar/ActiveRecordTestTrait.php | 1144 ++++++++++++++++++++ tests/framework/base/ActionFilterTest.php | 164 +++ tests/framework/base/BehaviorTest.php | 107 ++ tests/framework/base/ComponentTest.php | 451 ++++++++ tests/framework/base/DynamicModelTest.php | 80 ++ tests/framework/base/EventTest.php | 92 ++ tests/framework/base/ExposedSecurity.php | 27 + tests/framework/base/ModelTest.php | 323 ++++++ tests/framework/base/ObjectTest.php | 200 ++++ tests/framework/base/SecurityTest.php | 1062 ++++++++++++++++++ .../framework/behaviors/SluggableBehaviorTest.php | 193 ++++ .../framework/behaviors/TimestampBehaviorTest.php | 110 ++ tests/framework/caching/ApcCacheTest.php | 46 + tests/framework/caching/ArrayCacheTest.php | 49 + tests/framework/caching/CacheTestCase.php | 246 +++++ tests/framework/caching/DbCacheTest.php | 99 ++ tests/framework/caching/FileCacheTest.php | 49 + tests/framework/caching/MemCacheTest.php | 51 + tests/framework/caching/MemCachedTest.php | 51 + tests/framework/caching/TagDependencyTest.php | 79 ++ tests/framework/caching/WinCacheTest.php | 34 + tests/framework/caching/XCacheTest.php | 30 + tests/framework/caching/ZendDataCacheTest.php | 30 + .../console/controllers/AssetControllerTest.php | 602 ++++++++++ .../controllers/BaseMessageControllerTest.php | 385 +++++++ .../console/controllers/CacheControllerTest.php | 143 +++ .../console/controllers/EchoMigrateController.php | 18 + .../console/controllers/FixtureControllerTest.php | 187 ++++ .../console/controllers/MigrateControllerTest.php | 53 + .../controllers/MigrateControllerTestTrait.php | 258 +++++ .../controllers/PHPMessageControllerTest.php | 87 ++ .../controllers/POMessageControllerTest.php | 87 ++ .../controllers/SilencedCacheController.php | 20 + .../controllers/StdOutBufferControllerTrait.php | 27 + tests/framework/data/ActiveDataProviderTest.php | 180 +++ tests/framework/data/ArrayDataProviderTest.php | 182 ++++ tests/framework/data/SortTest.php | 180 +++ tests/framework/db/ActiveRecordTest.php | 694 ++++++++++++ tests/framework/db/BatchQueryResultTest.php | 136 +++ tests/framework/db/CommandTest.php | 403 +++++++ tests/framework/db/ConnectionTest.php | 169 +++ tests/framework/db/DatabaseTestCase.php | 92 ++ tests/framework/db/QueryBuilderTest.php | 480 ++++++++ tests/framework/db/QueryTest.php | 239 ++++ tests/framework/db/SchemaTest.php | 336 ++++++ .../db/cubrid/CubridActiveDataProviderTest.php | 14 + .../framework/db/cubrid/CubridActiveRecordTest.php | 13 + tests/framework/db/cubrid/CubridCommandTest.php | 82 ++ tests/framework/db/cubrid/CubridConnectionTest.php | 44 + .../framework/db/cubrid/CubridQueryBuilderTest.php | 82 ++ tests/framework/db/cubrid/CubridQueryTest.php | 13 + tests/framework/db/cubrid/CubridSchemaTest.php | 73 ++ .../db/mssql/MssqlActiveDataProviderTest.php | 14 + tests/framework/db/mssql/MssqlActiveRecordTest.php | 14 + tests/framework/db/mssql/MssqlCommandTest.php | 84 ++ tests/framework/db/mssql/MssqlConnectionTest.php | 45 + tests/framework/db/mssql/MssqlQueryBuilderTest.php | 57 + tests/framework/db/mssql/MssqlQueryTest.php | 14 + .../db/oci/OracleActiveDataProviderTest.php | 16 + tests/framework/db/oci/OracleActiveRecordTest.php | 110 ++ tests/framework/db/oci/OracleCommandTest.php | 22 + tests/framework/db/oci/OracleQueryTest.php | 25 + tests/framework/db/oci/OracleSchemaTest.php | 97 ++ .../db/pgsql/PostgreSQLActiveDataProviderTest.php | 14 + .../db/pgsql/PostgreSQLActiveRecordTest.php | 190 ++++ tests/framework/db/pgsql/PostgreSQLCommandTest.php | 57 + .../db/pgsql/PostgreSQLConnectionTest.php | 77 ++ .../db/pgsql/PostgreSQLQueryBuilderTest.php | 125 +++ tests/framework/db/pgsql/PostgreSQLQueryTest.php | 40 + tests/framework/db/pgsql/PostgreSQLSchemaTest.php | 109 ++ .../db/sqlite/SqliteActiveDataProviderTest.php | 14 + .../framework/db/sqlite/SqliteActiveRecordTest.php | 13 + tests/framework/db/sqlite/SqliteCommandTest.php | 22 + tests/framework/db/sqlite/SqliteConnectionTest.php | 145 +++ .../framework/db/sqlite/SqliteQueryBuilderTest.php | 94 ++ tests/framework/db/sqlite/SqliteQueryTest.php | 13 + tests/framework/db/sqlite/SqliteSchemaTest.php | 33 + tests/framework/di/ContainerTest.php | 103 ++ tests/framework/di/InstanceTest.php | 49 + tests/framework/di/ServiceLocatorTest.php | 88 ++ tests/framework/di/stubs/Bar.php | 25 + tests/framework/di/stubs/Foo.php | 25 + tests/framework/di/stubs/Qux.php | 29 + tests/framework/di/stubs/QuxInterface.php | 17 + tests/framework/filters/CompositeAuthTest.php | 121 +++ tests/framework/filters/HttpCacheTest.php | 79 ++ tests/framework/helpers/ArrayHelperTest.php | 467 ++++++++ tests/framework/helpers/ConsoleTest.php | 132 +++ tests/framework/helpers/FallbackInflector.php | 21 + tests/framework/helpers/FileHelperTest.php | 568 ++++++++++ tests/framework/helpers/FormatConverterTest.php | 75 ++ tests/framework/helpers/HtmlTest.php | 658 +++++++++++ tests/framework/helpers/InflectorTest.php | 248 +++++ tests/framework/helpers/JsonTest.php | 81 ++ tests/framework/helpers/StringHelperTest.php | 239 ++++ tests/framework/helpers/UrlTest.php | 208 ++++ tests/framework/helpers/VarDumperTest.php | 108 ++ .../i18n/FallbackMessageFormatterTest.php | 179 +++ tests/framework/i18n/FormatterDateTest.php | 575 ++++++++++ tests/framework/i18n/FormatterNumberTest.php | 509 +++++++++ tests/framework/i18n/FormatterTest.php | 194 ++++ tests/framework/i18n/GettextMessageSourceTest.php | 16 + tests/framework/i18n/GettextMoFileTest.php | 98 ++ tests/framework/i18n/GettextPoFileTest.php | 98 ++ tests/framework/i18n/I18NTest.php | 177 +++ tests/framework/i18n/IntlTestHelper.php | 77 ++ tests/framework/i18n/MessageFormatterTest.php | 337 ++++++ tests/framework/log/DbTargetTest.php | 142 +++ tests/framework/log/FileTargetTest.php | 105 ++ tests/framework/log/LoggerTest.php | 33 + tests/framework/log/MySQLTargetTest.php | 10 + tests/framework/log/PgSQLTargetTest.php | 10 + tests/framework/log/SqliteTargetTest.php | 10 + tests/framework/log/TargetTest.php | 93 ++ tests/framework/mail/BaseMailerTest.php | 449 ++++++++ tests/framework/mail/BaseMessageTest.php | 153 +++ tests/framework/rbac/AuthorRule.php | 21 + tests/framework/rbac/DbManagerTestCase.php | 119 ++ tests/framework/rbac/ExposedPhpManager.php | 37 + tests/framework/rbac/ManagerTestCase.php | 289 +++++ tests/framework/rbac/MySQLManagerCacheTest.php | 24 + tests/framework/rbac/MySQLManagerTest.php | 12 + tests/framework/rbac/PgSQLManagerTest.php | 12 + tests/framework/rbac/PhpManagerTest.php | 142 +++ tests/framework/rbac/SqliteManagerTest.php | 12 + .../requirements/YiiRequirementCheckerTest.php | 201 ++++ tests/framework/test/ActiveFixtureTest.php | 96 ++ tests/framework/test/ArrayFixtureTest.php | 58 + tests/framework/test/FixtureTest.php | 169 +++ tests/framework/test/data/array_fixture.php | 16 + tests/framework/test/data/customer.php | 16 + .../framework/validators/BooleanValidatorTest.php | 60 + .../framework/validators/CompareValidatorTest.php | 176 +++ tests/framework/validators/DateValidatorTest.php | 201 ++++ .../validators/DefaultValueValidatorTest.php | 40 + tests/framework/validators/EachValidatorTest.php | 75 ++ tests/framework/validators/EmailValidatorTest.php | 118 ++ .../ExistValidatorPostgresTest.php | 12 + .../ExistValidatorSQliteTest.php | 12 + tests/framework/validators/ExistValidatorTest.php | 168 +++ tests/framework/validators/FileValidatorTest.php | 377 +++++++ tests/framework/validators/FilterValidatorTest.php | 66 ++ tests/framework/validators/NumberValidatorTest.php | 211 ++++ tests/framework/validators/RangeValidatorTest.php | 108 ++ .../validators/RegularExpressionValidatorTest.php | 55 + .../framework/validators/RequiredValidatorTest.php | 62 ++ tests/framework/validators/StringValidatorTest.php | 118 ++ .../UniqueValidatorPostgresTest.php | 13 + .../UniqueValidatorSQliteTest.php | 13 + tests/framework/validators/UniqueValidatorTest.php | 139 +++ tests/framework/validators/UrlValidatorTest.php | 103 ++ tests/framework/validators/ValidatorTest.php | 228 ++++ tests/framework/web/AssetBundleTest.php | 273 +++++ tests/framework/web/AssetConverterTest.php | 87 ++ tests/framework/web/CacheSessionTest.php | 36 + tests/framework/web/FormatterTest.php | 77 ++ tests/framework/web/GroupUrlRuleTest.php | 216 ++++ tests/framework/web/JsonResponseFormatterTest.php | 76 ++ tests/framework/web/Post.php | 16 + tests/framework/web/RequestTest.php | 81 ++ tests/framework/web/ResponseTest.php | 104 ++ tests/framework/web/UrlManagerTest.php | 372 +++++++ tests/framework/web/UrlRuleTest.php | 710 ++++++++++++ tests/framework/web/UserTest.php | 137 +++ tests/framework/web/XmlResponseFormatterTest.php | 86 ++ tests/framework/widgets/ActiveFieldTest.php | 366 +++++++ tests/framework/widgets/ActiveFormTest.php | 77 ++ tests/framework/widgets/BreadcrumbsTest.php | 175 +++ tests/framework/widgets/LinkSorterTest.php | 76 ++ tests/framework/widgets/MenuTest.php | 104 ++ tests/framework/widgets/SpacelessTest.php | 41 + tests/runtime/.gitignore | 3 + tests/unit/.gitignore | 2 - tests/unit/TestCase.php | 100 -- tests/unit/assets/.gitignore | 3 - tests/unit/bootstrap.php | 22 - tests/unit/data/ar/ActiveRecord.php | 24 - tests/unit/data/ar/Animal.php | 50 - tests/unit/data/ar/Cat.php | 32 - tests/unit/data/ar/Category.php | 43 - tests/unit/data/ar/Customer.php | 87 -- tests/unit/data/ar/CustomerQuery.php | 18 - tests/unit/data/ar/Dog.php | 32 - tests/unit/data/ar/Item.php | 23 - tests/unit/data/ar/NullValues.php | 20 - tests/unit/data/ar/Order.php | 129 --- tests/unit/data/ar/OrderItem.php | 29 - tests/unit/data/ar/OrderItemWithNullFK.php | 20 - tests/unit/data/ar/OrderWithNullFK.php | 21 - tests/unit/data/ar/Profile.php | 21 - tests/unit/data/ar/Type.php | 32 - tests/unit/data/base/InvalidRulesModel.php | 17 - tests/unit/data/base/Singer.php | 24 - tests/unit/data/base/Speaker.php | 45 - tests/unit/data/config.php | 53 - .../console/controllers/fixtures/FirstFixture.php | 19 - .../controllers/fixtures/FixtureStorage.php | 21 - .../console/controllers/fixtures/GlobalFixture.php | 20 - .../console/controllers/fixtures/SecondFixture.php | 19 - tests/unit/data/cubrid.sql | 176 --- tests/unit/data/i18n/messages/de-DE/test.php | 9 - tests/unit/data/i18n/messages/de/test.php | 7 - tests/unit/data/i18n/messages/en-US/test.php | 7 - tests/unit/data/i18n/messages/ru/test.php | 8 - tests/unit/data/i18n/test.mo | Bin 1426 -> 0 bytes tests/unit/data/i18n/test.po | 64 -- tests/unit/data/mssql.sql | 159 --- tests/unit/data/mysql.sql | 210 ---- tests/unit/data/oci.sql | 280 ----- tests/unit/data/postgres.sql | 210 ---- tests/unit/data/sqlite.sql | 189 ---- tests/unit/data/travis/README.md | 12 - tests/unit/data/travis/apc-setup.sh | 8 - tests/unit/data/travis/cubrid-setup.sh | 79 -- tests/unit/data/travis/cubrid-solo.rb | 5 - tests/unit/data/travis/memcache-setup.sh | 9 - tests/unit/data/validators/TestValidator.php | 43 - .../validators/models/FakedValidationModel.php | 66 -- .../validators/models/ValidatorTestMainModel.php | 20 - .../validators/models/ValidatorTestRefModel.php | 22 - tests/unit/data/views/layout.php | 20 - tests/unit/data/views/rawlayout.php | 3 - tests/unit/data/views/simple.php | 1 - tests/unit/data/web/assets/.gitignore | 2 - tests/unit/data/web/data.txt | 1 - tests/unit/framework/BaseYiiTest.php | 63 -- tests/unit/framework/ar/ActiveRecordTestTrait.php | 1144 -------------------- tests/unit/framework/base/ActionFilterTest.php | 164 --- tests/unit/framework/base/BehaviorTest.php | 107 -- tests/unit/framework/base/ComponentTest.php | 451 -------- tests/unit/framework/base/DynamicModelTest.php | 80 -- tests/unit/framework/base/EventTest.php | 92 -- tests/unit/framework/base/ExposedSecurity.php | 27 - tests/unit/framework/base/ModelTest.php | 323 ------ tests/unit/framework/base/ObjectTest.php | 200 ---- tests/unit/framework/base/SecurityTest.php | 1062 ------------------ .../framework/behaviors/SluggableBehaviorTest.php | 193 ---- .../framework/behaviors/TimestampBehaviorTest.php | 110 -- tests/unit/framework/caching/ApcCacheTest.php | 46 - tests/unit/framework/caching/ArrayCacheTest.php | 49 - tests/unit/framework/caching/CacheTestCase.php | 246 ----- tests/unit/framework/caching/DbCacheTest.php | 99 -- tests/unit/framework/caching/FileCacheTest.php | 49 - tests/unit/framework/caching/MemCacheTest.php | 51 - tests/unit/framework/caching/MemCachedTest.php | 51 - tests/unit/framework/caching/TagDependencyTest.php | 79 -- tests/unit/framework/caching/WinCacheTest.php | 34 - tests/unit/framework/caching/XCacheTest.php | 30 - tests/unit/framework/caching/ZendDataCacheTest.php | 30 - .../console/controllers/AssetControllerTest.php | 602 ---------- .../controllers/BaseMessageControllerTest.php | 385 ------- .../console/controllers/CacheControllerTest.php | 143 --- .../console/controllers/EchoMigrateController.php | 18 - .../console/controllers/FixtureControllerTest.php | 187 ---- .../console/controllers/MigrateControllerTest.php | 53 - .../controllers/MigrateControllerTestTrait.php | 258 ----- .../controllers/PHPMessageControllerTest.php | 87 -- .../controllers/POMessageControllerTest.php | 87 -- .../controllers/SilencedCacheController.php | 20 - .../controllers/StdOutBufferControllerTrait.php | 27 - .../unit/framework/data/ActiveDataProviderTest.php | 180 --- .../unit/framework/data/ArrayDataProviderTest.php | 182 ---- tests/unit/framework/data/SortTest.php | 180 --- tests/unit/framework/db/ActiveRecordTest.php | 694 ------------ tests/unit/framework/db/BatchQueryResultTest.php | 136 --- tests/unit/framework/db/CommandTest.php | 403 ------- tests/unit/framework/db/ConnectionTest.php | 169 --- tests/unit/framework/db/DatabaseTestCase.php | 92 -- tests/unit/framework/db/QueryBuilderTest.php | 480 -------- tests/unit/framework/db/QueryTest.php | 239 ---- tests/unit/framework/db/SchemaTest.php | 336 ------ .../db/cubrid/CubridActiveDataProviderTest.php | 14 - .../framework/db/cubrid/CubridActiveRecordTest.php | 13 - .../unit/framework/db/cubrid/CubridCommandTest.php | 82 -- .../framework/db/cubrid/CubridConnectionTest.php | 44 - .../framework/db/cubrid/CubridQueryBuilderTest.php | 82 -- tests/unit/framework/db/cubrid/CubridQueryTest.php | 13 - .../unit/framework/db/cubrid/CubridSchemaTest.php | 73 -- .../db/mssql/MssqlActiveDataProviderTest.php | 14 - .../framework/db/mssql/MssqlActiveRecordTest.php | 14 - tests/unit/framework/db/mssql/MssqlCommandTest.php | 84 -- .../framework/db/mssql/MssqlConnectionTest.php | 45 - .../framework/db/mssql/MssqlQueryBuilderTest.php | 57 - tests/unit/framework/db/mssql/MssqlQueryTest.php | 14 - .../db/oci/OracleActiveDataProviderTest.php | 16 - .../framework/db/oci/OracleActiveRecordTest.php | 110 -- tests/unit/framework/db/oci/OracleCommandTest.php | 22 - tests/unit/framework/db/oci/OracleQueryTest.php | 25 - tests/unit/framework/db/oci/OracleSchemaTest.php | 97 -- .../db/pgsql/PostgreSQLActiveDataProviderTest.php | 14 - .../db/pgsql/PostgreSQLActiveRecordTest.php | 190 ---- .../framework/db/pgsql/PostgreSQLCommandTest.php | 57 - .../db/pgsql/PostgreSQLConnectionTest.php | 77 -- .../db/pgsql/PostgreSQLQueryBuilderTest.php | 125 --- .../framework/db/pgsql/PostgreSQLQueryTest.php | 40 - .../framework/db/pgsql/PostgreSQLSchemaTest.php | 109 -- .../db/sqlite/SqliteActiveDataProviderTest.php | 14 - .../framework/db/sqlite/SqliteActiveRecordTest.php | 13 - .../unit/framework/db/sqlite/SqliteCommandTest.php | 22 - .../framework/db/sqlite/SqliteConnectionTest.php | 145 --- .../framework/db/sqlite/SqliteQueryBuilderTest.php | 94 -- tests/unit/framework/db/sqlite/SqliteQueryTest.php | 13 - .../unit/framework/db/sqlite/SqliteSchemaTest.php | 33 - tests/unit/framework/di/ContainerTest.php | 103 -- tests/unit/framework/di/InstanceTest.php | 49 - tests/unit/framework/di/ServiceLocatorTest.php | 88 -- tests/unit/framework/di/stubs/Bar.php | 25 - tests/unit/framework/di/stubs/Foo.php | 25 - tests/unit/framework/di/stubs/Qux.php | 29 - tests/unit/framework/di/stubs/QuxInterface.php | 17 - tests/unit/framework/filters/CompositeAuthTest.php | 121 --- tests/unit/framework/filters/HttpCacheTest.php | 79 -- tests/unit/framework/helpers/ArrayHelperTest.php | 467 -------- tests/unit/framework/helpers/ConsoleTest.php | 132 --- tests/unit/framework/helpers/FallbackInflector.php | 21 - tests/unit/framework/helpers/FileHelperTest.php | 568 ---------- .../unit/framework/helpers/FormatConverterTest.php | 75 -- tests/unit/framework/helpers/HtmlTest.php | 658 ----------- tests/unit/framework/helpers/InflectorTest.php | 248 ----- tests/unit/framework/helpers/JsonTest.php | 81 -- tests/unit/framework/helpers/StringHelperTest.php | 239 ---- tests/unit/framework/helpers/UrlTest.php | 208 ---- tests/unit/framework/helpers/VarDumperTest.php | 108 -- .../i18n/FallbackMessageFormatterTest.php | 179 --- tests/unit/framework/i18n/FormatterDateTest.php | 575 ---------- tests/unit/framework/i18n/FormatterNumberTest.php | 509 --------- tests/unit/framework/i18n/FormatterTest.php | 194 ---- .../framework/i18n/GettextMessageSourceTest.php | 16 - tests/unit/framework/i18n/GettextMoFileTest.php | 98 -- tests/unit/framework/i18n/GettextPoFileTest.php | 98 -- tests/unit/framework/i18n/I18NTest.php | 177 --- tests/unit/framework/i18n/IntlTestHelper.php | 77 -- tests/unit/framework/i18n/MessageFormatterTest.php | 337 ------ tests/unit/framework/log/DbTargetTest.php | 142 --- tests/unit/framework/log/FileTargetTest.php | 105 -- tests/unit/framework/log/LoggerTest.php | 33 - tests/unit/framework/log/MySQLTargetTest.php | 10 - tests/unit/framework/log/PgSQLTargetTest.php | 10 - tests/unit/framework/log/SqliteTargetTest.php | 10 - tests/unit/framework/log/TargetTest.php | 93 -- tests/unit/framework/mail/BaseMailerTest.php | 449 -------- tests/unit/framework/mail/BaseMessageTest.php | 153 --- tests/unit/framework/rbac/AuthorRule.php | 21 - tests/unit/framework/rbac/DbManagerTestCase.php | 119 -- tests/unit/framework/rbac/ExposedPhpManager.php | 37 - tests/unit/framework/rbac/ManagerTestCase.php | 289 ----- .../unit/framework/rbac/MySQLManagerCacheTest.php | 24 - tests/unit/framework/rbac/MySQLManagerTest.php | 12 - tests/unit/framework/rbac/PgSQLManagerTest.php | 12 - tests/unit/framework/rbac/PhpManagerTest.php | 142 --- tests/unit/framework/rbac/SqliteManagerTest.php | 12 - .../requirements/YiiRequirementCheckerTest.php | 201 ---- tests/unit/framework/test/ActiveFixtureTest.php | 96 -- tests/unit/framework/test/ArrayFixtureTest.php | 58 - tests/unit/framework/test/FixtureTest.php | 169 --- tests/unit/framework/test/data/array_fixture.php | 16 - tests/unit/framework/test/data/customer.php | 16 - .../framework/validators/BooleanValidatorTest.php | 60 - .../framework/validators/CompareValidatorTest.php | 176 --- .../framework/validators/DateValidatorTest.php | 201 ---- .../validators/DefaultValueValidatorTest.php | 40 - .../framework/validators/EachValidatorTest.php | 75 -- .../framework/validators/EmailValidatorTest.php | 118 -- .../ExistValidatorPostgresTest.php | 12 - .../ExistValidatorSQliteTest.php | 12 - .../framework/validators/ExistValidatorTest.php | 168 --- .../framework/validators/FileValidatorTest.php | 377 ------- .../framework/validators/FilterValidatorTest.php | 66 -- .../framework/validators/NumberValidatorTest.php | 211 ---- .../framework/validators/RangeValidatorTest.php | 108 -- .../validators/RegularExpressionValidatorTest.php | 55 - .../framework/validators/RequiredValidatorTest.php | 62 -- .../framework/validators/StringValidatorTest.php | 118 -- .../UniqueValidatorPostgresTest.php | 13 - .../UniqueValidatorSQliteTest.php | 13 - .../framework/validators/UniqueValidatorTest.php | 139 --- .../unit/framework/validators/UrlValidatorTest.php | 103 -- tests/unit/framework/validators/ValidatorTest.php | 228 ---- tests/unit/framework/web/AssetBundleTest.php | 273 ----- tests/unit/framework/web/AssetConverterTest.php | 87 -- tests/unit/framework/web/CacheSessionTest.php | 36 - tests/unit/framework/web/FormatterTest.php | 77 -- tests/unit/framework/web/GroupUrlRuleTest.php | 216 ---- .../framework/web/JsonResponseFormatterTest.php | 76 -- tests/unit/framework/web/Post.php | 16 - tests/unit/framework/web/RequestTest.php | 81 -- tests/unit/framework/web/ResponseTest.php | 104 -- tests/unit/framework/web/UrlManagerTest.php | 372 ------- tests/unit/framework/web/UrlRuleTest.php | 710 ------------ tests/unit/framework/web/UserTest.php | 137 --- .../framework/web/XmlResponseFormatterTest.php | 86 -- tests/unit/framework/widgets/ActiveFieldTest.php | 366 ------- tests/unit/framework/widgets/ActiveFormTest.php | 77 -- tests/unit/framework/widgets/BreadcrumbsTest.php | 175 --- tests/unit/framework/widgets/LinkSorterTest.php | 76 -- tests/unit/framework/widgets/MenuTest.php | 104 -- tests/unit/framework/widgets/SpacelessTest.php | 41 - tests/unit/runtime/.gitignore | 3 - tests/unit/runtime/coveralls/.gitkeep | 0 tests/web/app/assets/.gitignore | 1 - tests/web/app/index.php | 6 - tests/web/app/protected/config/main.php | 3 - .../app/protected/controllers/SiteController.php | 30 - tests/web/app/protected/runtime/.gitignore | 1 - tests/web/app/protected/views/site/index.php | 8 - 461 files changed, 27351 insertions(+), 27396 deletions(-) create mode 100644 tests/.gitignore create mode 100644 tests/TestCase.php create mode 100644 tests/assets/.gitignore create mode 100644 tests/bootstrap.php create mode 100644 tests/data/ar/ActiveRecord.php create mode 100644 tests/data/ar/Animal.php create mode 100644 tests/data/ar/Cat.php create mode 100644 tests/data/ar/Category.php create mode 100644 tests/data/ar/Customer.php create mode 100644 tests/data/ar/CustomerQuery.php create mode 100644 tests/data/ar/Dog.php create mode 100644 tests/data/ar/Item.php create mode 100644 tests/data/ar/NullValues.php create mode 100644 tests/data/ar/Order.php create mode 100644 tests/data/ar/OrderItem.php create mode 100644 tests/data/ar/OrderItemWithNullFK.php create mode 100644 tests/data/ar/OrderWithNullFK.php create mode 100644 tests/data/ar/Profile.php create mode 100644 tests/data/ar/Type.php create mode 100644 tests/data/base/InvalidRulesModel.php create mode 100644 tests/data/base/Singer.php create mode 100644 tests/data/base/Speaker.php create mode 100644 tests/data/config.php create mode 100644 tests/data/console/controllers/fixtures/FirstFixture.php create mode 100644 tests/data/console/controllers/fixtures/FixtureStorage.php create mode 100644 tests/data/console/controllers/fixtures/GlobalFixture.php create mode 100644 tests/data/console/controllers/fixtures/SecondFixture.php create mode 100644 tests/data/cubrid.sql create mode 100644 tests/data/i18n/messages/de-DE/test.php create mode 100644 tests/data/i18n/messages/de/test.php create mode 100644 tests/data/i18n/messages/en-US/test.php create mode 100644 tests/data/i18n/messages/ru/test.php create mode 100644 tests/data/i18n/test.mo create mode 100644 tests/data/i18n/test.po create mode 100644 tests/data/mssql.sql create mode 100644 tests/data/mysql.sql create mode 100644 tests/data/oci.sql create mode 100644 tests/data/postgres.sql create mode 100644 tests/data/sqlite.sql create mode 100644 tests/data/travis/README.md create mode 100644 tests/data/travis/apc-setup.sh create mode 100644 tests/data/travis/cubrid-setup.sh create mode 100644 tests/data/travis/cubrid-solo.rb create mode 100644 tests/data/travis/memcache-setup.sh create mode 100644 tests/data/validators/TestValidator.php create mode 100644 tests/data/validators/models/FakedValidationModel.php create mode 100644 tests/data/validators/models/ValidatorTestMainModel.php create mode 100644 tests/data/validators/models/ValidatorTestRefModel.php create mode 100644 tests/data/views/layout.php create mode 100644 tests/data/views/rawlayout.php create mode 100644 tests/data/views/simple.php create mode 100644 tests/data/web/assets/.gitignore create mode 100644 tests/data/web/data.txt create mode 100644 tests/framework/BaseYiiTest.php create mode 100644 tests/framework/ar/ActiveRecordTestTrait.php create mode 100644 tests/framework/base/ActionFilterTest.php create mode 100644 tests/framework/base/BehaviorTest.php create mode 100644 tests/framework/base/ComponentTest.php create mode 100644 tests/framework/base/DynamicModelTest.php create mode 100644 tests/framework/base/EventTest.php create mode 100644 tests/framework/base/ExposedSecurity.php create mode 100644 tests/framework/base/ModelTest.php create mode 100644 tests/framework/base/ObjectTest.php create mode 100644 tests/framework/base/SecurityTest.php create mode 100644 tests/framework/behaviors/SluggableBehaviorTest.php create mode 100644 tests/framework/behaviors/TimestampBehaviorTest.php create mode 100644 tests/framework/caching/ApcCacheTest.php create mode 100644 tests/framework/caching/ArrayCacheTest.php create mode 100644 tests/framework/caching/CacheTestCase.php create mode 100644 tests/framework/caching/DbCacheTest.php create mode 100644 tests/framework/caching/FileCacheTest.php create mode 100644 tests/framework/caching/MemCacheTest.php create mode 100644 tests/framework/caching/MemCachedTest.php create mode 100644 tests/framework/caching/TagDependencyTest.php create mode 100644 tests/framework/caching/WinCacheTest.php create mode 100644 tests/framework/caching/XCacheTest.php create mode 100644 tests/framework/caching/ZendDataCacheTest.php create mode 100644 tests/framework/console/controllers/AssetControllerTest.php create mode 100644 tests/framework/console/controllers/BaseMessageControllerTest.php create mode 100644 tests/framework/console/controllers/CacheControllerTest.php create mode 100644 tests/framework/console/controllers/EchoMigrateController.php create mode 100644 tests/framework/console/controllers/FixtureControllerTest.php create mode 100644 tests/framework/console/controllers/MigrateControllerTest.php create mode 100644 tests/framework/console/controllers/MigrateControllerTestTrait.php create mode 100644 tests/framework/console/controllers/PHPMessageControllerTest.php create mode 100644 tests/framework/console/controllers/POMessageControllerTest.php create mode 100644 tests/framework/console/controllers/SilencedCacheController.php create mode 100644 tests/framework/console/controllers/StdOutBufferControllerTrait.php create mode 100644 tests/framework/data/ActiveDataProviderTest.php create mode 100644 tests/framework/data/ArrayDataProviderTest.php create mode 100644 tests/framework/data/SortTest.php create mode 100644 tests/framework/db/ActiveRecordTest.php create mode 100644 tests/framework/db/BatchQueryResultTest.php create mode 100644 tests/framework/db/CommandTest.php create mode 100644 tests/framework/db/ConnectionTest.php create mode 100644 tests/framework/db/DatabaseTestCase.php create mode 100644 tests/framework/db/QueryBuilderTest.php create mode 100644 tests/framework/db/QueryTest.php create mode 100644 tests/framework/db/SchemaTest.php create mode 100644 tests/framework/db/cubrid/CubridActiveDataProviderTest.php create mode 100644 tests/framework/db/cubrid/CubridActiveRecordTest.php create mode 100644 tests/framework/db/cubrid/CubridCommandTest.php create mode 100644 tests/framework/db/cubrid/CubridConnectionTest.php create mode 100644 tests/framework/db/cubrid/CubridQueryBuilderTest.php create mode 100644 tests/framework/db/cubrid/CubridQueryTest.php create mode 100644 tests/framework/db/cubrid/CubridSchemaTest.php create mode 100644 tests/framework/db/mssql/MssqlActiveDataProviderTest.php create mode 100644 tests/framework/db/mssql/MssqlActiveRecordTest.php create mode 100644 tests/framework/db/mssql/MssqlCommandTest.php create mode 100644 tests/framework/db/mssql/MssqlConnectionTest.php create mode 100644 tests/framework/db/mssql/MssqlQueryBuilderTest.php create mode 100644 tests/framework/db/mssql/MssqlQueryTest.php create mode 100644 tests/framework/db/oci/OracleActiveDataProviderTest.php create mode 100644 tests/framework/db/oci/OracleActiveRecordTest.php create mode 100644 tests/framework/db/oci/OracleCommandTest.php create mode 100644 tests/framework/db/oci/OracleQueryTest.php create mode 100644 tests/framework/db/oci/OracleSchemaTest.php create mode 100644 tests/framework/db/pgsql/PostgreSQLActiveDataProviderTest.php create mode 100644 tests/framework/db/pgsql/PostgreSQLActiveRecordTest.php create mode 100644 tests/framework/db/pgsql/PostgreSQLCommandTest.php create mode 100644 tests/framework/db/pgsql/PostgreSQLConnectionTest.php create mode 100644 tests/framework/db/pgsql/PostgreSQLQueryBuilderTest.php create mode 100644 tests/framework/db/pgsql/PostgreSQLQueryTest.php create mode 100644 tests/framework/db/pgsql/PostgreSQLSchemaTest.php create mode 100644 tests/framework/db/sqlite/SqliteActiveDataProviderTest.php create mode 100644 tests/framework/db/sqlite/SqliteActiveRecordTest.php create mode 100644 tests/framework/db/sqlite/SqliteCommandTest.php create mode 100644 tests/framework/db/sqlite/SqliteConnectionTest.php create mode 100644 tests/framework/db/sqlite/SqliteQueryBuilderTest.php create mode 100644 tests/framework/db/sqlite/SqliteQueryTest.php create mode 100644 tests/framework/db/sqlite/SqliteSchemaTest.php create mode 100644 tests/framework/di/ContainerTest.php create mode 100644 tests/framework/di/InstanceTest.php create mode 100644 tests/framework/di/ServiceLocatorTest.php create mode 100644 tests/framework/di/stubs/Bar.php create mode 100644 tests/framework/di/stubs/Foo.php create mode 100644 tests/framework/di/stubs/Qux.php create mode 100644 tests/framework/di/stubs/QuxInterface.php create mode 100644 tests/framework/filters/CompositeAuthTest.php create mode 100644 tests/framework/filters/HttpCacheTest.php create mode 100644 tests/framework/helpers/ArrayHelperTest.php create mode 100644 tests/framework/helpers/ConsoleTest.php create mode 100644 tests/framework/helpers/FallbackInflector.php create mode 100644 tests/framework/helpers/FileHelperTest.php create mode 100644 tests/framework/helpers/FormatConverterTest.php create mode 100644 tests/framework/helpers/HtmlTest.php create mode 100644 tests/framework/helpers/InflectorTest.php create mode 100644 tests/framework/helpers/JsonTest.php create mode 100644 tests/framework/helpers/StringHelperTest.php create mode 100644 tests/framework/helpers/UrlTest.php create mode 100644 tests/framework/helpers/VarDumperTest.php create mode 100644 tests/framework/i18n/FallbackMessageFormatterTest.php create mode 100644 tests/framework/i18n/FormatterDateTest.php create mode 100644 tests/framework/i18n/FormatterNumberTest.php create mode 100644 tests/framework/i18n/FormatterTest.php create mode 100644 tests/framework/i18n/GettextMessageSourceTest.php create mode 100644 tests/framework/i18n/GettextMoFileTest.php create mode 100644 tests/framework/i18n/GettextPoFileTest.php create mode 100644 tests/framework/i18n/I18NTest.php create mode 100644 tests/framework/i18n/IntlTestHelper.php create mode 100644 tests/framework/i18n/MessageFormatterTest.php create mode 100644 tests/framework/log/DbTargetTest.php create mode 100644 tests/framework/log/FileTargetTest.php create mode 100644 tests/framework/log/LoggerTest.php create mode 100644 tests/framework/log/MySQLTargetTest.php create mode 100644 tests/framework/log/PgSQLTargetTest.php create mode 100644 tests/framework/log/SqliteTargetTest.php create mode 100644 tests/framework/log/TargetTest.php create mode 100644 tests/framework/mail/BaseMailerTest.php create mode 100644 tests/framework/mail/BaseMessageTest.php create mode 100644 tests/framework/rbac/AuthorRule.php create mode 100644 tests/framework/rbac/DbManagerTestCase.php create mode 100644 tests/framework/rbac/ExposedPhpManager.php create mode 100644 tests/framework/rbac/ManagerTestCase.php create mode 100644 tests/framework/rbac/MySQLManagerCacheTest.php create mode 100644 tests/framework/rbac/MySQLManagerTest.php create mode 100644 tests/framework/rbac/PgSQLManagerTest.php create mode 100644 tests/framework/rbac/PhpManagerTest.php create mode 100644 tests/framework/rbac/SqliteManagerTest.php create mode 100644 tests/framework/requirements/YiiRequirementCheckerTest.php create mode 100644 tests/framework/test/ActiveFixtureTest.php create mode 100644 tests/framework/test/ArrayFixtureTest.php create mode 100644 tests/framework/test/FixtureTest.php create mode 100644 tests/framework/test/data/array_fixture.php create mode 100644 tests/framework/test/data/customer.php create mode 100644 tests/framework/validators/BooleanValidatorTest.php create mode 100644 tests/framework/validators/CompareValidatorTest.php create mode 100644 tests/framework/validators/DateValidatorTest.php create mode 100644 tests/framework/validators/DefaultValueValidatorTest.php create mode 100644 tests/framework/validators/EachValidatorTest.php create mode 100644 tests/framework/validators/EmailValidatorTest.php create mode 100644 tests/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php create mode 100644 tests/framework/validators/ExistValidatorDriverTests/ExistValidatorSQliteTest.php create mode 100644 tests/framework/validators/ExistValidatorTest.php create mode 100644 tests/framework/validators/FileValidatorTest.php create mode 100644 tests/framework/validators/FilterValidatorTest.php create mode 100644 tests/framework/validators/NumberValidatorTest.php create mode 100644 tests/framework/validators/RangeValidatorTest.php create mode 100644 tests/framework/validators/RegularExpressionValidatorTest.php create mode 100644 tests/framework/validators/RequiredValidatorTest.php create mode 100644 tests/framework/validators/StringValidatorTest.php create mode 100644 tests/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php create mode 100644 tests/framework/validators/UniqueValidatorDriverTests/UniqueValidatorSQliteTest.php create mode 100644 tests/framework/validators/UniqueValidatorTest.php create mode 100644 tests/framework/validators/UrlValidatorTest.php create mode 100644 tests/framework/validators/ValidatorTest.php create mode 100644 tests/framework/web/AssetBundleTest.php create mode 100644 tests/framework/web/AssetConverterTest.php create mode 100644 tests/framework/web/CacheSessionTest.php create mode 100644 tests/framework/web/FormatterTest.php create mode 100644 tests/framework/web/GroupUrlRuleTest.php create mode 100644 tests/framework/web/JsonResponseFormatterTest.php create mode 100644 tests/framework/web/Post.php create mode 100644 tests/framework/web/RequestTest.php create mode 100644 tests/framework/web/ResponseTest.php create mode 100644 tests/framework/web/UrlManagerTest.php create mode 100644 tests/framework/web/UrlRuleTest.php create mode 100644 tests/framework/web/UserTest.php create mode 100644 tests/framework/web/XmlResponseFormatterTest.php create mode 100644 tests/framework/widgets/ActiveFieldTest.php create mode 100644 tests/framework/widgets/ActiveFormTest.php create mode 100644 tests/framework/widgets/BreadcrumbsTest.php create mode 100644 tests/framework/widgets/LinkSorterTest.php create mode 100644 tests/framework/widgets/MenuTest.php create mode 100644 tests/framework/widgets/SpacelessTest.php create mode 100644 tests/runtime/.gitignore delete mode 100644 tests/unit/.gitignore delete mode 100644 tests/unit/TestCase.php delete mode 100644 tests/unit/assets/.gitignore delete mode 100644 tests/unit/bootstrap.php delete mode 100644 tests/unit/data/ar/ActiveRecord.php delete mode 100644 tests/unit/data/ar/Animal.php delete mode 100644 tests/unit/data/ar/Cat.php delete mode 100644 tests/unit/data/ar/Category.php delete mode 100644 tests/unit/data/ar/Customer.php delete mode 100644 tests/unit/data/ar/CustomerQuery.php delete mode 100644 tests/unit/data/ar/Dog.php delete mode 100644 tests/unit/data/ar/Item.php delete mode 100644 tests/unit/data/ar/NullValues.php delete mode 100644 tests/unit/data/ar/Order.php delete mode 100644 tests/unit/data/ar/OrderItem.php delete mode 100644 tests/unit/data/ar/OrderItemWithNullFK.php delete mode 100644 tests/unit/data/ar/OrderWithNullFK.php delete mode 100644 tests/unit/data/ar/Profile.php delete mode 100644 tests/unit/data/ar/Type.php delete mode 100644 tests/unit/data/base/InvalidRulesModel.php delete mode 100644 tests/unit/data/base/Singer.php delete mode 100644 tests/unit/data/base/Speaker.php delete mode 100644 tests/unit/data/config.php delete mode 100644 tests/unit/data/console/controllers/fixtures/FirstFixture.php delete mode 100644 tests/unit/data/console/controllers/fixtures/FixtureStorage.php delete mode 100644 tests/unit/data/console/controllers/fixtures/GlobalFixture.php delete mode 100644 tests/unit/data/console/controllers/fixtures/SecondFixture.php delete mode 100644 tests/unit/data/cubrid.sql delete mode 100644 tests/unit/data/i18n/messages/de-DE/test.php delete mode 100644 tests/unit/data/i18n/messages/de/test.php delete mode 100644 tests/unit/data/i18n/messages/en-US/test.php delete mode 100644 tests/unit/data/i18n/messages/ru/test.php delete mode 100644 tests/unit/data/i18n/test.mo delete mode 100644 tests/unit/data/i18n/test.po delete mode 100644 tests/unit/data/mssql.sql delete mode 100644 tests/unit/data/mysql.sql delete mode 100644 tests/unit/data/oci.sql delete mode 100644 tests/unit/data/postgres.sql delete mode 100644 tests/unit/data/sqlite.sql delete mode 100644 tests/unit/data/travis/README.md delete mode 100755 tests/unit/data/travis/apc-setup.sh delete mode 100755 tests/unit/data/travis/cubrid-setup.sh delete mode 100644 tests/unit/data/travis/cubrid-solo.rb delete mode 100755 tests/unit/data/travis/memcache-setup.sh delete mode 100644 tests/unit/data/validators/TestValidator.php delete mode 100644 tests/unit/data/validators/models/FakedValidationModel.php delete mode 100644 tests/unit/data/validators/models/ValidatorTestMainModel.php delete mode 100644 tests/unit/data/validators/models/ValidatorTestRefModel.php delete mode 100644 tests/unit/data/views/layout.php delete mode 100644 tests/unit/data/views/rawlayout.php delete mode 100644 tests/unit/data/views/simple.php delete mode 100644 tests/unit/data/web/assets/.gitignore delete mode 100644 tests/unit/data/web/data.txt delete mode 100644 tests/unit/framework/BaseYiiTest.php delete mode 100644 tests/unit/framework/ar/ActiveRecordTestTrait.php delete mode 100644 tests/unit/framework/base/ActionFilterTest.php delete mode 100644 tests/unit/framework/base/BehaviorTest.php delete mode 100644 tests/unit/framework/base/ComponentTest.php delete mode 100644 tests/unit/framework/base/DynamicModelTest.php delete mode 100644 tests/unit/framework/base/EventTest.php delete mode 100644 tests/unit/framework/base/ExposedSecurity.php delete mode 100644 tests/unit/framework/base/ModelTest.php delete mode 100644 tests/unit/framework/base/ObjectTest.php delete mode 100644 tests/unit/framework/base/SecurityTest.php delete mode 100644 tests/unit/framework/behaviors/SluggableBehaviorTest.php delete mode 100644 tests/unit/framework/behaviors/TimestampBehaviorTest.php delete mode 100644 tests/unit/framework/caching/ApcCacheTest.php delete mode 100644 tests/unit/framework/caching/ArrayCacheTest.php delete mode 100644 tests/unit/framework/caching/CacheTestCase.php delete mode 100644 tests/unit/framework/caching/DbCacheTest.php delete mode 100644 tests/unit/framework/caching/FileCacheTest.php delete mode 100644 tests/unit/framework/caching/MemCacheTest.php delete mode 100644 tests/unit/framework/caching/MemCachedTest.php delete mode 100644 tests/unit/framework/caching/TagDependencyTest.php delete mode 100644 tests/unit/framework/caching/WinCacheTest.php delete mode 100644 tests/unit/framework/caching/XCacheTest.php delete mode 100644 tests/unit/framework/caching/ZendDataCacheTest.php delete mode 100644 tests/unit/framework/console/controllers/AssetControllerTest.php delete mode 100644 tests/unit/framework/console/controllers/BaseMessageControllerTest.php delete mode 100644 tests/unit/framework/console/controllers/CacheControllerTest.php delete mode 100644 tests/unit/framework/console/controllers/EchoMigrateController.php delete mode 100644 tests/unit/framework/console/controllers/FixtureControllerTest.php delete mode 100644 tests/unit/framework/console/controllers/MigrateControllerTest.php delete mode 100644 tests/unit/framework/console/controllers/MigrateControllerTestTrait.php delete mode 100644 tests/unit/framework/console/controllers/PHPMessageControllerTest.php delete mode 100644 tests/unit/framework/console/controllers/POMessageControllerTest.php delete mode 100644 tests/unit/framework/console/controllers/SilencedCacheController.php delete mode 100644 tests/unit/framework/console/controllers/StdOutBufferControllerTrait.php delete mode 100644 tests/unit/framework/data/ActiveDataProviderTest.php delete mode 100644 tests/unit/framework/data/ArrayDataProviderTest.php delete mode 100644 tests/unit/framework/data/SortTest.php delete mode 100644 tests/unit/framework/db/ActiveRecordTest.php delete mode 100644 tests/unit/framework/db/BatchQueryResultTest.php delete mode 100644 tests/unit/framework/db/CommandTest.php delete mode 100644 tests/unit/framework/db/ConnectionTest.php delete mode 100644 tests/unit/framework/db/DatabaseTestCase.php delete mode 100644 tests/unit/framework/db/QueryBuilderTest.php delete mode 100644 tests/unit/framework/db/QueryTest.php delete mode 100644 tests/unit/framework/db/SchemaTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridActiveRecordTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridCommandTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridConnectionTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridQueryTest.php delete mode 100644 tests/unit/framework/db/cubrid/CubridSchemaTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlActiveDataProviderTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlActiveRecordTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlCommandTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlConnectionTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlQueryBuilderTest.php delete mode 100644 tests/unit/framework/db/mssql/MssqlQueryTest.php delete mode 100644 tests/unit/framework/db/oci/OracleActiveDataProviderTest.php delete mode 100644 tests/unit/framework/db/oci/OracleActiveRecordTest.php delete mode 100644 tests/unit/framework/db/oci/OracleCommandTest.php delete mode 100644 tests/unit/framework/db/oci/OracleQueryTest.php delete mode 100644 tests/unit/framework/db/oci/OracleSchemaTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLActiveDataProviderTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLCommandTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLQueryTest.php delete mode 100644 tests/unit/framework/db/pgsql/PostgreSQLSchemaTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteActiveDataProviderTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteCommandTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteConnectionTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteQueryTest.php delete mode 100644 tests/unit/framework/db/sqlite/SqliteSchemaTest.php delete mode 100644 tests/unit/framework/di/ContainerTest.php delete mode 100644 tests/unit/framework/di/InstanceTest.php delete mode 100644 tests/unit/framework/di/ServiceLocatorTest.php delete mode 100644 tests/unit/framework/di/stubs/Bar.php delete mode 100644 tests/unit/framework/di/stubs/Foo.php delete mode 100644 tests/unit/framework/di/stubs/Qux.php delete mode 100644 tests/unit/framework/di/stubs/QuxInterface.php delete mode 100644 tests/unit/framework/filters/CompositeAuthTest.php delete mode 100644 tests/unit/framework/filters/HttpCacheTest.php delete mode 100644 tests/unit/framework/helpers/ArrayHelperTest.php delete mode 100644 tests/unit/framework/helpers/ConsoleTest.php delete mode 100644 tests/unit/framework/helpers/FallbackInflector.php delete mode 100644 tests/unit/framework/helpers/FileHelperTest.php delete mode 100644 tests/unit/framework/helpers/FormatConverterTest.php delete mode 100644 tests/unit/framework/helpers/HtmlTest.php delete mode 100644 tests/unit/framework/helpers/InflectorTest.php delete mode 100644 tests/unit/framework/helpers/JsonTest.php delete mode 100644 tests/unit/framework/helpers/StringHelperTest.php delete mode 100644 tests/unit/framework/helpers/UrlTest.php delete mode 100644 tests/unit/framework/helpers/VarDumperTest.php delete mode 100644 tests/unit/framework/i18n/FallbackMessageFormatterTest.php delete mode 100644 tests/unit/framework/i18n/FormatterDateTest.php delete mode 100644 tests/unit/framework/i18n/FormatterNumberTest.php delete mode 100644 tests/unit/framework/i18n/FormatterTest.php delete mode 100644 tests/unit/framework/i18n/GettextMessageSourceTest.php delete mode 100644 tests/unit/framework/i18n/GettextMoFileTest.php delete mode 100644 tests/unit/framework/i18n/GettextPoFileTest.php delete mode 100644 tests/unit/framework/i18n/I18NTest.php delete mode 100644 tests/unit/framework/i18n/IntlTestHelper.php delete mode 100644 tests/unit/framework/i18n/MessageFormatterTest.php delete mode 100644 tests/unit/framework/log/DbTargetTest.php delete mode 100644 tests/unit/framework/log/FileTargetTest.php delete mode 100644 tests/unit/framework/log/LoggerTest.php delete mode 100644 tests/unit/framework/log/MySQLTargetTest.php delete mode 100644 tests/unit/framework/log/PgSQLTargetTest.php delete mode 100644 tests/unit/framework/log/SqliteTargetTest.php delete mode 100644 tests/unit/framework/log/TargetTest.php delete mode 100644 tests/unit/framework/mail/BaseMailerTest.php delete mode 100644 tests/unit/framework/mail/BaseMessageTest.php delete mode 100644 tests/unit/framework/rbac/AuthorRule.php delete mode 100644 tests/unit/framework/rbac/DbManagerTestCase.php delete mode 100644 tests/unit/framework/rbac/ExposedPhpManager.php delete mode 100644 tests/unit/framework/rbac/ManagerTestCase.php delete mode 100644 tests/unit/framework/rbac/MySQLManagerCacheTest.php delete mode 100644 tests/unit/framework/rbac/MySQLManagerTest.php delete mode 100644 tests/unit/framework/rbac/PgSQLManagerTest.php delete mode 100644 tests/unit/framework/rbac/PhpManagerTest.php delete mode 100644 tests/unit/framework/rbac/SqliteManagerTest.php delete mode 100644 tests/unit/framework/requirements/YiiRequirementCheckerTest.php delete mode 100644 tests/unit/framework/test/ActiveFixtureTest.php delete mode 100644 tests/unit/framework/test/ArrayFixtureTest.php delete mode 100644 tests/unit/framework/test/FixtureTest.php delete mode 100644 tests/unit/framework/test/data/array_fixture.php delete mode 100644 tests/unit/framework/test/data/customer.php delete mode 100644 tests/unit/framework/validators/BooleanValidatorTest.php delete mode 100644 tests/unit/framework/validators/CompareValidatorTest.php delete mode 100644 tests/unit/framework/validators/DateValidatorTest.php delete mode 100644 tests/unit/framework/validators/DefaultValueValidatorTest.php delete mode 100644 tests/unit/framework/validators/EachValidatorTest.php delete mode 100644 tests/unit/framework/validators/EmailValidatorTest.php delete mode 100644 tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php delete mode 100644 tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorSQliteTest.php delete mode 100644 tests/unit/framework/validators/ExistValidatorTest.php delete mode 100644 tests/unit/framework/validators/FileValidatorTest.php delete mode 100644 tests/unit/framework/validators/FilterValidatorTest.php delete mode 100644 tests/unit/framework/validators/NumberValidatorTest.php delete mode 100644 tests/unit/framework/validators/RangeValidatorTest.php delete mode 100644 tests/unit/framework/validators/RegularExpressionValidatorTest.php delete mode 100644 tests/unit/framework/validators/RequiredValidatorTest.php delete mode 100644 tests/unit/framework/validators/StringValidatorTest.php delete mode 100644 tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php delete mode 100644 tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorSQliteTest.php delete mode 100644 tests/unit/framework/validators/UniqueValidatorTest.php delete mode 100644 tests/unit/framework/validators/UrlValidatorTest.php delete mode 100644 tests/unit/framework/validators/ValidatorTest.php delete mode 100644 tests/unit/framework/web/AssetBundleTest.php delete mode 100644 tests/unit/framework/web/AssetConverterTest.php delete mode 100644 tests/unit/framework/web/CacheSessionTest.php delete mode 100644 tests/unit/framework/web/FormatterTest.php delete mode 100644 tests/unit/framework/web/GroupUrlRuleTest.php delete mode 100644 tests/unit/framework/web/JsonResponseFormatterTest.php delete mode 100644 tests/unit/framework/web/Post.php delete mode 100644 tests/unit/framework/web/RequestTest.php delete mode 100644 tests/unit/framework/web/ResponseTest.php delete mode 100644 tests/unit/framework/web/UrlManagerTest.php delete mode 100644 tests/unit/framework/web/UrlRuleTest.php delete mode 100644 tests/unit/framework/web/UserTest.php delete mode 100644 tests/unit/framework/web/XmlResponseFormatterTest.php delete mode 100644 tests/unit/framework/widgets/ActiveFieldTest.php delete mode 100644 tests/unit/framework/widgets/ActiveFormTest.php delete mode 100644 tests/unit/framework/widgets/BreadcrumbsTest.php delete mode 100644 tests/unit/framework/widgets/LinkSorterTest.php delete mode 100644 tests/unit/framework/widgets/MenuTest.php delete mode 100644 tests/unit/framework/widgets/SpacelessTest.php delete mode 100644 tests/unit/runtime/.gitignore delete mode 100644 tests/unit/runtime/coveralls/.gitkeep delete mode 100644 tests/web/app/assets/.gitignore delete mode 100644 tests/web/app/index.php delete mode 100644 tests/web/app/protected/config/main.php delete mode 100644 tests/web/app/protected/controllers/SiteController.php delete mode 100644 tests/web/app/protected/runtime/.gitignore delete mode 100644 tests/web/app/protected/views/site/index.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 803e852..6debe5e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,5 +1,5 @@ - - ./tests/unit + ./tests diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..f5f5f83 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,2 @@ +/runtime/cache/* +/data/config.local.php \ No newline at end of file diff --git a/tests/README.md b/tests/README.md index 028f74a..d55d549 100644 --- a/tests/README.md +++ b/tests/README.md @@ -4,12 +4,10 @@ Yii 2.0 Unit tests DIRECTORY STRUCTURE ------------------- - unit/ Unit tests to run with PHPUnit - data/ models, config and other test data - config.php this file contains configuration for database and caching backends - framework/ the framework unit tests - runtime/ the application runtime dir for the yii test app - web/ webapp for functional testing + data/ models, config and other test data + config.php this file contains configuration for database and caching backends + framework/ the framework unit tests + runtime/ the application runtime dir for the yii test app HOW TO RUN THE TESTS @@ -19,18 +17,24 @@ Make sure you have PHPUnit installed and that you installed all composer depende Run PHPUnit in the yii repo base directory. -```php +``` phpunit ``` You can run tests for specific groups only: -```php +``` phpunit --group=mysql,base,i18n ``` You can get a list of available groups via `phpunit --list-groups`. +A single test class could be run like the follwing: + +``` +phpunit tests/framework/base/ObjectTest.php +``` + TEST CONFIGURATION ------------------ diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..f4f8e2d --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,100 @@ +destroyApplication(); + } + + /** + * Returns a test configuration param from /data/config.php + * @param string $name params name + * @param mixed $default default value to use when param is not set. + * @return mixed the value of the configuration param + */ + public static function getParam($name, $default = null) + { + if (static::$params === null) { + static::$params = require(__DIR__ . '/data/config.php'); + } + + return isset(static::$params[$name]) ? static::$params[$name] : $default; + } + + /** + * Populates Yii::$app with a new application + * The application will be destroyed on tearDown() automatically. + * @param array $config The application configuration, if needed + * @param string $appClass name of the application class to create + */ + protected function mockApplication($config = [], $appClass = '\yii\console\Application') + { + new $appClass(ArrayHelper::merge([ + 'id' => 'testapp', + 'basePath' => __DIR__, + 'vendorPath' => $this->getVendorPath(), + ], $config)); + } + + protected function mockWebApplication($config = [], $appClass = '\yii\web\Application') + { + new $appClass(ArrayHelper::merge([ + 'id' => 'testapp', + 'basePath' => __DIR__, + 'vendorPath' => $this->getVendorPath(), + 'components' => [ + 'request' => [ + 'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq', + 'scriptFile' => __DIR__ .'/index.php', + 'scriptUrl' => '/index.php', + ], + ] + ], $config)); + } + + protected function getVendorPath() + { + $vendor = dirname(dirname(__DIR__)) . '/vendor'; + if (!is_dir($vendor)) { + $vendor = dirname(dirname(dirname(dirname(__DIR__)))); + } + return $vendor; + } + + /** + * Destroys application in Yii::$app by setting it to null. + */ + protected function destroyApplication() + { + \Yii::$app = null; + } + + /** + * Asserting two strings equality ignoring line endings + * + * @param string $expected + * @param string $actual + */ + public function assertEqualsWithoutLE($expected, $actual) + { + $expected = str_replace("\r\n", "\n", $expected); + $actual = str_replace("\r\n", "\n", $actual); + + $this->assertEquals($expected, $actual); + } +} diff --git a/tests/assets/.gitignore b/tests/assets/.gitignore new file mode 100644 index 0000000..5e31724 --- /dev/null +++ b/tests/assets/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!/coveralls/.gitkeep diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..1aeaedc --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,22 @@ + + * @since 2.0 + */ +class ActiveRecord extends \yii\db\ActiveRecord +{ + public static $db; + + public static function getDb() + { + return self::$db; + } +} diff --git a/tests/data/ar/Animal.php b/tests/data/ar/Animal.php new file mode 100644 index 0000000..129588f --- /dev/null +++ b/tests/data/ar/Animal.php @@ -0,0 +1,50 @@ + + * @property integer $id + * @property string $type + */ +class Animal extends ActiveRecord +{ + + public $does; + + public static function tableName() + { + return 'animal'; + } + + public function init() + { + parent::init(); + $this->type = get_called_class(); + } + + public function getDoes() + { + return $this->does; + } + + /** + * + * @param type $row + * @return \yiiunit\data\ar\Animal + */ + public static function instantiate($row) + { + $class = $row['type']; + return new $class; + } + +} diff --git a/tests/data/ar/Cat.php b/tests/data/ar/Cat.php new file mode 100644 index 0000000..831cb8d --- /dev/null +++ b/tests/data/ar/Cat.php @@ -0,0 +1,32 @@ + + * @since 2.0 + */ +class Cat extends Animal +{ + + /** + * + * @param self $record + * @param array $row + */ + public static function populateRecord($record, $row) + { + parent::populateRecord($record, $row); + + $record->does = 'meow'; + } + +} diff --git a/tests/data/ar/Category.php b/tests/data/ar/Category.php new file mode 100644 index 0000000..aa19326 --- /dev/null +++ b/tests/data/ar/Category.php @@ -0,0 +1,43 @@ +hasMany(Item::className(), ['category_id' => 'id']); + } + + public function getLimitedItems() + { + return $this->hasMany(Item::className(), ['category_id' => 'id']) + ->onCondition(['item.id' => [1, 2, 3]]); + } + + public function getOrderItems() + { + return $this->hasMany(OrderItem::className(), ['item_id' => 'id'])->via('items'); + } + + public function getOrders() + { + return $this->hasMany(Order::className(), ['id' => 'order_id'])->via('orderItems'); + } +} diff --git a/tests/data/ar/Customer.php b/tests/data/ar/Customer.php new file mode 100644 index 0000000..65125c3 --- /dev/null +++ b/tests/data/ar/Customer.php @@ -0,0 +1,87 @@ +hasOne(Profile::className(), ['id' => 'profile_id']); + } + + public function getOrders() + { + return $this->hasMany(Order::className(), ['customer_id' => 'id'])->orderBy('id'); + } + + public function getExpensiveOrders() + { + return $this->hasMany(Order::className(), ['customer_id' => 'id'])->andWhere('[[total]] > 50')->orderBy('id'); + } + + public function getExpensiveOrdersWithNullFK() + { + return $this->hasMany(OrderWithNullFK::className(), ['customer_id' => 'id'])->andWhere('[[total]] > 50')->orderBy('id'); + } + + public function getOrdersWithNullFK() + { + return $this->hasMany(OrderWithNullFK::className(), ['customer_id' => 'id'])->orderBy('id'); + } + + public function getOrders2() + { + return $this->hasMany(Order::className(), ['customer_id' => 'id'])->inverseOf('customer2')->orderBy('id'); + } + + // deeply nested table relation + public function getOrderItems() + { + /* @var $rel ActiveQuery */ + $rel = $this->hasMany(Item::className(), ['id' => 'item_id']); + + return $rel->viaTable('order_item', ['order_id' => 'id'], function ($q) { + /* @var $q ActiveQuery */ + $q->viaTable('order', ['customer_id' => 'id']); + })->orderBy('id'); + } + + public function afterSave($insert, $changedAttributes) + { + ActiveRecordTest::$afterSaveInsert = $insert; + ActiveRecordTest::$afterSaveNewRecord = $this->isNewRecord; + parent::afterSave($insert, $changedAttributes); + } + + /** + * @inheritdoc + * @return CustomerQuery + */ + public static function find() + { + return new CustomerQuery(get_called_class()); + } +} diff --git a/tests/data/ar/CustomerQuery.php b/tests/data/ar/CustomerQuery.php new file mode 100644 index 0000000..80b2b01 --- /dev/null +++ b/tests/data/ar/CustomerQuery.php @@ -0,0 +1,18 @@ +andWhere('[[status]]=1'); + + return $this; + } +} diff --git a/tests/data/ar/Dog.php b/tests/data/ar/Dog.php new file mode 100644 index 0000000..9422cc5 --- /dev/null +++ b/tests/data/ar/Dog.php @@ -0,0 +1,32 @@ + + * @since 2.0 + */ +class Dog extends Animal +{ + + /** + * + * @param self $record + * @param array $row + */ + public static function populateRecord($record, $row) + { + parent::populateRecord($record, $row); + + $record->does = 'bark'; + } + +} diff --git a/tests/data/ar/Item.php b/tests/data/ar/Item.php new file mode 100644 index 0000000..6567567 --- /dev/null +++ b/tests/data/ar/Item.php @@ -0,0 +1,23 @@ +hasOne(Category::className(), ['id' => 'category_id']); + } +} diff --git a/tests/data/ar/NullValues.php b/tests/data/ar/NullValues.php new file mode 100644 index 0000000..ad22899 --- /dev/null +++ b/tests/data/ar/NullValues.php @@ -0,0 +1,20 @@ +hasOne(Customer::className(), ['id' => 'customer_id']); + } + + public function getCustomer2() + { + return $this->hasOne(Customer::className(), ['id' => 'customer_id'])->inverseOf('orders2'); + } + + public function getOrderItems() + { + return $this->hasMany(OrderItem::className(), ['order_id' => 'id']); + } + + public function getOrderItemsWithNullFK() + { + return $this->hasMany(OrderItemWithNullFK::className(), ['order_id' => 'id']); + } + + public function getItems() + { + return $this->hasMany(Item::className(), ['id' => 'item_id']) + ->via('orderItems', function ($q) { + // additional query configuration + })->orderBy('item.id'); + } + + public function getItemsIndexed() + { + return $this->hasMany(Item::className(), ['id' => 'item_id']) + ->via('orderItems')->indexBy('id'); + } + + public function getItemsWithNullFK() + { + return $this->hasMany(Item::className(), ['id' => 'item_id']) + ->viaTable('order_item_with_null_fk', ['order_id' => 'id']); + } + + public function getItemsInOrder1() + { + return $this->hasMany(Item::className(), ['id' => 'item_id']) + ->via('orderItems', function ($q) { + $q->orderBy(['subtotal' => SORT_ASC]); + })->orderBy('name'); + } + + public function getItemsInOrder2() + { + return $this->hasMany(Item::className(), ['id' => 'item_id']) + ->via('orderItems', function ($q) { + $q->orderBy(['subtotal' => SORT_DESC]); + })->orderBy('name'); + } + + public function getBooks() + { + return $this->hasMany(Item::className(), ['id' => 'item_id']) + ->via('orderItems') + ->where(['category_id' => 1]); + } + + public function getBooksWithNullFK() + { + return $this->hasMany(Item::className(), ['id' => 'item_id']) + ->via('orderItemsWithNullFK') + ->where(['category_id' => 1]); + } + + public function getBooksViaTable() + { + return $this->hasMany(Item::className(), ['id' => 'item_id']) + ->viaTable('order_item', ['order_id' => 'id']) + ->where(['category_id' => 1]); + } + + public function getBooksWithNullFKViaTable() + { + return $this->hasMany(Item::className(), ['id' => 'item_id']) + ->viaTable('order_item_with_null_fk', ['order_id' => 'id']) + ->where(['category_id' => 1]); + } + + public function getBooks2() + { + return $this->hasMany(Item::className(), ['id' => 'item_id']) + ->onCondition(['category_id' => 1]) + ->viaTable('order_item', ['order_id' => 'id']); + } + + public function beforeSave($insert) + { + if (parent::beforeSave($insert)) { + $this->created_at = time(); + + return true; + } else { + return false; + } + } + + public function attributeLabels() + { + return [ + 'customer_id' => 'Customer', + 'total' => 'Invoice Total', + ]; + } +} diff --git a/tests/data/ar/OrderItem.php b/tests/data/ar/OrderItem.php new file mode 100644 index 0000000..4c45f88 --- /dev/null +++ b/tests/data/ar/OrderItem.php @@ -0,0 +1,29 @@ +hasOne(Order::className(), ['id' => 'order_id']); + } + + public function getItem() + { + return $this->hasOne(Item::className(), ['id' => 'item_id']); + } +} diff --git a/tests/data/ar/OrderItemWithNullFK.php b/tests/data/ar/OrderItemWithNullFK.php new file mode 100644 index 0000000..63e6551 --- /dev/null +++ b/tests/data/ar/OrderItemWithNullFK.php @@ -0,0 +1,20 @@ + + */ + +namespace yiiunit\data\ar; + +/** + * Class Profile + * + * @property integer $id + * @property string $description + * + */ +class Profile extends ActiveRecord +{ + public static function tableName() + { + return 'profile'; + } +} diff --git a/tests/data/ar/Type.php b/tests/data/ar/Type.php new file mode 100644 index 0000000..7922ba5 --- /dev/null +++ b/tests/data/ar/Type.php @@ -0,0 +1,32 @@ + 'Lennon'], + [['lastName'], 'required'], + [['underscore_style'], 'yii\captcha\CaptchaValidator'], + [['test'], 'required', 'when' => function($model) { return $model->firstName === 'cebe'; }], + ]; + } +} diff --git a/tests/data/base/Speaker.php b/tests/data/base/Speaker.php new file mode 100644 index 0000000..5e80111 --- /dev/null +++ b/tests/data/base/Speaker.php @@ -0,0 +1,45 @@ + 'This is the custom label', + ]; + } + + public function rules() + { + return []; + } + + public function scenarios() + { + return [ + 'test' => ['firstName', 'lastName', '!underscore_style'], + ]; + } +} diff --git a/tests/data/config.php b/tests/data/config.php new file mode 100644 index 0000000..5003da5 --- /dev/null +++ b/tests/data/config.php @@ -0,0 +1,53 @@ + [ + 'cubrid' => [ + 'dsn' => 'cubrid:dbname=demodb;host=localhost;port=33000', + 'username' => 'dba', + 'password' => '', + 'fixture' => __DIR__ . '/cubrid.sql', + ], + 'mysql' => [ + 'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest', + 'username' => 'travis', + 'password' => '', + 'fixture' => __DIR__ . '/mysql.sql', + ], + 'sqlite' => [ + 'dsn' => 'sqlite::memory:', + 'fixture' => __DIR__ . '/sqlite.sql', + ], + 'sqlsrv' => [ + 'dsn' => 'sqlsrv:Server=localhost;Database=test', + 'username' => '', + 'password' => '', + 'fixture' => __DIR__ . '/mssql.sql', + ], + 'pgsql' => [ + 'dsn' => 'pgsql:host=localhost;dbname=yiitest;port=5432;', + 'username' => 'postgres', + 'password' => 'postgres', + 'fixture' => __DIR__ . '/postgres.sql', + ], + ], +]; + +if (is_file(__DIR__ . '/config.local.php')) { + include(__DIR__ . '/config.local.php'); +} + +return $config; \ No newline at end of file diff --git a/tests/data/console/controllers/fixtures/FirstFixture.php b/tests/data/console/controllers/fixtures/FirstFixture.php new file mode 100644 index 0000000..d97b542 --- /dev/null +++ b/tests/data/console/controllers/fixtures/FirstFixture.php @@ -0,0 +1,19 @@ + 'Der Hund rennt schnell.', + 'His speed is about {n} km/h.' => 'Seine Geschwindigkeit beträgt {n} km/h.', + 'His name is {name} and his speed is about {n, number} km/h.' => 'Er heißt {name} und ist {n, number} km/h schnell.', +]; diff --git a/tests/data/i18n/messages/de/test.php b/tests/data/i18n/messages/de/test.php new file mode 100644 index 0000000..6d7b903 --- /dev/null +++ b/tests/data/i18n/messages/de/test.php @@ -0,0 +1,7 @@ + 'Hallo Welt!', +]; diff --git a/tests/data/i18n/messages/en-US/test.php b/tests/data/i18n/messages/en-US/test.php new file mode 100644 index 0000000..d14d9ca --- /dev/null +++ b/tests/data/i18n/messages/en-US/test.php @@ -0,0 +1,7 @@ + 'Der Hund rennt schell.', +]; diff --git a/tests/data/i18n/messages/ru/test.php b/tests/data/i18n/messages/ru/test.php new file mode 100644 index 0000000..fd6c6c7 --- /dev/null +++ b/tests/data/i18n/messages/ru/test.php @@ -0,0 +1,8 @@ + 'Собака бегает быстро.', + 'There {n, plural, =0{no cats} =1{one cat} other{are # cats}} on lying on the sofa!' => 'На диване {n, plural, =0{нет кошек} =1{лежит одна кошка} one{лежит # кошка} few{лежит # кошки} many{лежит # кошек} other{лежит # кошки}}!', +]; diff --git a/tests/data/i18n/test.mo b/tests/data/i18n/test.mo new file mode 100644 index 0000000000000000000000000000000000000000..d5f94f14a3b52a4ef0b2ddaeeb6bcff474f67594 GIT binary patch literal 1426 zcma)5!EO{s5FL^wht2_sD?t=@X23>B$b=+_kjTQoDlCWtIkab+bw@KjOHYqUq#SIb zzySeL6fPVH+{n#YJg^vhIB-Vl`GNdF{vog0Ya0m;j8t1y-PQG8z3%;YZ|6aT?=#pJ zusPW0uwP;PJ%zo6{SCVdyRj>Z_QCJ|B#QRKADsBF;r~PaBm5iGoc%P42>G7fQFH+Q z2t4QAiN6kyvZwB~v*%^;ULOVT3$ zO3X=|jnA00z^fU|&~d0PuEgI%WV|b;)GZW0gQ?_La!f@2k$>gK?JZxoH~q*r?UJwk zh9CQyeB)OUHhv9@E7(SykpC-`thUQoS;3K4;lM_F$G@bIthLKHzvi15LG9O3wSn4k zdmA9j*cfvq7Gc2lFQ~oGeeeqs=zCxI*W9E19pGHC;h&*k93bCqvrc|Qs042Sp=pDJ z8IOE@h&Up^*XYA&K=SKc-hjy_>&;Pd@bv^~l~It@?Gik;G4LNDza1plJO*_H4tz+R z$AEglq=CUqY6{|UPoAam&x2e+-w`zX2bEBlCkM6m9`Cc%n{s{(`6TiW!@V^)HxV}s z03a4-6$MYA>k{HMzY=5#sw@#E82J_K|A}#bgUF44DFk0#xUm{Hk6Xq+2Ay$r?M?hy NwnF~HY{f^T{{g1ziG%\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.5.5\n" + +msgctxt "context1" +msgid "" +"Aliquam tempus elit vel purus molestie placerat. In sollicitudin tincidunt\n" +"aliquet. Integer tincidunt gravida tempor. In convallis blandit dui vel " +"malesuada.\n" +"Nunc vel sapien nunc, a pretium nulla." +msgstr "" +"Олицетворение однократно. Представленный лексико-семантический анализ " +"является\n" +"психолингвистическим в своей основе, но механизм сочленений полидисперсен. " +"Впечатление\n" +"однократно. Различное расположение выбирает сюжетный механизм сочленений." + +msgctxt "context1" +msgid "String number two." +msgstr "Строка номер два." + +msgctxt "context2" +msgid "" +"The other\n" +"\n" +"context.\n" +msgstr "" +"Другой\n" +"\n" +"контекст.\n" + +msgctxt "context1" +msgid "" +"Missing\n" +"\r\t\"translation." +msgstr "" + +msgctxt "context1" +msgid "" +"Nunc vel sapien nunc, a pretium nulla.\n" +"Pellentesque habitant morbi tristique senectus et netus et malesuada fames " +"ac turpis egestas." +msgstr "Короткий перевод." + +msgid "contextless" +msgstr "" + +msgctxt "context2" +msgid "" +"test1\\ntest2\n" +"\\\n" +"test3" +msgstr "" +"тест1\\nтест2\n" +"\\\n" +"тест3" diff --git a/tests/data/mssql.sql b/tests/data/mssql.sql new file mode 100644 index 0000000..544f480 --- /dev/null +++ b/tests/data/mssql.sql @@ -0,0 +1,159 @@ +IF OBJECT_ID('[dbo].[order_item]', 'U') IS NOT NULL DROP TABLE [dbo].[order_item]; +IF OBJECT_ID('[dbo].[order_item_with_null_fk]', 'U') IS NOT NULL DROP TABLE [dbo].[order_item_with_null_fk]; +IF OBJECT_ID('[dbo].[item]', 'U') IS NOT NULL DROP TABLE [dbo].[item]; +IF OBJECT_ID('[dbo].[order]', 'U') IS NOT NULL DROP TABLE [dbo].[order]; +IF OBJECT_ID('[dbo].[order_with_null_fk]', 'U') IS NOT NULL DROP TABLE [dbo].[order_with_null_fk]; +IF OBJECT_ID('[dbo].[category]', 'U') IS NOT NULL DROP TABLE [dbo].[category]; +IF OBJECT_ID('[dbo].[customer]', 'U') IS NOT NULL DROP TABLE [dbo].[customer]; +IF OBJECT_ID('[dbo].[profile]', 'U') IS NOT NULL DROP TABLE [dbo].[profile]; +IF OBJECT_ID('[dbo].[type]', 'U') IS NOT NULL DROP TABLE [dbo].[type]; +IF OBJECT_ID('[dbo].[null_values]', 'U') IS NOT NULL DROP TABLE [dbo].[null_values]; +IF OBJECT_ID('[dbo].[animal]', 'U') IS NOT NULL DROP TABLE [dbo].[animal]; +IF OBJECT_ID('[dbo].[animal_view]', 'V') IS NOT NULL DROP VIEW [dbo].[animal_view]; + +CREATE TABLE [dbo].[profile] ( + [id] [int] IDENTITY(1,1) NOT NULL, + [description] [varchar](128) NOT NULL, + CONSTRAINT [PK_customer] PRIMARY KEY CLUSTERED ( + [id] ASC + ) ON [PRIMARY] +); + +CREATE TABLE [dbo].[customer] ( + [id] [int] IDENTITY(1,1) NOT NULL, + [email] [varchar](128) NOT NULL, + [name] [varchar](128), + [address] [text], + [status] [int] DEFAULT 0, + [profile_id] [int], + CONSTRAINT [PK_customer] PRIMARY KEY CLUSTERED ( + [id] ASC + ) ON [PRIMARY] +); + +CREATE TABLE [dbo].[category] ( + [id] [int] IDENTITY(1,1) NOT NULL, + [name] [varchar](128) NOT NULL, + CONSTRAINT [PK_category] PRIMARY KEY CLUSTERED ( + [id] ASC + ) ON [PRIMARY] +); + +CREATE TABLE [dbo].[item] ( + [id] [int] IDENTITY(1,1) NOT NULL, + [name] [varchar](128) NOT NULL, + [category_id] [int] NOT NULL, + CONSTRAINT [PK_item] PRIMARY KEY CLUSTERED ( + [id] ASC + ) ON [PRIMARY] +); + +CREATE TABLE [dbo].[order] ( + [id] [int] IDENTITY(1,1) NOT NULL, + [customer_id] [int] NOT NULL, + [created_at] [int] NOT NULL, + [total] [decimal](10,0) NOT NULL, + CONSTRAINT [PK_order] PRIMARY KEY CLUSTERED ( + [id] ASC + ) ON [PRIMARY] +); + +CREATE TABLE [dbo].[order_with_null_fk] ( + [id] [int] IDENTITY(1,1) NOT NULL, + [customer_id] [int] , + [created_at] [int] NOT NULL, + [total] [decimal](10,0) NOT NULL +); + +CREATE TABLE [dbo].[order_item] ( + [order_id] [int] NOT NULL, + [item_id] [int] NOT NULL, + [quantity] [int] NOT NULL, + [subtotal] [decimal](10,0) NOT NULL, + CONSTRAINT [PK_order_item] PRIMARY KEY CLUSTERED ( + [order_id] ASC, + [item_id] ASC + ) ON [PRIMARY] + +);CREATE TABLE [dbo].[order_item_with_null_fk] ( + [order_id] [int], + [item_id] [int], + [quantity] [int] NOT NULL, + [subtotal] [decimal](10,0) NOT NULL +); + +CREATE TABLE [dbo].[null_values] ( + id [int] UNSIGNED NOT NULL, + var1 [int] UNSIGNED NULL, + var2 [int] NULL, + var3 [int] DEFAULT NULL, + stringcol [varchar](32) DEFAULT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE [dbo].[type] ( + [int_col] [int] NOT NULL, + [int_col2] [int] DEFAULT '1', + [smallint_col] [smallint] DEFAULT '1', + [char_col] [char](100) NOT NULL, + [char_col2] [varchar](100) DEFAULT 'something', + [char_col3] [text], + [float_col] [decimal](4,3) NOT NULL, + [float_col2] [float] DEFAULT '1.23', + [blob_col] [varbinary](MAX), + [numeric_col] [decimal](5,2) DEFAULT '33.22', + [time] [datetime] NOT NULL DEFAULT '2002-01-01 00:00:00', + [bool_col] [tinyint] NOT NULL, + [bool_col2] [tinyint] DEFAULT '1' +); + +CREATE TABLE [dbo].[animal] ( + [id] [int] IDENTITY(1,1) NOT NULL, + [type] [varchar](255) NOT NULL, + CONSTRAINT [PK_animal] PRIMARY KEY CLUSTERED ( + [id] ASC + ) ON [PRIMARY] +); + +CREATE VIEW [dbo].[animal_view] AS SELECT * FROM [dbo].[animal]; + +INSERT INTO [dbo].[animal] (type) VALUES ('yiiunit\data\ar\Cat'); +INSERT INTO [dbo].[animal] (type) VALUES ('yiiunit\data\ar\Dog'); + +INSERT INTO [dbo].[profile] ([description]) VALUES ('profile customer 1'); +INSERT INTO [dbo].[profile] ([description]) VALUES ('profile customer 3'); + +INSERT INTO [dbo].[customer] ([email], [name], [address], [status], [profile_id]) VALUES ('user1@example.com', 'user1', 'address1', 1, 1); +INSERT INTO [dbo].[customer] ([email], [name], [address], [status]) VALUES ('user2@example.com', 'user2', 'address2', 1); +INSERT INTO [dbo].[customer] ([email], [name], [address], [status], [profile_id]) VALUES ('user3@example.com', 'user3', 'address3', 2, 2); + +INSERT INTO [dbo].[category] ([name]) VALUES ('Books'); +INSERT INTO [dbo].[category] ([name]) VALUES ('Movies'); + +INSERT INTO [dbo].[item] ([name], [category_id]) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); +INSERT INTO [dbo].[item] ([name], [category_id]) VALUES ('Yii 1.1 Application Development Cookbook', 1); +INSERT INTO [dbo].[item] ([name], [category_id]) VALUES ('Ice Age', 2); +INSERT INTO [dbo].[item] ([name], [category_id]) VALUES ('Toy Story', 2); +INSERT INTO [dbo].[item] ([name], [category_id]) VALUES ('Cars', 2); + +INSERT INTO [dbo].[order] ([customer_id], [created_at], [total]) VALUES (1, 1325282384, 110.0); +INSERT INTO [dbo].[order] ([customer_id], [created_at], [total]) VALUES (2, 1325334482, 33.0); +INSERT INTO [dbo].[order] ([customer_id], [created_at], [total]) VALUES (2, 1325502201, 40.0); + +INSERT INTO [dbo].[order_with_null_fk] ([customer_id], [created_at], [total]) VALUES (1, 1325282384, 110.0); +INSERT INTO [dbo].[order_with_null_fk] ([customer_id], [created_at], [total]) VALUES (2, 1325334482, 33.0); +INSERT INTO [dbo].[order_with_null_fk] ([customer_id], [created_at], [total]) VALUES (2, 1325502201, 40.0); + +INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 1, 1, 30.0); +INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 2, 2, 40.0); +INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 4, 1, 10.0); +INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 5, 1, 15.0); +INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 3, 1, 8.0); +INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (3, 2, 1, 40.0); + +INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 1, 1, 30.0); +INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 2, 2, 40.0); +INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 4, 1, 10.0); +INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 5, 1, 15.0); +INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 3, 1, 8.0); +INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (3, 2, 1, 40.0); diff --git a/tests/data/mysql.sql b/tests/data/mysql.sql new file mode 100644 index 0000000..27bb20a --- /dev/null +++ b/tests/data/mysql.sql @@ -0,0 +1,210 @@ +/** + * This is the database schema for testing MySQL support of Yii DAO and Active Record. + * The database setup in config.php is required to perform then relevant tests: + */ + +DROP TABLE IF EXISTS `composite_fk` CASCADE; +DROP TABLE IF EXISTS `order_item` CASCADE; +DROP TABLE IF EXISTS `order_item_with_null_fk` CASCADE; +DROP TABLE IF EXISTS `item` CASCADE; +DROP TABLE IF EXISTS `order` CASCADE; +DROP TABLE IF EXISTS `order_with_null_fk` CASCADE; +DROP TABLE IF EXISTS `category` CASCADE; +DROP TABLE IF EXISTS `customer` CASCADE; +DROP TABLE IF EXISTS `profile` CASCADE; +DROP TABLE IF EXISTS `null_values` CASCADE; +DROP TABLE IF EXISTS `type` CASCADE; +DROP TABLE IF EXISTS `constraints` CASCADE; +DROP TABLE IF EXISTS `animal` CASCADE; +DROP VIEW IF EXISTS `animal_view`; + +CREATE TABLE `constraints` +( + `id` integer not null, + `field1` varchar(255) +); + + +CREATE TABLE `profile` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `description` varchar(128) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `customer` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `email` varchar(128) NOT NULL, + `name` varchar(128), + `address` text, + `status` int (11) DEFAULT 0, + `profile_id` int(11), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `category` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `item` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(128) NOT NULL, + `category_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `FK_item_category_id` (`category_id`), + CONSTRAINT `FK_item_category_id` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `order` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `customer_id` int(11) NOT NULL, + `created_at` int(11) NOT NULL, + `total` decimal(10,0) NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `FK_order_customer_id` FOREIGN KEY (`customer_id`) REFERENCES `customer` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `order_with_null_fk` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `customer_id` int(11), + `created_at` int(11) NOT NULL, + `total` decimal(10,0) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `order_item` ( + `order_id` int(11) NOT NULL, + `item_id` int(11) NOT NULL, + `quantity` int(11) NOT NULL, + `subtotal` decimal(10,0) NOT NULL, + PRIMARY KEY (`order_id`,`item_id`), + KEY `FK_order_item_item_id` (`item_id`), + CONSTRAINT `FK_order_item_order_id` FOREIGN KEY (`order_id`) REFERENCES `order` (`id`) ON DELETE CASCADE, + CONSTRAINT `FK_order_item_item_id` FOREIGN KEY (`item_id`) REFERENCES `item` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +CREATE TABLE `order_item_with_null_fk` ( + `order_id` int(11), + `item_id` int(11), + `quantity` int(11) NOT NULL, + `subtotal` decimal(10,0) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `composite_fk` ( + `id` int(11) NOT NULL, + `order_id` int(11) NOT NULL, + `item_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `order_item` (`order_id`,`item_id`) ON DELETE CASCADE +); + +CREATE TABLE null_values ( + `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, + `var1` INT UNSIGNED NULL, + `var2` INT NULL, + `var3` INT DEFAULT NULL, + `stringcol` VARCHAR (32) DEFAULT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE `type` ( + `int_col` integer NOT NULL, + `int_col2` integer DEFAULT '1', + `smallint_col` smallint(1) DEFAULT '1', + `char_col` char(100) NOT NULL, + `char_col2` varchar(100) DEFAULT 'something', + `char_col3` text, + `enum_col` enum('a', 'B'), + `float_col` double(4,3) NOT NULL, + `float_col2` double DEFAULT '1.23', + `blob_col` blob, + `numeric_col` decimal(5,2) DEFAULT '33.22', + `time` timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', + `bool_col` tinyint(1) NOT NULL, + `bool_col2` tinyint(1) DEFAULT '1', + `ts_default` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `bit_col` BIT(8) NOT NULL DEFAULT b'10000010' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `animal` ( + `id` INT NOT NULL AUTO_INCREMENT, + `type` VARCHAR(255) NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE VIEW `animal_view` AS SELECT * FROM `animal`; + +INSERT INTO `animal` (`type`) VALUES ('yiiunit\data\ar\Cat'); +INSERT INTO `animal` (`type`) VALUES ('yiiunit\data\ar\Dog'); + +INSERT INTO `profile` (description) VALUES ('profile customer 1'); +INSERT INTO `profile` (description) VALUES ('profile customer 3'); + +INSERT INTO `customer` (email, name, address, status, profile_id) VALUES ('user1@example.com', 'user1', 'address1', 1, 1); +INSERT INTO `customer` (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); +INSERT INTO `customer` (email, name, address, status, profile_id) VALUES ('user3@example.com', 'user3', 'address3', 2, 2); + +INSERT INTO `category` (name) VALUES ('Books'); +INSERT INTO `category` (name) VALUES ('Movies'); + +INSERT INTO `item` (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); +INSERT INTO `item` (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); +INSERT INTO `item` (name, category_id) VALUES ('Ice Age', 2); +INSERT INTO `item` (name, category_id) VALUES ('Toy Story', 2); +INSERT INTO `item` (name, category_id) VALUES ('Cars', 2); + +INSERT INTO `order` (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); +INSERT INTO `order` (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); +INSERT INTO `order` (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); + +INSERT INTO `order_with_null_fk` (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); +INSERT INTO `order_with_null_fk` (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); +INSERT INTO `order_with_null_fk` (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); + +INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); +INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); +INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); +INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); +INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); + +INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); +INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); +INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); +INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); +INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); + + +/** + * (MySQL-)Database Schema for validator tests + */ + +DROP TABLE IF EXISTS `validator_main` CASCADE; +DROP TABLE IF EXISTS `validator_ref` CASCADE; + +CREATE TABLE `validator_main` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `field1` VARCHAR(255), + PRIMARY KEY (`id`) +) ENGINE =InnoDB DEFAULT CHARSET =utf8; + +CREATE TABLE `validator_ref` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `a_field` VARCHAR(255), + `ref` INT(11), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT INTO `validator_main` (id, field1) VALUES (1, 'just a string1'); +INSERT INTO `validator_main` (id, field1) VALUES (2, 'just a string2'); +INSERT INTO `validator_main` (id, field1) VALUES (3, 'just a string3'); +INSERT INTO `validator_main` (id, field1) VALUES (4, 'just a string4'); +INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_2', 2); +INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_2', 2); +INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_3', 3); +INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_4', 4); +INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_4', 4); +INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_5', 5); diff --git a/tests/data/oci.sql b/tests/data/oci.sql new file mode 100644 index 0000000..cf8736f --- /dev/null +++ b/tests/data/oci.sql @@ -0,0 +1,280 @@ +/** + * This is the database schema for testing PostgreSQL support of yii Active Record. + * To test this feature, you need to create a database named 'yiitest' on 'localhost' + * and create an account 'postgres/postgres' which owns this test database. + */ + +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "composite_fk"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "order_item"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "item"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "order_item_with_null_fk"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "order"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "order_with_null_fk"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "category"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "customer"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "profile"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "type"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "null_values"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "constraints"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "bool_values"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "animal"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP VIEW "animal_view"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "validator_main"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP TABLE "validator_ref"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- + +BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "profile_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "customer_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "category_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "item_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "order_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "order_with_null_fk_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "bool_values_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- +BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "animal_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- + +/* STATEMENTS */ + +CREATE TABLE "constraints" +( + "id" integer not null, + "field1" varchar2(255) +); + +CREATE TABLE "profile" ( + "id" integer not null, + "description" varchar2(128) NOT NULL, + CONSTRAINT "profile_PK" PRIMARY KEY ("id") ENABLE +); + +CREATE SEQUENCE "profile_SEQ"; + +CREATE TABLE "customer" ( + "id" integer not null, + "email" varchar2(128) NOT NULL, + "name" varchar2(128), + "address" varchar(4000), + "status" integer DEFAULT 0, + "bool_status" char DEFAULT 0 check ("bool_status" in (0,1)), + "profile_id" integer, + CONSTRAINT "customer_PK" PRIMARY KEY ("id") ENABLE +); +CREATE SEQUENCE "customer_SEQ"; + +comment on column "customer"."email" is 'someone@example.com'; + +CREATE TABLE "category" ( + "id" integer not null, + "name" varchar2(128) NOT NULL, + CONSTRAINT "category_PK" PRIMARY KEY ("id") ENABLE +); +CREATE SEQUENCE "category_SEQ"; + +CREATE TABLE "item" ( + "id" integer not null, + "name" varchar2(128) NOT NULL, + "category_id" integer NOT NULL references "category"("id") on DELETE CASCADE, + CONSTRAINT "item_PK" PRIMARY KEY ("id") ENABLE +); +CREATE SEQUENCE "item_SEQ"; + +CREATE TABLE "order" ( + "id" integer not null, + "customer_id" integer NOT NULL references "customer"("id") on DELETE CASCADE, + "created_at" integer NOT NULL, + "total" decimal(10,0) NOT NULL, + CONSTRAINT "order_PK" PRIMARY KEY ("id") ENABLE +); +CREATE SEQUENCE "order_SEQ"; + +CREATE TABLE "order_with_null_fk" ( + "id" integer not null, + "customer_id" integer, + "created_at" integer NOT NULL, + "total" decimal(10,0) NOT NULL, + CONSTRAINT "order_with_null_fk_PK" PRIMARY KEY ("id") ENABLE +); +CREATE SEQUENCE "order_with_null_fk_SEQ"; + +CREATE TABLE "order_item" ( + "order_id" integer NOT NULL references "order"("id") on DELETE CASCADE, + "item_id" integer NOT NULL references "item"("id") on DELETE CASCADE, + "quantity" integer NOT NULL, + "subtotal" decimal(10,0) NOT NULL, + CONSTRAINT "order_item_PK" PRIMARY KEY ("order_id", "item_id") ENABLE +); + +CREATE TABLE "order_item_with_null_fk" ( + "order_id" integer, + "item_id" integer, + "quantity" integer NOT NULL, + "subtotal" decimal(10,0) NOT NULL +); + +CREATE TABLE "composite_fk" ( + "id" integer NOT NULL, + "order_id" integer NOT NULL, + "item_id" integer NOT NULL, + CONSTRAINT "composite_fk_PK" PRIMARY KEY ("id") ENABLE, + CONSTRAINT FK_composite_fk_order_item FOREIGN KEY ("order_id", "item_id") + REFERENCES "order_item" ("order_id", "item_id") ON DELETE CASCADE +); + +CREATE TABLE "null_values" ( + "id" INT NOT NULL, + "var1" INT NULL, + "var2" INT NULL, + "var3" INT DEFAULT NULL, + "stringcol" varchar2(32) DEFAULT NULL, + CONSTRAINT "null_values_PK" PRIMARY KEY ("id") ENABLE +); + +CREATE TABLE "type" ( + "int_col" integer NOT NULL, + "int_col2" integer DEFAULT 1, + "smallint_col" smallint DEFAULT 1, + "char_col" char(100) NOT NULL, + "char_col2" varchar2(100) DEFAULT 'something', + "char_col3" varchar2(4000), + "float_col" double precision NOT NULL, + "float_col2" double precision DEFAULT 1.23, + "blob_col" blob, + "numeric_col" decimal(5,2) DEFAULT 33.22, + "time" timestamp DEFAULT to_timestamp('2002-01-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') NOT NULL, + "bool_col" char NOT NULL check ("bool_col" in (0,1)), + "bool_col2" char DEFAULT 1 check("bool_col2" in (0,1)), + "ts_default" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + "bit_col" char(3) DEFAULT 130 NOT NULL +); + +CREATE TABLE "bool_values" ( + "id" integer not null, + "bool_col" char check ("bool_col" in (0,1)), + "default_true" char default 1 not null check ("default_true" in (0,1)), + "default_false" char default 0 not null check ("default_false" in (0,1)), + CONSTRAINT "bool_values_PK" PRIMARY KEY ("id") ENABLE +); +CREATE SEQUENCE "bool_values_SEQ"; + + +CREATE TABLE "animal" ( + "id" integer, + "type" varchar2(255) not null, + CONSTRAINT "animal_PK" PRIMARY KEY ("id") ENABLE +); +CREATE SEQUENCE "animal_SEQ"; + +CREATE VIEW "animal_view" AS SELECT * FROM "animal"; + +/** + * (Postgres-)Database Schema for validator tests + */ + +CREATE TABLE "validator_main" ( + "id" integer not null, + "field1" varchar2(255), + CONSTRAINT "validator_main_PK" PRIMARY KEY ("id") ENABLE +); + +CREATE TABLE "validator_ref" ( + "id" integer not null, + "a_field" varchar2(255), + "ref" integer, + CONSTRAINT "validator_ref_PK" PRIMARY KEY ("id") ENABLE +); + +/* TRIGGERS */ + +CREATE TRIGGER "profile_TRG" BEFORE INSERT ON "profile" FOR EACH ROW BEGIN <> BEGIN + IF INSERTING AND :NEW."id" IS NULL THEN SELECT "profile_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; +END COLUMN_SEQUENCES; +END; +/ +CREATE TRIGGER "customer_TRG" BEFORE INSERT ON "customer" FOR EACH ROW BEGIN <> BEGIN + IF INSERTING AND :NEW."id" IS NULL THEN SELECT "customer_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; +END COLUMN_SEQUENCES; +END; +/ +CREATE TRIGGER "category_TRG" BEFORE INSERT ON "category" FOR EACH ROW BEGIN <> BEGIN + IF INSERTING AND :NEW."id" IS NULL THEN SELECT "category_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; +END COLUMN_SEQUENCES; +END; +/ +CREATE TRIGGER "item_TRG" BEFORE INSERT ON "item" FOR EACH ROW BEGIN <> BEGIN + IF INSERTING AND :NEW."id" IS NULL THEN SELECT "item_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; +END COLUMN_SEQUENCES; +END; +/ +CREATE TRIGGER "order_TRG" BEFORE INSERT ON "order" FOR EACH ROW BEGIN <> BEGIN + IF INSERTING AND :NEW."id" IS NULL THEN SELECT "order_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; +END COLUMN_SEQUENCES; +END; +/ +CREATE TRIGGER "order_with_null_fk_TRG" BEFORE INSERT ON "order_with_null_fk" FOR EACH ROW BEGIN <> BEGIN + IF INSERTING AND :NEW."id" IS NULL THEN SELECT "order_with_null_fk_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; +END COLUMN_SEQUENCES; +END; +/ +CREATE TRIGGER "bool_values_TRG" BEFORE INSERT ON "bool_values" FOR EACH ROW BEGIN <> BEGIN + IF INSERTING AND :NEW."id" IS NULL THEN SELECT "bool_values_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; +END COLUMN_SEQUENCES; +END; +/ +CREATE TRIGGER "animal_TRG" BEFORE INSERT ON "animal" FOR EACH ROW BEGIN <> BEGIN + IF INSERTING AND :NEW."id" IS NULL THEN SELECT "animal_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; +END COLUMN_SEQUENCES; +END; +/ + +/* TRIGGERS */ + +INSERT INTO "animal" ("type") VALUES ('yiiunit\data\ar\Cat'); +INSERT INTO "animal" ("type") VALUES ('yiiunit\data\ar\Dog'); + + +INSERT INTO "profile" ("description") VALUES ('profile customer 1'); +INSERT INTO "profile" ("description") VALUES ('profile customer 3'); + +INSERT INTO "customer" ("email", "name", "address", "status", "bool_status", "profile_id") VALUES ('user1@example.com', 'user1', 'address1', 1, 1, 1); +INSERT INTO "customer" ("email", "name", "address", "status", "bool_status") VALUES ('user2@example.com', 'user2', 'address2', 1, 1); +INSERT INTO "customer" ("email", "name", "address", "status", "bool_status", "profile_id") VALUES ('user3@example.com', 'user3', 'address3', 2, 0, 2); + +INSERT INTO "category" ("name") VALUES ('Books'); +INSERT INTO "category" ("name") VALUES ('Movies'); + +INSERT INTO "item" ("name", "category_id") VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); +INSERT INTO "item" ("name", "category_id") VALUES ('Yii 1.1 Application Development Cookbook', 1); +INSERT INTO "item" ("name", "category_id") VALUES ('Ice Age', 2); +INSERT INTO "item" ("name", "category_id") VALUES ('Toy Story', 2); +INSERT INTO "item" ("name", "category_id") VALUES ('Cars', 2); + +INSERT INTO "order" ("customer_id", "created_at", "total") VALUES (1, 1325282384, 110.0); +INSERT INTO "order" ("customer_id", "created_at", "total") VALUES (2, 1325334482, 33.0); +INSERT INTO "order" ("customer_id", "created_at", "total") VALUES (2, 1325502201, 40.0); + +INSERT INTO "order_with_null_fk" ("customer_id", "created_at", "total") VALUES (1, 1325282384, 110.0); +INSERT INTO "order_with_null_fk" ("customer_id", "created_at", "total") VALUES (2, 1325334482, 33.0); +INSERT INTO "order_with_null_fk" ("customer_id", "created_at", "total") VALUES (2, 1325502201, 40.0); + +INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (1, 1, 1, 30.0); +INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (1, 2, 2, 40.0); +INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 4, 1, 10.0); +INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 5, 1, 15.0); +INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 3, 1, 8.0); +INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (3, 2, 1, 40.0); + +INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (1, 1, 1, 30.0); +INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (1, 2, 2, 40.0); +INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 4, 1, 10.0); +INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 5, 1, 15.0); +INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 3, 1, 8.0); +INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (3, 2, 1, 40.0); + +INSERT INTO "validator_main" ("id", "field1") VALUES (1, 'just a string1'); +INSERT INTO "validator_main" ("id", "field1") VALUES (2, 'just a string2'); +INSERT INTO "validator_main" ("id", "field1") VALUES (3, 'just a string3'); +INSERT INTO "validator_main" ("id", "field1") VALUES (4, 'just a string4'); +INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (1, 'ref_to_2', 2); +INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (2, 'ref_to_2', 2); +INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (3, 'ref_to_3', 3); +INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (4, 'ref_to_4', 4); +INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (5, 'ref_to_4', 4); +INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (6, 'ref_to_5', 5); diff --git a/tests/data/postgres.sql b/tests/data/postgres.sql new file mode 100644 index 0000000..bbb8aba --- /dev/null +++ b/tests/data/postgres.sql @@ -0,0 +1,210 @@ +/** + * This is the database schema for testing PostgreSQL support of yii Active Record. + * To test this feature, you need to create a database named 'yiitest' on 'localhost' + * and create an account 'postgres/postgres' which owns this test database. + */ + +DROP TABLE IF EXISTS "composite_fk" CASCADE; +DROP TABLE IF EXISTS "order_item" CASCADE; +DROP TABLE IF EXISTS "item" CASCADE; +DROP TABLE IF EXISTS "order_item_with_null_fk" CASCADE; +DROP TABLE IF EXISTS "order" CASCADE; +DROP TABLE IF EXISTS "order_with_null_fk" CASCADE; +DROP TABLE IF EXISTS "category" CASCADE; +DROP TABLE IF EXISTS "customer" CASCADE; +DROP TABLE IF EXISTS "profile" CASCADE; +DROP TABLE IF EXISTS "type" CASCADE; +DROP TABLE IF EXISTS "null_values" CASCADE; +DROP TABLE IF EXISTS "constraints" CASCADE; +DROP TABLE IF EXISTS "bool_values" CASCADE; +DROP TABLE IF EXISTS "animal" CASCADE; +DROP VIEW IF EXISTS "animal_view"; +DROP SCHEMA IF EXISTS "schema1" CASCADE; +DROP SCHEMA IF EXISTS "schema2" CASCADE; + +CREATE SCHEMA "schema1"; +CREATE SCHEMA "schema2"; + +CREATE TABLE "constraints" +( + id integer not null, + field1 varchar(255) +); + +CREATE TABLE "profile" ( + id serial not null primary key, + description varchar(128) NOT NULL +); + +CREATE TABLE "customer" ( + id serial not null primary key, + email varchar(128) NOT NULL, + name varchar(128), + address text, + status integer DEFAULT 0, + bool_status boolean DEFAULT FALSE, + profile_id integer +); + +comment on column public.customer.email is 'someone@example.com'; + +CREATE TABLE "category" ( + id serial not null primary key, + name varchar(128) NOT NULL +); + +CREATE TABLE "item" ( + id serial not null primary key, + name varchar(128) NOT NULL, + category_id integer NOT NULL references "category"(id) on UPDATE CASCADE on DELETE CASCADE +); + +CREATE TABLE "order" ( + id serial not null primary key, + customer_id integer NOT NULL references "customer"(id) on UPDATE CASCADE on DELETE CASCADE, + created_at integer NOT NULL, + total decimal(10,0) NOT NULL +); + +CREATE TABLE "order_with_null_fk" ( + id serial not null primary key, + customer_id integer, + created_at integer NOT NULL, + total decimal(10,0) NOT NULL +); + +CREATE TABLE "order_item" ( + order_id integer NOT NULL references "order"(id) on UPDATE CASCADE on DELETE CASCADE, + item_id integer NOT NULL references "item"(id) on UPDATE CASCADE on DELETE CASCADE, + quantity integer NOT NULL, + subtotal decimal(10,0) NOT NULL, + PRIMARY KEY (order_id,item_id) +); + +CREATE TABLE "order_item_with_null_fk" ( + order_id integer, + item_id integer, + quantity integer NOT NULL, + subtotal decimal(10,0) NOT NULL +); + +CREATE TABLE "composite_fk" ( + id integer NOT NULL, + order_id integer NOT NULL, + item_id integer NOT NULL, + PRIMARY KEY (id), + CONSTRAINT FK_composite_fk_order_item FOREIGN KEY (order_id, item_id) REFERENCES "order_item" (order_id, item_id) ON DELETE CASCADE +); + +CREATE TABLE "null_values" ( + id INT NOT NULL, + var1 INT NULL, + var2 INT NULL, + var3 INT DEFAULT NULL, + stringcol VARCHAR(32) DEFAULT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE "type" ( + int_col integer NOT NULL, + int_col2 integer DEFAULT '1', + smallint_col smallint DEFAULT '1', + char_col char(100) NOT NULL, + char_col2 varchar(100) DEFAULT 'something', + char_col3 text, + float_col double precision NOT NULL, + float_col2 double precision DEFAULT '1.23', + blob_col bytea, + numeric_col decimal(5,2) DEFAULT '33.22', + time timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', + bool_col boolean NOT NULL, + bool_col2 boolean DEFAULT TRUE, + ts_default TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + bit_col BIT(8) NOT NULL DEFAULT B'10000010' +); + +CREATE TABLE "bool_values" ( + id serial not null primary key, + bool_col bool, + default_true bool not null default true, + default_false boolean not null default false +); + + +CREATE TABLE "animal" ( + id serial primary key, + type varchar(255) not null +); + +CREATE VIEW "animal_view" AS SELECT * FROM "animal"; + +INSERT INTO "animal" (type) VALUES ('yiiunit\data\ar\Cat'); +INSERT INTO "animal" (type) VALUES ('yiiunit\data\ar\Dog'); + + +INSERT INTO "profile" (description) VALUES ('profile customer 1'); +INSERT INTO "profile" (description) VALUES ('profile customer 3'); + +INSERT INTO "customer" (email, name, address, status, bool_status, profile_id) VALUES ('user1@example.com', 'user1', 'address1', 1, true, 1); +INSERT INTO "customer" (email, name, address, status, bool_status) VALUES ('user2@example.com', 'user2', 'address2', 1, true); +INSERT INTO "customer" (email, name, address, status, bool_status, profile_id) VALUES ('user3@example.com', 'user3', 'address3', 2, false, 2); + +INSERT INTO "category" (name) VALUES ('Books'); +INSERT INTO "category" (name) VALUES ('Movies'); + +INSERT INTO "item" (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); +INSERT INTO "item" (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); +INSERT INTO "item" (name, category_id) VALUES ('Ice Age', 2); +INSERT INTO "item" (name, category_id) VALUES ('Toy Story', 2); +INSERT INTO "item" (name, category_id) VALUES ('Cars', 2); + +INSERT INTO "order" (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); +INSERT INTO "order" (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); +INSERT INTO "order" (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); + +INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); +INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); +INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); + +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); + +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); + +/** + * (Postgres-)Database Schema for validator tests + */ + +DROP TABLE IF EXISTS "validator_main" CASCADE; +DROP TABLE IF EXISTS "validator_ref" CASCADE; + +CREATE TABLE "validator_main" ( + id integer not null primary key, + field1 VARCHAR(255) +); + +CREATE TABLE "validator_ref" ( + id integer not null primary key, + a_field VARCHAR(255), + ref integer +); + +INSERT INTO "validator_main" (id, field1) VALUES (1, 'just a string1'); +INSERT INTO "validator_main" (id, field1) VALUES (2, 'just a string2'); +INSERT INTO "validator_main" (id, field1) VALUES (3, 'just a string3'); +INSERT INTO "validator_main" (id, field1) VALUES (4, 'just a string4'); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (1, 'ref_to_2', 2); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (2, 'ref_to_2', 2); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (3, 'ref_to_3', 3); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (4, 'ref_to_4', 4); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (5, 'ref_to_4', 4); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (6, 'ref_to_5', 5); diff --git a/tests/data/sqlite.sql b/tests/data/sqlite.sql new file mode 100644 index 0000000..2c2d590 --- /dev/null +++ b/tests/data/sqlite.sql @@ -0,0 +1,189 @@ +/** + * This is the database schema for testing Sqlite support of Yii DAO and Active Record. + * The database setup in config.php is required to perform then relevant tests: + */ + +DROP TABLE IF EXISTS "composite_fk"; +DROP TABLE IF EXISTS "order_item"; +DROP TABLE IF EXISTS "order_item_with_null_fk"; +DROP TABLE IF EXISTS "item"; +DROP TABLE IF EXISTS "order"; +DROP TABLE IF EXISTS "order_with_null_fk"; +DROP TABLE IF EXISTS "category"; +DROP TABLE IF EXISTS "customer"; +DROP TABLE IF EXISTS "profile"; +DROP TABLE IF EXISTS "type"; +DROP TABLE IF EXISTS "null_values"; +DROP TABLE IF EXISTS "animal"; +DROP VIEW IF EXISTS "animal_view"; + +CREATE TABLE "profile" ( + id INTEGER NOT NULL, + description varchar(128) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE "customer" ( + id INTEGER NOT NULL, + email varchar(128) NOT NULL, + name varchar(128), + address text, + status INTEGER DEFAULT 0, + profile_id INTEGER, + PRIMARY KEY (id) +); + +CREATE TABLE "category" ( + id INTEGER NOT NULL, + name varchar(128) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE "item" ( + id INTEGER NOT NULL, + name varchar(128) NOT NULL, + category_id INTEGER NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE "order" ( + id INTEGER NOT NULL, + customer_id INTEGER NOT NULL, + created_at INTEGER NOT NULL, + total decimal(10,0) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE "order_with_null_fk" ( + id INTEGER NOT NULL, + customer_id INTEGER, + created_at INTEGER NOT NULL, + total decimal(10,0) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE "order_item" ( + order_id INTEGER NOT NULL, + item_id INTEGER NOT NULL, + quantity INTEGER NOT NULL, + subtotal decimal(10,0) NOT NULL, + PRIMARY KEY (order_id, item_id) +); + +CREATE TABLE "order_item_with_null_fk" ( + order_id INTEGER, + item_id INTEGER, + quantity INTEGER NOT NULL, + subtotal decimal(10,0) NOT NULL +); + +CREATE TABLE "composite_fk" ( + id int(11) NOT NULL, + order_id int(11) NOT NULL, + item_id int(11) NOT NULL, + PRIMARY KEY (id), + CONSTRAINT FK_composite_fk_order_item FOREIGN KEY (order_id, item_id) REFERENCES "order_item" (order_id, item_id) ON DELETE CASCADE +); + +CREATE TABLE "null_values" ( + id INTEGER UNSIGNED PRIMARY KEY NOT NULL, + var1 INTEGER UNSIGNED, + var2 INTEGER, + var3 INTEGER DEFAULT NULL, + stringcol VARCHAR(32) DEFAULT NULL +); + +CREATE TABLE "type" ( + int_col INTEGER NOT NULL, + int_col2 INTEGER DEFAULT '1', + smallint_col SMALLINT(1) DEFAULT '1', + char_col char(100) NOT NULL, + char_col2 varchar(100) DEFAULT 'something', + char_col3 text, + float_col double(4,3) NOT NULL, + float_col2 double DEFAULT '1.23', + blob_col blob, + numeric_col decimal(5,2) DEFAULT '33.22', + time timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', + bool_col tinyint(1) NOT NULL, + bool_col2 tinyint(1) DEFAULT '1', + ts_default TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE "animal" ( + id INTEGER NOT NULL, + type VARCHAR(255) NOT NULL, + PRIMARY KEY (id) +); + +CREATE VIEW "animal_view" AS SELECT * FROM "animal"; + +INSERT INTO "animal" ("type") VALUES ('yiiunit\data\ar\Cat'); +INSERT INTO "animal" ("type") VALUES ('yiiunit\data\ar\Dog'); + +INSERT INTO "profile" (description) VALUES ('profile customer 1'); +INSERT INTO "profile" (description) VALUES ('profile customer 3'); + +INSERT INTO "customer" (email, name, address, status, profile_id) VALUES ('user1@example.com', 'user1', 'address1', 1, 1); +INSERT INTO "customer" (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); +INSERT INTO "customer" (email, name, address, status, profile_id) VALUES ('user3@example.com', 'user3', 'address3', 2, 2); + +INSERT INTO "category" (name) VALUES ('Books'); +INSERT INTO "category" (name) VALUES ('Movies'); + +INSERT INTO "item" (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); +INSERT INTO "item" (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); +INSERT INTO "item" (name, category_id) VALUES ('Ice Age', 2); +INSERT INTO "item" (name, category_id) VALUES ('Toy Story', 2); +INSERT INTO "item" (name, category_id) VALUES ('Cars', 2); + +INSERT INTO "order" (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); +INSERT INTO "order" (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); +INSERT INTO "order" (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); + +INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); +INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); +INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); + +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); + +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); + +/** + * (SqLite-)Database Schema for validator tests + */ + +DROP TABLE IF EXISTS "validator_main"; +DROP TABLE IF EXISTS "validator_ref"; + +CREATE TABLE "validator_main" ( + id INTEGER PRIMARY KEY , + field1 VARCHAR(255) +); + +CREATE TABLE "validator_ref" ( + id INTEGER PRIMARY KEY , + a_field VARCHAR(255), + ref INT(11) +); + +INSERT INTO "validator_main" (id, field1) VALUES (1, 'just a string1'); +INSERT INTO "validator_main" (id, field1) VALUES (2, 'just a string2'); +INSERT INTO "validator_main" (id, field1) VALUES (3, 'just a string3'); +INSERT INTO "validator_main" (id, field1) VALUES (4, 'just a string4'); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (1, 'ref_to_2', 2); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (2, 'ref_to_2', 2); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (3, 'ref_to_3', 3); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (4, 'ref_to_4', 4); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (5, 'ref_to_4', 4); +INSERT INTO "validator_ref" (id, a_field, ref) VALUES (6, 'ref_to_5', 5); diff --git a/tests/data/travis/README.md b/tests/data/travis/README.md new file mode 100644 index 0000000..a01c37f --- /dev/null +++ b/tests/data/travis/README.md @@ -0,0 +1,12 @@ +This directory contains scripts for automated test runs via the [Travis CI](http://travis-ci.org) build service. They are used for the preparation of worker instances by setting up needed extensions and configuring database access. + +These scripts might be used to configure your own system for test runs. But since their primary purpose remains to support Travis in running the test cases, you would be best advised to stick to the setup notes in the tests themselves. + +The scripts are: + + - [`apc-setup.sh`](apc-setup.sh) + Installs and configures the [apc pecl extension](http://pecl.php.net/package/apc) + - [`cubrid-setup.sh`](cubrid-setup.sh) + Prepares the [CUBRID](http://www.cubrid.org/) server instance by installing the server and PHP PDO driver + - [`memcache-setup.sh`](memcache-setup.sh) + Compiles and installs the [memcache pecl extension](http://pecl.php.net/package/memcache) diff --git a/tests/data/travis/apc-setup.sh b/tests/data/travis/apc-setup.sh new file mode 100644 index 0000000..d64e8a5 --- /dev/null +++ b/tests/data/travis/apc-setup.sh @@ -0,0 +1,8 @@ +#!/bin/sh -e + +if [ "$(expr "$TRAVIS_PHP_VERSION" "<" "5.5")" -eq 1 ]; then + echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini + echo "apc.enable_cli = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini +else + echo "Not installing APC as it is not available in PHP 5.5 anymore." +fi \ No newline at end of file diff --git a/tests/data/travis/cubrid-setup.sh b/tests/data/travis/cubrid-setup.sh new file mode 100644 index 0000000..81f4087 --- /dev/null +++ b/tests/data/travis/cubrid-setup.sh @@ -0,0 +1,79 @@ +#!/bin/sh -e +# +# install CUBRID DBMS + +if (php --version | grep -i HipHop > /dev/null); then + echo "Skipping CUBRID on HHVM" + exit 0 +fi + +CWD=$(pwd) + +# cubrid dbms +mkdir -p cubrid/$CUBRID_VERSION +cd cubrid +if (test -f $CUBRID_VERSION-linux.x86_64.tar.gz); then + echo "CUBRID is already downloaded" +else + wget http://ftp.cubrid.org/CUBRID_Engine/$CUBRID_VERSION-linux.x86_64.tar.gz -O $CUBRID_VERSION-linux.x86_64.tar.gz + cd $CUBRID_VERSION + tar xzf ../../$CUBRID_VERSION-linux.x86_64.tar.gz + cd ../.. +fi + +echo "setting cubrid env" +CUBRID=$CWD/cubrid/$CUBRID_VERSION/CUBRID +CUBRID_DATABASES=$CUBRID/databases +CUBRID_LANG=en_US + +ld_lib_path=`printenv LD_LIBRARY_PATH` || echo "LD_LIBRARY_PATH is empty" +if [ "$ld_lib_path" = "" ] +then + LD_LIBRARY_PATH=$CUBRID/lib +else + LD_LIBRARY_PATH=$CUBRID/lib:$LD_LIBRARY_PATH +fi + +SHLIB_PATH=$LD_LIBRARY_PATH +LIBPATH=$LD_LIBRARY_PATH +PATH=$CUBRID/bin:$CUBRID/cubridmanager:$PATH + +export CUBRID +export CUBRID_DATABASES +export CUBRID_LANG +export LD_LIBRARY_PATH +export SHLIB_PATH +export LIBPATH +export PATH + +# start cubrid +echo "starting cubrid..." +cubrid service start || echo "starting CUBRID services failed with exit code $?" +# create and start the demo db +$CUBRID/demo/make_cubrid_demo.sh || echo "setting up CUBRID demodb failed with exit code $?" +cubrid server start demodb || (echo "starting CUBRID demodb failed with exit code $?" && cat demodb_loaddb.log) + +echo "" +echo "Installed CUBRID $CUBRID_VERSION" +echo "" + +# cubrid pdo +install_pdo_cubrid() { + if (test "! (-f PDO_CUBRID-$CUBRID_PDO_VERSION.tgz)"); then + wget "http://pecl.php.net/get/PDO_CUBRID-$CUBRID_PDO_VERSION.tgz" -O PDO_CUBRID-$CUBRID_PDO_VERSION.tgz + fi + tar -zxf "PDO_CUBRID-$CUBRID_PDO_VERSION.tgz" + sh -c "cd PDO_CUBRID-$CUBRID_PDO_VERSION && phpize && ./configure --prefix=$CWD/cubrid/PDO_CUBRID-$CUBRID_PDO_VERSION && make" + + echo "extension=$CWD/cubrid/PDO_CUBRID-$CUBRID_PDO_VERSION/modules/pdo_cubrid.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini + + return $? +} + +install_pdo_cubrid > ~/pdo_cubrid.log || ( echo "=== PDO CUBRID BUILD FAILED ==="; cat ~/pdo_cubrid.log; exit 1 ) + +echo "" +echo "Installed CUBRID PDO $CUBRID_PDO_VERSION" +echo "" + +cd .. diff --git a/tests/data/travis/cubrid-solo.rb b/tests/data/travis/cubrid-solo.rb new file mode 100644 index 0000000..f5f0004 --- /dev/null +++ b/tests/data/travis/cubrid-solo.rb @@ -0,0 +1,5 @@ +file_cache_path "/tmp/chef-solo" +data_bag_path "/tmp/chef-solo/data_bags" +encrypted_data_bag_secret "/tmp/chef-solo/data_bag_key" +cookbook_path [ "/tmp/chef-solo/cookbooks" ] +role_path "/tmp/chef-solo/roles" \ No newline at end of file diff --git a/tests/data/travis/memcache-setup.sh b/tests/data/travis/memcache-setup.sh new file mode 100644 index 0000000..e8b99e7 --- /dev/null +++ b/tests/data/travis/memcache-setup.sh @@ -0,0 +1,9 @@ +#!/bin/sh -e + +if (php --version | grep -i HipHop > /dev/null); then + echo "skipping memcache on HHVM" +else + mkdir -p ~/.phpenv/versions/$(phpenv version-name)/etc + echo "extension=memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini + echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini +fi diff --git a/tests/data/validators/TestValidator.php b/tests/data/validators/TestValidator.php new file mode 100644 index 0000000..b26a589 --- /dev/null +++ b/tests/data/validators/TestValidator.php @@ -0,0 +1,43 @@ +markAttributeValidated($attribute); + if ($this->_setErrorOnValidateAttribute == true) { + $this->addError($object, $attribute, sprintf('%s##%s', $attribute, get_class($object))); + } + } + + protected function markAttributeValidated($attr, $increaseBy = 1) + { + if (!isset($this->_validatedAttributes[$attr])) { + $this->_validatedAttributes[$attr] = 1; + } else { + $this->_validatedAttributes[$attr] = $this->_validatedAttributes[$attr] + $increaseBy; + } + } + + public function countAttributeValidations($attr) + { + return isset($this->_validatedAttributes[$attr]) ? $this->_validatedAttributes[$attr] : 0; + } + + public function isAttributeValidated($attr) + { + return isset($this->_validatedAttributes[$attr]); + } + + public function enableErrorOnValidateAttribute() + { + $this->_setErrorOnValidateAttribute = true; + } +} diff --git a/tests/data/validators/models/FakedValidationModel.php b/tests/data/validators/models/FakedValidationModel.php new file mode 100644 index 0000000..6da3aa2 --- /dev/null +++ b/tests/data/validators/models/FakedValidationModel.php @@ -0,0 +1,66 @@ + $value) { + $m->$attribute = $value; + } + + return $m; + } + + public function rules() + { + return [ + [['val_attr_a', 'val_attr_b'], 'required', 'on' => 'reqTest'], + ['val_attr_c', 'integer'], + ['attr_images', 'file', 'maxFiles' => 3, 'extensions' => ['png'], 'on' => 'validateMultipleFiles', 'checkExtensionByMimeType' => false], + ['attr_image', 'file', 'extensions' => ['png'], 'on' => 'validateFile', 'checkExtensionByMimeType' => false] + ]; + } + + public function inlineVal($attribute, $params = []) + { + return true; + } + + public function __get($name) + { + if (stripos($name, 'attr') === 0) { + return isset($this->attr[$name]) ? $this->attr[$name] : null; + } + + return parent::__get($name); + } + + public function __set($name, $value) + { + if (stripos($name, 'attr') === 0) { + $this->attr[$name] = $value; + } else { + parent::__set($name, $value); + } + } + + public function getAttributeLabel($attr) + { + return $attr; + } +} diff --git a/tests/data/validators/models/ValidatorTestMainModel.php b/tests/data/validators/models/ValidatorTestMainModel.php new file mode 100644 index 0000000..7031e3f --- /dev/null +++ b/tests/data/validators/models/ValidatorTestMainModel.php @@ -0,0 +1,20 @@ +hasMany(ValidatorTestRefModel::className(), ['ref' => 'id']); + } +} diff --git a/tests/data/validators/models/ValidatorTestRefModel.php b/tests/data/validators/models/ValidatorTestRefModel.php new file mode 100644 index 0000000..bf0ebe5 --- /dev/null +++ b/tests/data/validators/models/ValidatorTestRefModel.php @@ -0,0 +1,22 @@ +hasOne(ValidatorTestMainModel::className(), ['id' => 'ref']); + } +} diff --git a/tests/data/views/layout.php b/tests/data/views/layout.php new file mode 100644 index 0000000..321819b --- /dev/null +++ b/tests/data/views/layout.php @@ -0,0 +1,20 @@ + +beginPage(); ?> + + + + Test + head(); ?> + + +beginBody(); ?> + + + +endBody(); ?> + + +endPage(); ?> diff --git a/tests/data/views/rawlayout.php b/tests/data/views/rawlayout.php new file mode 100644 index 0000000..0d4f3e0 --- /dev/null +++ b/tests/data/views/rawlayout.php @@ -0,0 +1,3 @@ +beginPage(); ?>1head(); ?>2beginBody(); ?>3endBody(); ?>4endPage(); ?> diff --git a/tests/data/views/simple.php b/tests/data/views/simple.php new file mode 100644 index 0000000..2533486 --- /dev/null +++ b/tests/data/views/simple.php @@ -0,0 +1 @@ +This is a damn simple view file. diff --git a/tests/data/web/assets/.gitignore b/tests/data/web/assets/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/tests/data/web/assets/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/tests/data/web/data.txt b/tests/data/web/data.txt new file mode 100644 index 0000000..8e58281 --- /dev/null +++ b/tests/data/web/data.txt @@ -0,0 +1 @@ +12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=? \ No newline at end of file diff --git a/tests/framework/BaseYiiTest.php b/tests/framework/BaseYiiTest.php new file mode 100644 index 0000000..4168382 --- /dev/null +++ b/tests/framework/BaseYiiTest.php @@ -0,0 +1,63 @@ +aliases = Yii::$aliases; + } + + protected function tearDown() + { + parent::tearDown(); + Yii::$aliases = $this->aliases; + } + + public function testAlias() + { + $this->assertEquals(YII2_PATH, Yii::getAlias('@yii')); + + Yii::$aliases = []; + $this->assertFalse(Yii::getAlias('@yii', false)); + + Yii::setAlias('@yii', '/yii/framework'); + $this->assertEquals('/yii/framework', Yii::getAlias('@yii')); + $this->assertEquals('/yii/framework/test/file', Yii::getAlias('@yii/test/file')); + Yii::setAlias('@yii/gii', '/yii/gii'); + $this->assertEquals('/yii/framework', Yii::getAlias('@yii')); + $this->assertEquals('/yii/framework/test/file', Yii::getAlias('@yii/test/file')); + $this->assertEquals('/yii/gii', Yii::getAlias('@yii/gii')); + $this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file')); + + Yii::setAlias('@tii', '@yii/test'); + $this->assertEquals('/yii/framework/test', Yii::getAlias('@tii')); + + Yii::setAlias('@yii', null); + $this->assertFalse(Yii::getAlias('@yii', false)); + $this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file')); + + Yii::setAlias('@some/alias', '/www'); + $this->assertEquals('/www', Yii::getAlias('@some/alias')); + } + + public function testGetVersion() + { + $this->assertTrue((boolean) preg_match('~\d+\.\d+(?:\.\d+)?(?:-\w+)?~', \Yii::getVersion())); + } + + public function testPowered() + { + $this->assertTrue(is_string(Yii::powered())); + } +} diff --git a/tests/framework/ar/ActiveRecordTestTrait.php b/tests/framework/ar/ActiveRecordTestTrait.php new file mode 100644 index 0000000..8ecb615 --- /dev/null +++ b/tests/framework/ar/ActiveRecordTestTrait.php @@ -0,0 +1,1144 @@ + + */ + +namespace yiiunit\framework\ar; + +use yii\base\Event; +use yii\db\ActiveQueryInterface; +use yii\db\BaseActiveRecord; +use yiiunit\TestCase; +use yiiunit\data\ar\Customer; +use yiiunit\data\ar\Order; + +/** + * This trait provides unit tests shared by the different AR implementations + */ +trait ActiveRecordTestTrait +{ + /* @var $this TestCase */ + /** + * This method should return the classname of Customer class + * @return string + */ + abstract public function getCustomerClass(); + + /** + * This method should return the classname of Order class + * @return string + */ + abstract public function getOrderClass(); + + /** + * This method should return the classname of OrderItem class + * @return string + */ + abstract public function getOrderItemClass(); + + /** + * This method should return the classname of Item class + * @return string + */ + abstract public function getItemClass(); + + abstract public function getOrderWithNullFKClass(); + + abstract public function getOrderItemWithNullFKmClass(); + + /** + * can be overridden to do things after save() + */ + public function afterSave() + { + } + + public function testFind() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + // find one + $result = $customerClass::find(); + $this->assertTrue($result instanceof ActiveQueryInterface); + $customer = $result->one(); + $this->assertTrue($customer instanceof $customerClass); + + // find all + $customers = $customerClass::find()->all(); + $this->assertEquals(3, count($customers)); + $this->assertTrue($customers[0] instanceof $customerClass); + $this->assertTrue($customers[1] instanceof $customerClass); + $this->assertTrue($customers[2] instanceof $customerClass); + + // find by a single primary key + $customer = $customerClass::findOne(2); + $this->assertTrue($customer instanceof $customerClass); + $this->assertEquals('user2', $customer->name); + $customer = $customerClass::findOne(5); + $this->assertNull($customer); + $customer = $customerClass::findOne(['id' => [5, 6, 1]]); + $this->assertEquals(1, count($customer)); + $customer = $customerClass::find()->where(['id' => [5, 6, 1]])->one(); + $this->assertNotNull($customer); + + // find by column values + $customer = $customerClass::findOne(['id' => 2, 'name' => 'user2']); + $this->assertTrue($customer instanceof $customerClass); + $this->assertEquals('user2', $customer->name); + $customer = $customerClass::findOne(['id' => 2, 'name' => 'user1']); + $this->assertNull($customer); + $customer = $customerClass::findOne(['id' => 5]); + $this->assertNull($customer); + $customer = $customerClass::findOne(['name' => 'user5']); + $this->assertNull($customer); + + // find by attributes + $customer = $customerClass::find()->where(['name' => 'user2'])->one(); + $this->assertTrue($customer instanceof $customerClass); + $this->assertEquals(2, $customer->id); + + // scope + $this->assertEquals(2, count($customerClass::find()->active()->all())); + $this->assertEquals(2, $customerClass::find()->active()->count()); + } + + public function testFindAsArray() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + // asArray + $customer = $customerClass::find()->where(['id' => 2])->asArray()->one(); + $this->assertEquals([ + 'id' => 2, + 'email' => 'user2@example.com', + 'name' => 'user2', + 'address' => 'address2', + 'status' => 1, + 'profile_id' => null, + ], $customer); + + // find all asArray + $customers = $customerClass::find()->asArray()->all(); + $this->assertEquals(3, count($customers)); + $this->assertArrayHasKey('id', $customers[0]); + $this->assertArrayHasKey('name', $customers[0]); + $this->assertArrayHasKey('email', $customers[0]); + $this->assertArrayHasKey('address', $customers[0]); + $this->assertArrayHasKey('status', $customers[0]); + $this->assertArrayHasKey('id', $customers[1]); + $this->assertArrayHasKey('name', $customers[1]); + $this->assertArrayHasKey('email', $customers[1]); + $this->assertArrayHasKey('address', $customers[1]); + $this->assertArrayHasKey('status', $customers[1]); + $this->assertArrayHasKey('id', $customers[2]); + $this->assertArrayHasKey('name', $customers[2]); + $this->assertArrayHasKey('email', $customers[2]); + $this->assertArrayHasKey('address', $customers[2]); + $this->assertArrayHasKey('status', $customers[2]); + } + + public function testFindScalar() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + // query scalar + $customerName = $customerClass::find()->where(['id' => 2])->scalar('name'); + $this->assertEquals('user2', $customerName); + $customerName = $customerClass::find()->where(['status' => 2])->scalar('name'); + $this->assertEquals('user3', $customerName); + $customerName = $customerClass::find()->where(['status' => 2])->scalar('noname'); + $this->assertNull($customerName); + $customerId = $customerClass::find()->where(['status' => 2])->scalar('id'); + $this->assertEquals(3, $customerId); + } + + public function testFindColumn() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + $this->assertEquals(['user1', 'user2', 'user3'], $customerClass::find()->orderBy(['name' => SORT_ASC])->column('name')); + $this->assertEquals(['user3', 'user2', 'user1'], $customerClass::find()->orderBy(['name' => SORT_DESC])->column('name')); + } + + public function testFindIndexBy() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + // indexBy + $customers = $customerClass::find()->indexBy('name')->orderBy('id')->all(); + $this->assertEquals(3, count($customers)); + $this->assertTrue($customers['user1'] instanceof $customerClass); + $this->assertTrue($customers['user2'] instanceof $customerClass); + $this->assertTrue($customers['user3'] instanceof $customerClass); + + // indexBy callable + $customers = $customerClass::find()->indexBy(function ($customer) { + return $customer->id . '-' . $customer->name; + })->orderBy('id')->all(); + $this->assertEquals(3, count($customers)); + $this->assertTrue($customers['1-user1'] instanceof $customerClass); + $this->assertTrue($customers['2-user2'] instanceof $customerClass); + $this->assertTrue($customers['3-user3'] instanceof $customerClass); + } + + public function testFindIndexByAsArray() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + // indexBy + asArray + $customers = $customerClass::find()->asArray()->indexBy('name')->all(); + $this->assertEquals(3, count($customers)); + $this->assertArrayHasKey('id', $customers['user1']); + $this->assertArrayHasKey('name', $customers['user1']); + $this->assertArrayHasKey('email', $customers['user1']); + $this->assertArrayHasKey('address', $customers['user1']); + $this->assertArrayHasKey('status', $customers['user1']); + $this->assertArrayHasKey('id', $customers['user2']); + $this->assertArrayHasKey('name', $customers['user2']); + $this->assertArrayHasKey('email', $customers['user2']); + $this->assertArrayHasKey('address', $customers['user2']); + $this->assertArrayHasKey('status', $customers['user2']); + $this->assertArrayHasKey('id', $customers['user3']); + $this->assertArrayHasKey('name', $customers['user3']); + $this->assertArrayHasKey('email', $customers['user3']); + $this->assertArrayHasKey('address', $customers['user3']); + $this->assertArrayHasKey('status', $customers['user3']); + + // indexBy callable + asArray + $customers = $customerClass::find()->indexBy(function ($customer) { + return $customer['id'] . '-' . $customer['name']; + })->asArray()->all(); + $this->assertEquals(3, count($customers)); + $this->assertArrayHasKey('id', $customers['1-user1']); + $this->assertArrayHasKey('name', $customers['1-user1']); + $this->assertArrayHasKey('email', $customers['1-user1']); + $this->assertArrayHasKey('address', $customers['1-user1']); + $this->assertArrayHasKey('status', $customers['1-user1']); + $this->assertArrayHasKey('id', $customers['2-user2']); + $this->assertArrayHasKey('name', $customers['2-user2']); + $this->assertArrayHasKey('email', $customers['2-user2']); + $this->assertArrayHasKey('address', $customers['2-user2']); + $this->assertArrayHasKey('status', $customers['2-user2']); + $this->assertArrayHasKey('id', $customers['3-user3']); + $this->assertArrayHasKey('name', $customers['3-user3']); + $this->assertArrayHasKey('email', $customers['3-user3']); + $this->assertArrayHasKey('address', $customers['3-user3']); + $this->assertArrayHasKey('status', $customers['3-user3']); + } + + public function testRefresh() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + $customer = new $customerClass(); + $this->assertFalse($customer->refresh()); + + $customer = $customerClass::findOne(1); + $customer->name = 'to be refreshed'; + $this->assertTrue($customer->refresh()); + $this->assertEquals('user1', $customer->name); + } + + public function testEquals() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $itemClass \yii\db\ActiveRecordInterface */ + $itemClass = $this->getItemClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + $customerA = new $customerClass(); + $customerB = new $customerClass(); + $this->assertFalse($customerA->equals($customerB)); + + $customerA = new $customerClass(); + $customerB = new $itemClass(); + $this->assertFalse($customerA->equals($customerB)); + + $customerA = $customerClass::findOne(1); + $customerB = $customerClass::findOne(2); + $this->assertFalse($customerA->equals($customerB)); + + $customerB = $customerClass::findOne(1); + $this->assertTrue($customerA->equals($customerB)); + + $customerA = $customerClass::findOne(1); + $customerB = $itemClass::findOne(1); + $this->assertFalse($customerA->equals($customerB)); + } + + public function testFindCount() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + $this->assertEquals(3, $customerClass::find()->count()); + + $this->assertEquals(1, $customerClass::find()->where(['id' => 1])->count()); + $this->assertEquals(2, $customerClass::find()->where(['id' => [1, 2]])->count()); + $this->assertEquals(2, $customerClass::find()->where(['id' => [1, 2]])->offset(1)->count()); + $this->assertEquals(2, $customerClass::find()->where(['id' => [1, 2]])->offset(2)->count()); + + // limit should have no effect on count() + $this->assertEquals(3, $customerClass::find()->limit(1)->count()); + $this->assertEquals(3, $customerClass::find()->limit(2)->count()); + $this->assertEquals(3, $customerClass::find()->limit(10)->count()); + $this->assertEquals(3, $customerClass::find()->offset(2)->limit(2)->count()); + } + + public function testFindLimit() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + // all() + $customers = $customerClass::find()->all(); + $this->assertEquals(3, count($customers)); + + $customers = $customerClass::find()->orderBy('id')->limit(1)->all(); + $this->assertEquals(1, count($customers)); + $this->assertEquals('user1', $customers[0]->name); + + $customers = $customerClass::find()->orderBy('id')->limit(1)->offset(1)->all(); + $this->assertEquals(1, count($customers)); + $this->assertEquals('user2', $customers[0]->name); + + $customers = $customerClass::find()->orderBy('id')->limit(1)->offset(2)->all(); + $this->assertEquals(1, count($customers)); + $this->assertEquals('user3', $customers[0]->name); + + $customers = $customerClass::find()->orderBy('id')->limit(2)->offset(1)->all(); + $this->assertEquals(2, count($customers)); + $this->assertEquals('user2', $customers[0]->name); + $this->assertEquals('user3', $customers[1]->name); + + $customers = $customerClass::find()->limit(2)->offset(3)->all(); + $this->assertEquals(0, count($customers)); + + // one() + $customer = $customerClass::find()->orderBy('id')->one(); + $this->assertEquals('user1', $customer->name); + + $customer = $customerClass::find()->orderBy('id')->offset(0)->one(); + $this->assertEquals('user1', $customer->name); + + $customer = $customerClass::find()->orderBy('id')->offset(1)->one(); + $this->assertEquals('user2', $customer->name); + + $customer = $customerClass::find()->orderBy('id')->offset(2)->one(); + $this->assertEquals('user3', $customer->name); + + $customer = $customerClass::find()->offset(3)->one(); + $this->assertNull($customer); + + } + + public function testFindComplexCondition() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + $this->assertEquals(2, $customerClass::find()->where(['OR', ['name' => 'user1'], ['name' => 'user2']])->count()); + $this->assertEquals(2, count($customerClass::find()->where(['OR', ['name' => 'user1'], ['name' => 'user2']])->all())); + + $this->assertEquals(2, $customerClass::find()->where(['name' => ['user1', 'user2']])->count()); + $this->assertEquals(2, count($customerClass::find()->where(['name' => ['user1', 'user2']])->all())); + + $this->assertEquals(1, $customerClass::find()->where(['AND', ['name' => ['user2', 'user3']], ['BETWEEN', 'status', 2, 4]])->count()); + $this->assertEquals(1, count($customerClass::find()->where(['AND', ['name' => ['user2', 'user3']], ['BETWEEN', 'status', 2, 4]])->all())); + } + + public function testFindNullValues() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + $customer = $customerClass::findOne(2); + $customer->name = null; + $customer->save(false); + $this->afterSave(); + + $result = $customerClass::find()->where(['name' => null])->all(); + $this->assertEquals(1, count($result)); + $this->assertEquals(2, reset($result)->primaryKey); + } + + public function testExists() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + $this->assertTrue($customerClass::find()->where(['id' => 2])->exists()); + $this->assertFalse($customerClass::find()->where(['id' => 5])->exists()); + $this->assertTrue($customerClass::find()->where(['name' => 'user1'])->exists()); + $this->assertFalse($customerClass::find()->where(['name' => 'user5'])->exists()); + + $this->assertTrue($customerClass::find()->where(['id' => [2, 3]])->exists()); + $this->assertTrue($customerClass::find()->where(['id' => [2, 3]])->offset(1)->exists()); + $this->assertFalse($customerClass::find()->where(['id' => [2, 3]])->offset(2)->exists()); + } + + public function testFindLazy() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + $customer = $customerClass::findOne(2); + $this->assertFalse($customer->isRelationPopulated('orders')); + $orders = $customer->orders; + $this->assertTrue($customer->isRelationPopulated('orders')); + $this->assertEquals(2, count($orders)); + $this->assertEquals(1, count($customer->relatedRecords)); + + // unset + unset($customer['orders']); + $this->assertFalse($customer->isRelationPopulated('orders')); + + /* @var $customer Customer */ + $customer = $customerClass::findOne(2); + $this->assertFalse($customer->isRelationPopulated('orders')); + $orders = $customer->getOrders()->where(['id' => 3])->all(); + $this->assertFalse($customer->isRelationPopulated('orders')); + $this->assertEquals(0, count($customer->relatedRecords)); + + $this->assertEquals(1, count($orders)); + $this->assertEquals(3, $orders[0]->id); + } + + public function testFindEager() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $orderClass \yii\db\ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + $customers = $customerClass::find()->with('orders')->indexBy('id')->all(); + ksort($customers); + $this->assertEquals(3, count($customers)); + $this->assertTrue($customers[1]->isRelationPopulated('orders')); + $this->assertTrue($customers[2]->isRelationPopulated('orders')); + $this->assertTrue($customers[3]->isRelationPopulated('orders')); + $this->assertEquals(1, count($customers[1]->orders)); + $this->assertEquals(2, count($customers[2]->orders)); + $this->assertEquals(0, count($customers[3]->orders)); + // unset + unset($customers[1]->orders); + $this->assertFalse($customers[1]->isRelationPopulated('orders')); + + $customer = $customerClass::find()->where(['id' => 1])->with('orders')->one(); + $this->assertTrue($customer->isRelationPopulated('orders')); + $this->assertEquals(1, count($customer->orders)); + $this->assertEquals(1, count($customer->relatedRecords)); + + // multiple with() calls + $orders = $orderClass::find()->with('customer', 'items')->all(); + $this->assertEquals(3, count($orders)); + $this->assertTrue($orders[0]->isRelationPopulated('customer')); + $this->assertTrue($orders[0]->isRelationPopulated('items')); + $orders = $orderClass::find()->with('customer')->with('items')->all(); + $this->assertEquals(3, count($orders)); + $this->assertTrue($orders[0]->isRelationPopulated('customer')); + $this->assertTrue($orders[0]->isRelationPopulated('items')); + } + + public function testFindLazyVia() + { + /* @var $orderClass \yii\db\ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + /* @var $order Order */ + $order = $orderClass::findOne(1); + $this->assertEquals(1, $order->id); + $this->assertEquals(2, count($order->items)); + $this->assertEquals(1, $order->items[0]->id); + $this->assertEquals(2, $order->items[1]->id); + } + + public function testFindLazyVia2() + { + /* @var $orderClass \yii\db\ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + /* @var $order Order */ + $order = $orderClass::findOne(1); + $order->id = 100; + $this->assertEquals([], $order->items); + } + + public function testFindEagerViaRelation() + { + /* @var $orderClass \yii\db\ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + $orders = $orderClass::find()->with('items')->orderBy('id')->all(); + $this->assertEquals(3, count($orders)); + $order = $orders[0]; + $this->assertEquals(1, $order->id); + $this->assertTrue($order->isRelationPopulated('items')); + $this->assertEquals(2, count($order->items)); + $this->assertEquals(1, $order->items[0]->id); + $this->assertEquals(2, $order->items[1]->id); + } + + public function testFindNestedRelation() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + $customers = $customerClass::find()->with('orders', 'orders.items')->indexBy('id')->all(); + ksort($customers); + $this->assertEquals(3, count($customers)); + $this->assertTrue($customers[1]->isRelationPopulated('orders')); + $this->assertTrue($customers[2]->isRelationPopulated('orders')); + $this->assertTrue($customers[3]->isRelationPopulated('orders')); + $this->assertEquals(1, count($customers[1]->orders)); + $this->assertEquals(2, count($customers[2]->orders)); + $this->assertEquals(0, count($customers[3]->orders)); + $this->assertTrue($customers[1]->orders[0]->isRelationPopulated('items')); + $this->assertTrue($customers[2]->orders[0]->isRelationPopulated('items')); + $this->assertTrue($customers[2]->orders[1]->isRelationPopulated('items')); + $this->assertEquals(2, count($customers[1]->orders[0]->items)); + $this->assertEquals(3, count($customers[2]->orders[0]->items)); + $this->assertEquals(1, count($customers[2]->orders[1]->items)); + } + + /** + * Ensure ActiveRelationTrait does preserve order of items on find via() + * https://github.com/yiisoft/yii2/issues/1310 + */ + public function testFindEagerViaRelationPreserveOrder() + { + /* @var $orderClass \yii\db\ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + + /* + Item (name, category_id) + Order (customer_id, created_at, total) + OrderItem (order_id, item_id, quantity, subtotal) + + Result should be the following: + + Order 1: 1, 1325282384, 110.0 + - orderItems: + OrderItem: 1, 1, 1, 30.0 + OrderItem: 1, 2, 2, 40.0 + - itemsInOrder: + Item 1: 'Agile Web Application Development with Yii1.1 and PHP5', 1 + Item 2: 'Yii 1.1 Application Development Cookbook', 1 + + Order 2: 2, 1325334482, 33.0 + - orderItems: + OrderItem: 2, 3, 1, 8.0 + OrderItem: 2, 4, 1, 10.0 + OrderItem: 2, 5, 1, 15.0 + - itemsInOrder: + Item 5: 'Cars', 2 + Item 3: 'Ice Age', 2 + Item 4: 'Toy Story', 2 + Order 3: 2, 1325502201, 40.0 + - orderItems: + OrderItem: 3, 2, 1, 40.0 + - itemsInOrder: + Item 3: 'Ice Age', 2 + */ + $orders = $orderClass::find()->with('itemsInOrder1')->orderBy('created_at')->all(); + $this->assertEquals(3, count($orders)); + + $order = $orders[0]; + $this->assertEquals(1, $order->id); + $this->assertTrue($order->isRelationPopulated('itemsInOrder1')); + $this->assertEquals(2, count($order->itemsInOrder1)); + $this->assertEquals(1, $order->itemsInOrder1[0]->id); + $this->assertEquals(2, $order->itemsInOrder1[1]->id); + + $order = $orders[1]; + $this->assertEquals(2, $order->id); + $this->assertTrue($order->isRelationPopulated('itemsInOrder1')); + $this->assertEquals(3, count($order->itemsInOrder1)); + $this->assertEquals(5, $order->itemsInOrder1[0]->id); + $this->assertEquals(3, $order->itemsInOrder1[1]->id); + $this->assertEquals(4, $order->itemsInOrder1[2]->id); + + $order = $orders[2]; + $this->assertEquals(3, $order->id); + $this->assertTrue($order->isRelationPopulated('itemsInOrder1')); + $this->assertEquals(1, count($order->itemsInOrder1)); + $this->assertEquals(2, $order->itemsInOrder1[0]->id); + } + + // different order in via table + public function testFindEagerViaRelationPreserveOrderB() + { + /* @var $orderClass \yii\db\ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + + $orders = $orderClass::find()->with('itemsInOrder2')->orderBy('created_at')->all(); + $this->assertEquals(3, count($orders)); + + $order = $orders[0]; + $this->assertEquals(1, $order->id); + $this->assertTrue($order->isRelationPopulated('itemsInOrder2')); + $this->assertEquals(2, count($order->itemsInOrder2)); + $this->assertEquals(1, $order->itemsInOrder2[0]->id); + $this->assertEquals(2, $order->itemsInOrder2[1]->id); + + $order = $orders[1]; + $this->assertEquals(2, $order->id); + $this->assertTrue($order->isRelationPopulated('itemsInOrder2')); + $this->assertEquals(3, count($order->itemsInOrder2)); + $this->assertEquals(5, $order->itemsInOrder2[0]->id); + $this->assertEquals(3, $order->itemsInOrder2[1]->id); + $this->assertEquals(4, $order->itemsInOrder2[2]->id); + + $order = $orders[2]; + $this->assertEquals(3, $order->id); + $this->assertTrue($order->isRelationPopulated('itemsInOrder2')); + $this->assertEquals(1, count($order->itemsInOrder2)); + $this->assertEquals(2, $order->itemsInOrder2[0]->id); + } + + public function testLink() + { + /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $itemClass \yii\db\ActiveRecordInterface */ + /* @var $orderItemClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + $orderClass = $this->getOrderClass(); + $orderItemClass = $this->getOrderItemClass(); + $itemClass = $this->getItemClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + $customer = $customerClass::findOne(2); + $this->assertEquals(2, count($customer->orders)); + + // has many + $order = new $orderClass; + $order->total = 100; + $this->assertTrue($order->isNewRecord); + $customer->link('orders', $order); + $this->afterSave(); + $this->assertEquals(3, count($customer->orders)); + $this->assertFalse($order->isNewRecord); + $this->assertEquals(3, count($customer->getOrders()->all())); + $this->assertEquals(2, $order->customer_id); + + // belongs to + $order = new $orderClass; + $order->total = 100; + $this->assertTrue($order->isNewRecord); + $customer = $customerClass::findOne(1); + $this->assertNull($order->customer); + $order->link('customer', $customer); + $this->assertFalse($order->isNewRecord); + $this->assertEquals(1, $order->customer_id); + $this->assertEquals(1, $order->customer->primaryKey); + + // via model + $order = $orderClass::findOne(1); + $this->assertEquals(2, count($order->items)); + $this->assertEquals(2, count($order->orderItems)); + $orderItem = $orderItemClass::findOne(['order_id' => 1, 'item_id' => 3]); + $this->assertNull($orderItem); + $item = $itemClass::findOne(3); + $order->link('items', $item, ['quantity' => 10, 'subtotal' => 100]); + $this->afterSave(); + $this->assertEquals(3, count($order->items)); + $this->assertEquals(3, count($order->orderItems)); + $orderItem = $orderItemClass::findOne(['order_id' => 1, 'item_id' => 3]); + $this->assertTrue($orderItem instanceof $orderItemClass); + $this->assertEquals(10, $orderItem->quantity); + $this->assertEquals(100, $orderItem->subtotal); + } + + public function testUnlink() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $orderClass \yii\db\ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + /* @var $orderWithNullFKClass \yii\db\ActiveRecordInterface */ + $orderWithNullFKClass = $this->getOrderWithNullFKClass(); + /* @var $orderItemsWithNullFKClass \yii\db\ActiveRecordInterface */ + $orderItemsWithNullFKClass = $this->getOrderItemWithNullFKmClass(); + + + + /* @var $this TestCase|ActiveRecordTestTrait */ + // has many without delete + $customer = $customerClass::findOne(2); + $this->assertEquals(2, count($customer->ordersWithNullFK)); + $customer->unlink('ordersWithNullFK', $customer->ordersWithNullFK[1], false); + + $this->assertEquals(1, count($customer->ordersWithNullFK)); + $orderWithNullFK = $orderWithNullFKClass::findOne(3); + + $this->assertEquals(3,$orderWithNullFK->id); + $this->assertNull($orderWithNullFK->customer_id); + + // has many with delete + $customer = $customerClass::findOne(2); + $this->assertEquals(2, count($customer->orders)); + $customer->unlink('orders', $customer->orders[1], true); + $this->afterSave(); + + $this->assertEquals(1, count($customer->orders)); + $this->assertNull($orderClass::findOne(3)); + + // via model with delete + $order = $orderClass::findOne(2); + $this->assertEquals(3, count($order->items)); + $this->assertEquals(3, count($order->orderItems)); + $order->unlink('items', $order->items[2], true); + $this->afterSave(); + + $this->assertEquals(2, count($order->items)); + $this->assertEquals(2, count($order->orderItems)); + + // via model without delete + $this->assertEquals(3, count($order->itemsWithNullFK)); + $order->unlink('itemsWithNullFK', $order->itemsWithNullFK[2], false); + $this->afterSave(); + + $this->assertEquals(2, count($order->itemsWithNullFK)); + $this->assertEquals(2, count($order->orderItems)); + } + + public function testUnlinkAll() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $orderClass \yii\db\ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + /* @var $orderItemClass \yii\db\ActiveRecordInterface */ + $orderItemClass = $this->getOrderItemClass(); + /* @var $itemClass \yii\db\ActiveRecordInterface */ + $itemClass = $this->getItemClass(); + /* @var $orderWithNullFKClass \yii\db\ActiveRecordInterface */ + $orderWithNullFKClass = $this->getOrderWithNullFKClass(); + /* @var $orderItemsWithNullFKClass \yii\db\ActiveRecordInterface */ + $orderItemsWithNullFKClass = $this->getOrderItemWithNullFKmClass(); + + /* @var $this TestCase|ActiveRecordTestTrait */ + // has many with delete + $customer = $customerClass::findOne(2); + $this->assertEquals(2, count($customer->orders)); + $this->assertEquals(3, $orderClass::find()->count()); + $customer->unlinkAll('orders', true); + $this->afterSave(); + $this->assertEquals(1, $orderClass::find()->count()); + $this->assertEquals(0, count($customer->orders)); + + $this->assertNull($orderClass::findOne(2)); + $this->assertNull($orderClass::findOne(3)); + + + // has many without delete + $customer = $customerClass::findOne(2); + $this->assertEquals(2, count($customer->ordersWithNullFK)); + $this->assertEquals(3, $orderWithNullFKClass::find()->count()); + $customer->unlinkAll('ordersWithNullFK', false); + $this->afterSave(); + $this->assertEquals(0, count($customer->ordersWithNullFK)); + $this->assertEquals(3, $orderWithNullFKClass::find()->count()); + $this->assertEquals(2, $orderWithNullFKClass::find()->where(['AND', ['id' => [2, 3]], ['customer_id' => null]])->count()); + + + // via model with delete + /* @var $order Order */ + $order = $orderClass::findOne(1); + $this->assertEquals(2, count($order->books)); + $orderItemCount = $orderItemClass::find()->count(); + $this->assertEquals(5, $itemClass::find()->count()); + $order->unlinkAll('books', true); + $this->afterSave(); + $this->assertEquals(5, $itemClass::find()->count()); + $this->assertEquals($orderItemCount - 2, $orderItemClass::find()->count()); + $this->assertEquals(0, count($order->books)); + + // via model without delete + $this->assertEquals(2, count($order->booksWithNullFK)); + $orderItemCount = $orderItemsWithNullFKClass::find()->count(); + $this->assertEquals(5, $itemClass::find()->count()); + $order->unlinkAll('booksWithNullFK',false); + $this->afterSave(); + $this->assertEquals(0, count($order->booksWithNullFK)); + $this->assertEquals(2, $orderItemsWithNullFKClass::find()->where(['AND', ['item_id' => [1, 2]], ['order_id' => null]])->count()); + $this->assertEquals($orderItemCount, $orderItemsWithNullFKClass::find()->count()); + $this->assertEquals(5, $itemClass::find()->count()); + + // via table is covered in \yiiunit\framework\db\ActiveRecordTest::testUnlinkAllViaTable() + } + + public function testUnlinkAllAndConditionSetNull() + { + /* @var $this TestCase|ActiveRecordTestTrait */ + + /* @var $customerClass \yii\db\BaseActiveRecord */ + $customerClass = $this->getCustomerClass(); + /* @var $orderClass \yii\db\BaseActiveRecord */ + $orderClass = $this->getOrderWithNullFKClass(); + + // in this test all orders are owned by customer 1 + $orderClass::updateAll(['customer_id' => 1]); + $this->afterSave(); + + $customer = $customerClass::findOne(1); + $this->assertEquals(3, count($customer->ordersWithNullFK)); + $this->assertEquals(1, count($customer->expensiveOrdersWithNullFK)); + $this->assertEquals(3, $orderClass::find()->count()); + $customer->unlinkAll('expensiveOrdersWithNullFK'); + $this->assertEquals(3, count($customer->ordersWithNullFK)); + $this->assertEquals(0, count($customer->expensiveOrdersWithNullFK)); + $this->assertEquals(3, $orderClass::find()->count()); + $customer = $customerClass::findOne(1); + $this->assertEquals(2, count($customer->ordersWithNullFK)); + $this->assertEquals(0, count($customer->expensiveOrdersWithNullFK)); + } + + public function testUnlinkAllAndConditionDelete() + { + /* @var $this TestCase|ActiveRecordTestTrait */ + + /* @var $customerClass \yii\db\BaseActiveRecord */ + $customerClass = $this->getCustomerClass(); + /* @var $orderClass \yii\db\BaseActiveRecord */ + $orderClass = $this->getOrderClass(); + + // in this test all orders are owned by customer 1 + $orderClass::updateAll(['customer_id' => 1]); + $this->afterSave(); + + $customer = $customerClass::findOne(1); + $this->assertEquals(3, count($customer->orders)); + $this->assertEquals(1, count($customer->expensiveOrders)); + $this->assertEquals(3, $orderClass::find()->count()); + $customer->unlinkAll('expensiveOrders', true); + $this->assertEquals(3, count($customer->orders)); + $this->assertEquals(0, count($customer->expensiveOrders)); + $this->assertEquals(2, $orderClass::find()->count()); + $customer = $customerClass::findOne(1); + $this->assertEquals(2, count($customer->orders)); + $this->assertEquals(0, count($customer->expensiveOrders)); + } + + public static $afterSaveNewRecord; + public static $afterSaveInsert; + + public function testInsert() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + $customer = new $customerClass; + $customer->email = 'user4@example.com'; + $customer->name = 'user4'; + $customer->address = 'address4'; + + $this->assertNull($customer->id); + $this->assertTrue($customer->isNewRecord); + static::$afterSaveNewRecord = null; + static::$afterSaveInsert = null; + + $customer->save(); + $this->afterSave(); + + $this->assertNotNull($customer->id); + $this->assertFalse(static::$afterSaveNewRecord); + $this->assertTrue(static::$afterSaveInsert); + $this->assertFalse($customer->isNewRecord); + } + + public function testUpdate() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + // save + /* @var $customer Customer */ + $customer = $customerClass::findOne(2); + $this->assertTrue($customer instanceof $customerClass); + $this->assertEquals('user2', $customer->name); + $this->assertFalse($customer->isNewRecord); + static::$afterSaveNewRecord = null; + static::$afterSaveInsert = null; + $this->assertEmpty($customer->dirtyAttributes); + + $customer->name = 'user2x'; + $customer->save(); + $this->afterSave(); + $this->assertEquals('user2x', $customer->name); + $this->assertFalse($customer->isNewRecord); + $this->assertFalse(static::$afterSaveNewRecord); + $this->assertFalse(static::$afterSaveInsert); + $customer2 = $customerClass::findOne(2); + $this->assertEquals('user2x', $customer2->name); + + // updateAll + $customer = $customerClass::findOne(3); + $this->assertEquals('user3', $customer->name); + $ret = $customerClass::updateAll(['name' => 'temp'], ['id' => 3]); + $this->afterSave(); + $this->assertEquals(1, $ret); + $customer = $customerClass::findOne(3); + $this->assertEquals('temp', $customer->name); + + $ret = $customerClass::updateAll(['name' => 'tempX']); + $this->afterSave(); + $this->assertEquals(3, $ret); + + $ret = $customerClass::updateAll(['name' => 'temp'], ['name' => 'user6']); + $this->afterSave(); + $this->assertEquals(0, $ret); + } + + public function testUpdateAttributes() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + /* @var $customer Customer */ + $customer = $customerClass::findOne(2); + $this->assertTrue($customer instanceof $customerClass); + $this->assertEquals('user2', $customer->name); + $this->assertFalse($customer->isNewRecord); + static::$afterSaveNewRecord = null; + static::$afterSaveInsert = null; + + $customer->updateAttributes(['name' => 'user2x']); + $this->afterSave(); + $this->assertEquals('user2x', $customer->name); + $this->assertFalse($customer->isNewRecord); + $this->assertNull(static::$afterSaveNewRecord); + $this->assertNull(static::$afterSaveInsert); + $customer2 = $customerClass::findOne(2); + $this->assertEquals('user2x', $customer2->name); + + $customer = $customerClass::findOne(1); + $this->assertEquals('user1', $customer->name); + $this->assertEquals(1, $customer->status); + $customer->name = 'user1x'; + $customer->status = 2; + $customer->updateAttributes(['name']); + $this->assertEquals('user1x', $customer->name); + $this->assertEquals(2, $customer->status); + $customer = $customerClass::findOne(1); + $this->assertEquals('user1x', $customer->name); + $this->assertEquals(1, $customer->status); + } + + public function testUpdateCounters() + { + /* @var $orderItemClass \yii\db\ActiveRecordInterface */ + $orderItemClass = $this->getOrderItemClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + // updateCounters + $pk = ['order_id' => 2, 'item_id' => 4]; + $orderItem = $orderItemClass::findOne($pk); + $this->assertEquals(1, $orderItem->quantity); + $ret = $orderItem->updateCounters(['quantity' => -1]); + $this->afterSave(); + $this->assertEquals(1, $ret); + $this->assertEquals(0, $orderItem->quantity); + $orderItem = $orderItemClass::findOne($pk); + $this->assertEquals(0, $orderItem->quantity); + + // updateAllCounters + $pk = ['order_id' => 1, 'item_id' => 2]; + $orderItem = $orderItemClass::findOne($pk); + $this->assertEquals(2, $orderItem->quantity); + $ret = $orderItemClass::updateAllCounters([ + 'quantity' => 3, + 'subtotal' => -10, + ], $pk); + $this->afterSave(); + $this->assertEquals(1, $ret); + $orderItem = $orderItemClass::findOne($pk); + $this->assertEquals(5, $orderItem->quantity); + $this->assertEquals(30, $orderItem->subtotal); + } + + public function testDelete() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + // delete + $customer = $customerClass::findOne(2); + $this->assertTrue($customer instanceof $customerClass); + $this->assertEquals('user2', $customer->name); + $customer->delete(); + $this->afterSave(); + $customer = $customerClass::findOne(2); + $this->assertNull($customer); + + // deleteAll + $customers = $customerClass::find()->all(); + $this->assertEquals(2, count($customers)); + $ret = $customerClass::deleteAll(); + $this->afterSave(); + $this->assertEquals(2, $ret); + $customers = $customerClass::find()->all(); + $this->assertEquals(0, count($customers)); + + $ret = $customerClass::deleteAll(); + $this->afterSave(); + $this->assertEquals(0, $ret); + } + + /** + * Some PDO implementations(e.g. cubrid) do not support boolean values. + * Make sure this does not affect AR layer. + */ + public function testBooleanAttribute() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + $customer = new $customerClass(); + $customer->name = 'boolean customer'; + $customer->email = 'mail@example.com'; + $customer->status = true; + $customer->save(false); + + $customer->refresh(); + $this->assertEquals(1, $customer->status); + + $customer->status = false; + $customer->save(false); + + $customer->refresh(); + $this->assertEquals(0, $customer->status); + + $customers = $customerClass::find()->where(['status' => true])->all(); + $this->assertEquals(2, count($customers)); + + $customers = $customerClass::find()->where(['status' => false])->all(); + $this->assertEquals(1, count($customers)); + } + + public function testAfterFind() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $orderClass BaseActiveRecord */ + $orderClass = $this->getOrderClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + + $afterFindCalls = []; + Event::on(BaseActiveRecord::className(), BaseActiveRecord::EVENT_AFTER_FIND, function ($event) use (&$afterFindCalls) { + /* @var $ar BaseActiveRecord */ + $ar = $event->sender; + $afterFindCalls[] = [get_class($ar), $ar->getIsNewRecord(), $ar->getPrimaryKey(), $ar->isRelationPopulated('orders')]; + }); + + $customer = $customerClass::findOne(1); + $this->assertNotNull($customer); + $this->assertEquals([[$customerClass, false, 1, false]], $afterFindCalls); + $afterFindCalls = []; + + $customer = $customerClass::find()->where(['id' => 1])->one(); + $this->assertNotNull($customer); + $this->assertEquals([[$customerClass, false, 1, false]], $afterFindCalls); + $afterFindCalls = []; + + $customer = $customerClass::find()->where(['id' => 1])->all(); + $this->assertNotNull($customer); + $this->assertEquals([[$customerClass, false, 1, false]], $afterFindCalls); + $afterFindCalls = []; + + $customer = $customerClass::find()->where(['id' => 1])->with('orders')->all(); + $this->assertNotNull($customer); + $this->assertEquals([ + [$this->getOrderClass(), false, 1, false], + [$customerClass, false, 1, true], + ], $afterFindCalls); + $afterFindCalls = []; + + if ($this instanceof \yiiunit\extensions\redis\ActiveRecordTest) { // TODO redis does not support orderBy() yet + $customer = $customerClass::find()->where(['id' => [1, 2]])->with('orders')->all(); + } else { + // orderBy is needed to avoid random test failure + $customer = $customerClass::find()->where(['id' => [1, 2]])->with('orders')->orderBy('name')->all(); + } + $this->assertNotNull($customer); + $this->assertEquals([ + [$orderClass, false, 1, false], + [$orderClass, false, 2, false], + [$orderClass, false, 3, false], + [$customerClass, false, 1, true], + [$customerClass, false, 2, true], + ], $afterFindCalls); + $afterFindCalls = []; + + Event::off(BaseActiveRecord::className(), BaseActiveRecord::EVENT_AFTER_FIND); + } + + public function testFindEmptyInCondition() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + + $customers = $customerClass::find()->where(['id' => [1]])->all(); + $this->assertEquals(1, count($customers)); + + $customers = $customerClass::find()->where(['id' => []])->all(); + $this->assertEquals(0, count($customers)); + + $customers = $customerClass::find()->where(['IN', 'id', [1]])->all(); + $this->assertEquals(1, count($customers)); + + $customers = $customerClass::find()->where(['IN', 'id', []])->all(); + $this->assertEquals(0, count($customers)); + } + + public function testFindEagerIndexBy() + { + /* @var $this TestCase|ActiveRecordTestTrait */ + + /* @var $orderClass \yii\db\ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + + /* @var $order Order */ + $order = $orderClass::find()->with('itemsIndexed')->where(['id' => 1])->one(); + $this->assertTrue($order->isRelationPopulated('itemsIndexed')); + $items = $order->itemsIndexed; + $this->assertEquals(2, count($items)); + $this->assertTrue(isset($items[1])); + $this->assertTrue(isset($items[2])); + + /* @var $order Order */ + $order = $orderClass::find()->with('itemsIndexed')->where(['id' => 2])->one(); + $this->assertTrue($order->isRelationPopulated('itemsIndexed')); + $items = $order->itemsIndexed; + $this->assertEquals(3, count($items)); + $this->assertTrue(isset($items[3])); + $this->assertTrue(isset($items[4])); + $this->assertTrue(isset($items[5])); + } +} diff --git a/tests/framework/base/ActionFilterTest.php b/tests/framework/base/ActionFilterTest.php new file mode 100644 index 0000000..01820cc --- /dev/null +++ b/tests/framework/base/ActionFilterTest.php @@ -0,0 +1,164 @@ +mockApplication(); + } + + public function testFilter() + { + // no filters + $controller = new FakeController('fake', Yii::$app); + $this->assertNull($controller->result); + $result = $controller->runAction('test'); + $this->assertEquals('x', $result); + $this->assertNull($controller->result); + + // all filters pass + $controller = new FakeController('fake', Yii::$app, [ + 'behaviors' => [ + 'filter1' => Filter1::className(), + 'filter3' => Filter3::className(), + ], + ]); + $this->assertNull($controller->result); + $result = $controller->runAction('test'); + $this->assertEquals('x-3-1', $result); + $this->assertEquals([1, 3], $controller->result); + + // a filter stops in the middle + $controller = new FakeController('fake', Yii::$app, [ + 'behaviors' => [ + 'filter1' => Filter1::className(), + 'filter2' => Filter2::className(), + 'filter3' => Filter3::className(), + ], + ]); + $this->assertNull($controller->result); + $result = $controller->runAction('test'); + $this->assertNull($result); + $this->assertEquals([1, 2], $controller->result); + + // the first filter stops + $controller = new FakeController('fake', Yii::$app, [ + 'behaviors' => [ + 'filter2' => Filter2::className(), + 'filter1' => Filter1::className(), + 'filter3' => Filter3::className(), + ], + ]); + $this->assertNull($controller->result); + $result = $controller->runAction('test'); + $this->assertNull($result); + $this->assertEquals([2], $controller->result); + + // the last filter stops + $controller = new FakeController('fake', Yii::$app, [ + 'behaviors' => [ + 'filter1' => Filter1::className(), + 'filter3' => Filter3::className(), + 'filter2' => Filter2::className(), + ], + ]); + $this->assertNull($controller->result); + $result = $controller->runAction('test'); + $this->assertNull($result); + $this->assertEquals([1, 3, 2], $controller->result); + } +} + +class FakeController extends Controller +{ + public $result; + public $behaviors = []; + + public function behaviors() + { + return $this->behaviors; + } + + public function actionTest() + { + return 'x'; + } +} + +class Filter1 extends ActionFilter +{ + /** + * @inheritdoc + */ + public function beforeAction($action) + { + $action->controller->result[] = 1; + return true; + } + + /** + * @inheritdoc + */ + public function afterAction($action, $result) + { + return $result . '-1'; + } +} + +class Filter2 extends ActionFilter +{ + /** + * @inheritdoc + */ + public function beforeAction($action) + { + $action->controller->result[] = 2; + return false; + } + + /** + * @inheritdoc + */ + public function afterAction($action, $result) + { + return $result . '-2'; + } +} + +class Filter3 extends ActionFilter +{ + /** + * @inheritdoc + */ + public function beforeAction($action) + { + $action->controller->result[] = 3; + return true; + } + + /** + * @inheritdoc + */ + public function afterAction($action, $result) + { + return $result . '-3'; + } +} + diff --git a/tests/framework/base/BehaviorTest.php b/tests/framework/base/BehaviorTest.php new file mode 100644 index 0000000..9a950f6 --- /dev/null +++ b/tests/framework/base/BehaviorTest.php @@ -0,0 +1,107 @@ + __NAMESPACE__ . '\BarBehavior', + ]; + } +} + +class BarBehavior extends Behavior +{ + public $behaviorProperty = 'behavior property'; + + public function behaviorMethod() + { + return 'behavior method'; + } + + public function __call($name, $params) + { + if ($name == 'magicBehaviorMethod') { + return 'Magic Behavior Method Result!'; + } + + return parent::__call($name, $params); + } + + public function hasMethod($name) + { + if ($name == 'magicBehaviorMethod') { + return true; + } + + return parent::hasMethod($name); + } +} + +/** + * @group base + */ +class BehaviorTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + + public function testAttachAndAccessing() + { + $bar = new BarClass(); + $behavior = new BarBehavior(); + $bar->attachBehavior('bar', $behavior); + $this->assertEquals('behavior property', $bar->behaviorProperty); + $this->assertEquals('behavior method', $bar->behaviorMethod()); + $this->assertEquals('behavior property', $bar->getBehavior('bar')->behaviorProperty); + $this->assertEquals('behavior method', $bar->getBehavior('bar')->behaviorMethod()); + + $behavior = new BarBehavior(['behaviorProperty' => 'reattached']); + $bar->attachBehavior('bar', $behavior); + $this->assertEquals('reattached', $bar->behaviorProperty); + } + + public function testAutomaticAttach() + { + $foo = new FooClass(); + $this->assertEquals('behavior property', $foo->behaviorProperty); + $this->assertEquals('behavior method', $foo->behaviorMethod()); + } + + public function testMagicMethods() + { + $bar = new BarClass(); + $behavior = new BarBehavior(); + + $this->assertFalse($bar->hasMethod('magicBehaviorMethod')); + $bar->attachBehavior('bar', $behavior); + $this->assertFalse($bar->hasMethod('magicBehaviorMethod', false)); + $this->assertTrue($bar->hasMethod('magicBehaviorMethod')); + + $this->assertEquals('Magic Behavior Method Result!', $bar->magicBehaviorMethod()); + } + + public function testCallUnknownMethod() + { + $bar = new BarClass(); + $behavior = new BarBehavior(); + $this->setExpectedException('yii\base\UnknownMethodException'); + + $this->assertFalse($bar->hasMethod('nomagicBehaviorMethod')); + $bar->attachBehavior('bar', $behavior); + $bar->nomagicBehaviorMethod(); + } +} diff --git a/tests/framework/base/ComponentTest.php b/tests/framework/base/ComponentTest.php new file mode 100644 index 0000000..e95d387 --- /dev/null +++ b/tests/framework/base/ComponentTest.php @@ -0,0 +1,451 @@ +sender->eventHandled = true; +} + +function globalEventHandler2($event) +{ + $event->sender->eventHandled = true; + $event->handled = true; +} + +/** + * @group base + */ +class ComponentTest extends TestCase +{ + /** + * @var NewComponent + */ + protected $component; + + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + $this->component = new NewComponent(); + } + + protected function tearDown() + { + parent::tearDown(); + $this->component = null; + } + + public function testClone() + { + $component = new NewComponent(); + $behavior = new NewBehavior(); + $component->attachBehavior('a', $behavior); + $this->assertSame($behavior, $component->getBehavior('a')); + $component->on('test', 'fake'); + $this->assertTrue($component->hasEventHandlers('test')); + + $clone = clone $component; + $this->assertNotSame($component, $clone); + $this->assertNull($clone->getBehavior('a')); + $this->assertFalse($clone->hasEventHandlers('test')); + } + + public function testHasProperty() + { + $this->assertTrue($this->component->hasProperty('Text')); + $this->assertTrue($this->component->hasProperty('text')); + $this->assertFalse($this->component->hasProperty('Caption')); + $this->assertTrue($this->component->hasProperty('content')); + $this->assertFalse($this->component->hasProperty('content', false)); + $this->assertFalse($this->component->hasProperty('Content')); + } + + public function testCanGetProperty() + { + $this->assertTrue($this->component->canGetProperty('Text')); + $this->assertTrue($this->component->canGetProperty('text')); + $this->assertFalse($this->component->canGetProperty('Caption')); + $this->assertTrue($this->component->canGetProperty('content')); + $this->assertFalse($this->component->canGetProperty('content', false)); + $this->assertFalse($this->component->canGetProperty('Content')); + } + + public function testCanSetProperty() + { + $this->assertTrue($this->component->canSetProperty('Text')); + $this->assertTrue($this->component->canSetProperty('text')); + $this->assertFalse($this->component->canSetProperty('Object')); + $this->assertFalse($this->component->canSetProperty('Caption')); + $this->assertTrue($this->component->canSetProperty('content')); + $this->assertFalse($this->component->canSetProperty('content', false)); + $this->assertFalse($this->component->canSetProperty('Content')); + + // behavior + $this->assertFalse($this->component->canSetProperty('p2')); + $behavior = new NewBehavior(); + $this->component->attachBehavior('a', $behavior); + $this->assertTrue($this->component->canSetProperty('p2')); + $this->component->detachBehavior('a'); + } + + public function testGetProperty() + { + $this->assertTrue('default' === $this->component->Text); + $this->setExpectedException('yii\base\UnknownPropertyException'); + $value2 = $this->component->Caption; + } + + public function testSetProperty() + { + $value = 'new value'; + $this->component->Text = $value; + $this->assertEquals($value, $this->component->Text); + $this->setExpectedException('yii\base\UnknownPropertyException'); + $this->component->NewMember = $value; + } + + public function testIsset() + { + $this->assertTrue(isset($this->component->Text)); + $this->assertFalse(empty($this->component->Text)); + + $this->component->Text = ''; + $this->assertTrue(isset($this->component->Text)); + $this->assertTrue(empty($this->component->Text)); + + $this->component->Text = null; + $this->assertFalse(isset($this->component->Text)); + $this->assertTrue(empty($this->component->Text)); + + $this->assertFalse(isset($this->component->p2)); + $this->component->attachBehavior('a', new NewBehavior()); + $this->component->setP2('test'); + $this->assertTrue(isset($this->component->p2)); + } + + public function testCallUnknownMethod() + { + $this->setExpectedException('yii\base\UnknownMethodException'); + $this->component->unknownMethod(); + } + + public function testUnset() + { + unset($this->component->Text); + $this->assertFalse(isset($this->component->Text)); + $this->assertTrue(empty($this->component->Text)); + + $this->component->attachBehavior('a', new NewBehavior()); + $this->component->setP2('test'); + $this->assertEquals('test', $this->component->getP2()); + + unset($this->component->p2); + $this->assertNull($this->component->getP2()); + } + + public function testUnsetReadonly() + { + $this->setExpectedException('yii\base\InvalidCallException'); + unset($this->component->object); + } + + public function testOn() + { + $this->assertFalse($this->component->hasEventHandlers('click')); + $this->component->on('click', 'foo'); + $this->assertTrue($this->component->hasEventHandlers('click')); + + $this->assertFalse($this->component->hasEventHandlers('click2')); + $p = 'on click2'; + $this->component->$p = 'foo2'; + $this->assertTrue($this->component->hasEventHandlers('click2')); + } + + public function testOff() + { + $this->assertFalse($this->component->hasEventHandlers('click')); + $this->component->on('click', 'foo'); + $this->assertTrue($this->component->hasEventHandlers('click')); + $this->component->off('click', 'foo'); + $this->assertFalse($this->component->hasEventHandlers('click')); + + $this->component->on('click2', 'foo'); + $this->component->on('click2', 'foo2'); + $this->component->on('click2', 'foo3'); + $this->assertTrue($this->component->hasEventHandlers('click2')); + $this->component->off('click2', 'foo3'); + $this->assertTrue($this->component->hasEventHandlers('click2')); + $this->component->off('click2'); + $this->assertFalse($this->component->hasEventHandlers('click2')); + } + + public function testTrigger() + { + $this->component->on('click', [$this->component, 'myEventHandler']); + $this->assertFalse($this->component->eventHandled); + $this->assertNull($this->component->event); + $this->component->raiseEvent(); + $this->assertTrue($this->component->eventHandled); + $this->assertEquals('click', $this->component->event->name); + $this->assertEquals($this->component, $this->component->event->sender); + $this->assertFalse($this->component->event->handled); + + $eventRaised = false; + $this->component->on('click', function ($event) use (&$eventRaised) { + $eventRaised = true; + }); + $this->component->raiseEvent(); + $this->assertTrue($eventRaised); + + // raise event w/o parameters + $eventRaised = false; + $this->component->on('test', function ($event) use (&$eventRaised) { + $eventRaised = true; + }); + $this->component->trigger('test'); + $this->assertTrue($eventRaised); + } + + public function testHasEventHandlers() + { + $this->assertFalse($this->component->hasEventHandlers('click')); + $this->component->on('click', 'foo'); + $this->assertTrue($this->component->hasEventHandlers('click')); + } + + public function testStopEvent() + { + $component = new NewComponent; + $component->on('click', 'yiiunit\framework\base\globalEventHandler2'); + $component->on('click', [$this->component, 'myEventHandler']); + $component->raiseEvent(); + $this->assertTrue($component->eventHandled); + $this->assertFalse($this->component->eventHandled); + } + + public function testAttachBehavior() + { + $component = new NewComponent; + $this->assertFalse($component->hasProperty('p')); + $this->assertFalse($component->behaviorCalled); + $this->assertNull($component->getBehavior('a')); + + $behavior = new NewBehavior; + $component->attachBehavior('a', $behavior); + $this->assertSame($behavior, $component->getBehavior('a')); + $this->assertTrue($component->hasProperty('p')); + $component->test(); + $this->assertTrue($component->behaviorCalled); + + $this->assertSame($behavior, $component->detachBehavior('a')); + $this->assertFalse($component->hasProperty('p')); + $this->setExpectedException('yii\base\UnknownMethodException'); + $component->test(); + + $p = 'as b'; + $component = new NewComponent; + $component->$p = ['class' => 'NewBehavior']; + $this->assertSame($behavior, $component->getBehavior('a')); + $this->assertTrue($component->hasProperty('p')); + $component->test(); + $this->assertTrue($component->behaviorCalled); + } + + public function testAttachBehaviors() + { + $component = new NewComponent; + $this->assertNull($component->getBehavior('a')); + $this->assertNull($component->getBehavior('b')); + + $behavior = new NewBehavior; + + $component->attachBehaviors([ + 'a' => $behavior, + 'b' => $behavior, + ]); + + $this->assertSame(['a' => $behavior, 'b' => $behavior], $component->getBehaviors()); + } + + public function testDetachBehavior() + { + $component = new NewComponent; + $behavior = new NewBehavior; + + $component->attachBehavior('a', $behavior); + $this->assertSame($behavior, $component->getBehavior('a')); + + $detachedBehavior = $component->detachBehavior('a'); + $this->assertSame($detachedBehavior, $behavior); + $this->assertNull($component->getBehavior('a')); + + $detachedBehavior = $component->detachBehavior('z'); + $this->assertNull($detachedBehavior); + } + + public function testDetachBehaviors() + { + $component = new NewComponent; + $behavior = new NewBehavior; + + $component->attachBehavior('a', $behavior); + $this->assertSame($behavior, $component->getBehavior('a')); + $component->attachBehavior('b', $behavior); + $this->assertSame($behavior, $component->getBehavior('b')); + + $component->detachBehaviors(); + $this->assertNull($component->getBehavior('a')); + $this->assertNull($component->getBehavior('b')); + } + + public function testSetReadOnlyProperty() + { + $this->setExpectedException( + '\yii\base\InvalidCallException', + 'Setting read-only property: yiiunit\framework\base\NewComponent::object' + ); + $this->component->object = 'z'; + } + + public function testSetPropertyOfBehavior() + { + $this->assertNull($this->component->getBehavior('a')); + + $behavior = new NewBehavior; + $this->component->attachBehaviors([ + 'a' => $behavior, + ]); + $this->component->p = 'Yii is cool.'; + + $this->assertSame('Yii is cool.', $this->component->getBehavior('a')->p); + } + + public function testSettingBehaviorWithSetter() + { + $behaviorName = 'foo'; + $this->assertNull($this->component->getBehavior($behaviorName)); + $p = 'as ' . $behaviorName; + $this->component->$p = __NAMESPACE__ . '\NewBehavior'; + $this->assertSame(__NAMESPACE__ . '\NewBehavior', get_class($this->component->getBehavior($behaviorName))); + } + + public function testWriteOnlyProperty() + { + $this->setExpectedException( + '\yii\base\InvalidCallException', + 'Getting write-only property: yiiunit\framework\base\NewComponent::writeOnly' + ); + $this->component->writeOnly; + } + + public function testSuccessfulMethodCheck() + { + $this->assertTrue($this->component->hasMethod('hasProperty')); + } + + public function testTurningOffNonExistingBehavior() + { + $this->assertFalse($this->component->hasEventHandlers('foo')); + $this->assertFalse($this->component->off('foo')); + } +} + +class NewComponent extends Component +{ + private $_object = null; + private $_text = 'default'; + private $_items = []; + public $content; + + public function getText() + { + return $this->_text; + } + + public function setText($value) + { + $this->_text = $value; + } + + public function getObject() + { + if (!$this->_object) { + $this->_object = new self; + $this->_object->_text = 'object text'; + } + + return $this->_object; + } + + public function getExecute() + { + return function ($param) { + return $param * 2; + }; + } + + public function getItems() + { + return $this->_items; + } + + public $eventHandled = false; + public $event; + public $behaviorCalled = false; + + public function myEventHandler($event) + { + $this->eventHandled = true; + $this->event = $event; + } + + public function raiseEvent() + { + $this->trigger('click', new Event); + } + + public function setWriteOnly() + { + } +} + +class NewBehavior extends Behavior +{ + public $p; + private $p2; + + public function getP2() + { + return $this->p2; + } + + public function setP2($value) + { + $this->p2 = $value; + } + + public function test() + { + $this->owner->behaviorCalled = true; + + return 2; + } +} + +class NewComponent2 extends Component +{ + public $a; + public $b; + public $c; + + public function __construct($b, $c) + { + $this->b = $b; + $this->c = $c; + } +} diff --git a/tests/framework/base/DynamicModelTest.php b/tests/framework/base/DynamicModelTest.php new file mode 100644 index 0000000..534f372 --- /dev/null +++ b/tests/framework/base/DynamicModelTest.php @@ -0,0 +1,80 @@ + + * @since 2.0 + */ +class DynamicModelTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + + public function testValidateData() + { + $email = 'invalid'; + $name = 'long name'; + $age = ''; + $model = DynamicModel::validateData(compact('name', 'email', 'age'), [ + [['email', 'name', 'age'], 'required'], + ['email', 'email'], + ['name', 'string', 'max' => 3], + ]); + $this->assertTrue($model->hasErrors()); + $this->assertTrue($model->hasErrors('email')); + $this->assertTrue($model->hasErrors('name')); + $this->assertTrue($model->hasErrors('age')); + } + + public function testAddRule() + { + $model = new DynamicModel(); + $this->assertEquals(0, $model->getValidators()->count()); + $model->addRule('name', 'string', ['min' => 12]); + $this->assertEquals(1, $model->getValidators()->count()); + $model->addRule('email', 'email'); + $this->assertEquals(2, $model->getValidators()->count()); + $model->addRule(['name', 'email'], 'required'); + $this->assertEquals(3, $model->getValidators()->count()); + } + + public function testValidateWithAddRule() + { + $email = 'invalid'; + $name = 'long name'; + $age = ''; + $model = new DynamicModel(compact('name', 'email', 'age')); + $model->addRule(['email', 'name', 'age'], 'required') + ->addRule('email', 'email') + ->addRule('name', 'string', ['max' => 3]) + ->validate(); + $this->assertTrue($model->hasErrors()); + $this->assertTrue($model->hasErrors('email')); + $this->assertTrue($model->hasErrors('name')); + $this->assertTrue($model->hasErrors('age')); + } + + public function testDynamicProperty() + { + $email = 'invalid'; + $name = 'long name'; + $model = new DynamicModel(compact('name', 'email')); + $this->assertEquals($email, $model->email); + $this->assertEquals($name, $model->name); + $this->setExpectedException('yii\base\UnknownPropertyException'); + $age = $model->age; + } +} diff --git a/tests/framework/base/EventTest.php b/tests/framework/base/EventTest.php new file mode 100644 index 0000000..8fda502 --- /dev/null +++ b/tests/framework/base/EventTest.php @@ -0,0 +1,92 @@ + + * @since 2.0 + */ +class EventTest extends TestCase +{ + public $counter; + + public function setUp() + { + $this->counter = 0; + Event::off(ActiveRecord::className(), 'save'); + Event::off(Post::className(), 'save'); + Event::off(User::className(), 'save'); + } + + public function testOn() + { + Event::on(Post::className(), 'save', function ($event) { + $this->counter += 1; + }); + Event::on(ActiveRecord::className(), 'save', function ($event) { + $this->counter += 3; + }); + $this->assertEquals(0, $this->counter); + $post = new Post; + $post->save(); + $this->assertEquals(4, $this->counter); + $user = new User; + $user->save(); + $this->assertEquals(7, $this->counter); + } + + public function testOff() + { + $handler = function ($event) { + $this->counter ++; + }; + $this->assertFalse(Event::hasHandlers(Post::className(), 'save')); + Event::on(Post::className(), 'save', $handler); + $this->assertTrue(Event::hasHandlers(Post::className(), 'save')); + Event::off(Post::className(), 'save', $handler); + $this->assertFalse(Event::hasHandlers(Post::className(), 'save')); + } + + public function testHasHandlers() + { + $this->assertFalse(Event::hasHandlers(Post::className(), 'save')); + $this->assertFalse(Event::hasHandlers(ActiveRecord::className(), 'save')); + Event::on(Post::className(), 'save', function ($event) { + $this->counter += 1; + }); + $this->assertTrue(Event::hasHandlers(Post::className(), 'save')); + $this->assertFalse(Event::hasHandlers(ActiveRecord::className(), 'save')); + + $this->assertFalse(Event::hasHandlers(User::className(), 'save')); + Event::on(ActiveRecord::className(), 'save', function ($event) { + $this->counter += 1; + }); + $this->assertTrue(Event::hasHandlers(User::className(), 'save')); + $this->assertTrue(Event::hasHandlers(ActiveRecord::className(), 'save')); + } +} + +class ActiveRecord extends Component +{ + public function save() + { + $this->trigger('save'); + } +} + +class Post extends ActiveRecord +{ +} + +class User extends ActiveRecord +{ +} diff --git a/tests/framework/base/ExposedSecurity.php b/tests/framework/base/ExposedSecurity.php new file mode 100644 index 0000000..431e123 --- /dev/null +++ b/tests/framework/base/ExposedSecurity.php @@ -0,0 +1,27 @@ +mockApplication(); + } + + public function testGetAttributeLabel() + { + $speaker = new Speaker(); + $this->assertEquals('First Name', $speaker->getAttributeLabel('firstName')); + $this->assertEquals('This is the custom label', $speaker->getAttributeLabel('customLabel')); + $this->assertEquals('Underscore Style', $speaker->getAttributeLabel('underscore_style')); + } + + public function testGetAttributes() + { + $speaker = new Speaker(); + $speaker->firstName = 'Qiang'; + $speaker->lastName = 'Xue'; + + $this->assertEquals([ + 'firstName' => 'Qiang', + 'lastName' => 'Xue', + 'customLabel' => null, + 'underscore_style' => null, + ], $speaker->getAttributes()); + + $this->assertEquals([ + 'firstName' => 'Qiang', + 'lastName' => 'Xue', + ], $speaker->getAttributes(['firstName', 'lastName'])); + + $this->assertEquals([ + 'firstName' => 'Qiang', + 'lastName' => 'Xue', + ], $speaker->getAttributes(null, ['customLabel', 'underscore_style'])); + + $this->assertEquals([ + 'firstName' => 'Qiang', + ], $speaker->getAttributes(['firstName', 'lastName'], ['lastName', 'customLabel', 'underscore_style'])); + } + + public function testSetAttributes() + { + // by default mass assignment doesn't work at all + $speaker = new Speaker(); + $speaker->setAttributes(['firstName' => 'Qiang', 'underscore_style' => 'test']); + $this->assertNull($speaker->firstName); + $this->assertNull($speaker->underscore_style); + + // in the test scenario + $speaker = new Speaker(); + $speaker->setScenario('test'); + $speaker->setAttributes(['firstName' => 'Qiang', 'underscore_style' => 'test']); + $this->assertNull($speaker->underscore_style); + $this->assertEquals('Qiang', $speaker->firstName); + + $speaker->setAttributes(['firstName' => 'Qiang', 'underscore_style' => 'test'], false); + $this->assertEquals('test', $speaker->underscore_style); + $this->assertEquals('Qiang', $speaker->firstName); + } + + public function testLoad() + { + $singer = new Singer(); + $this->assertEquals('Singer', $singer->formName()); + + $post = ['firstName' => 'Qiang']; + + Speaker::$formName = ''; + $model = new Speaker(); + $model->setScenario('test'); + $this->assertTrue($model->load($post)); + $this->assertEquals('Qiang', $model->firstName); + + Speaker::$formName = 'Speaker'; + $model = new Speaker(); + $model->setScenario('test'); + $this->assertTrue($model->load(['Speaker' => $post])); + $this->assertEquals('Qiang', $model->firstName); + + Speaker::$formName = 'Speaker'; + $model = new Speaker(); + $model->setScenario('test'); + $this->assertFalse($model->load(['Example' => []])); + $this->assertEquals('', $model->firstName); + } + + public function testActiveAttributes() + { + // by default mass assignment doesn't work at all + $speaker = new Speaker(); + $this->assertEmpty($speaker->activeAttributes()); + + $speaker = new Speaker(); + $speaker->setScenario('test'); + $this->assertEquals(['firstName', 'lastName', 'underscore_style'], $speaker->activeAttributes()); + } + + public function testIsAttributeSafe() + { + // by default mass assignment doesn't work at all + $speaker = new Speaker(); + $this->assertFalse($speaker->isAttributeSafe('firstName')); + + $speaker = new Speaker(); + $speaker->setScenario('test'); + $this->assertTrue($speaker->isAttributeSafe('firstName')); + + } + + public function testErrors() + { + $speaker = new Speaker(); + + $this->assertEmpty($speaker->getErrors()); + $this->assertEmpty($speaker->getErrors('firstName')); + $this->assertEmpty($speaker->getFirstErrors()); + + $this->assertFalse($speaker->hasErrors()); + $this->assertFalse($speaker->hasErrors('firstName')); + + $speaker->addError('firstName', 'Something is wrong!'); + $this->assertEquals(['firstName' => ['Something is wrong!']], $speaker->getErrors()); + $this->assertEquals(['Something is wrong!'], $speaker->getErrors('firstName')); + + $speaker->addError('firstName', 'Totally wrong!'); + $this->assertEquals(['firstName' => ['Something is wrong!', 'Totally wrong!']], $speaker->getErrors()); + $this->assertEquals(['Something is wrong!', 'Totally wrong!'], $speaker->getErrors('firstName')); + + $this->assertTrue($speaker->hasErrors()); + $this->assertTrue($speaker->hasErrors('firstName')); + $this->assertFalse($speaker->hasErrors('lastName')); + + $this->assertEquals(['firstName' => 'Something is wrong!'], $speaker->getFirstErrors()); + $this->assertEquals('Something is wrong!', $speaker->getFirstError('firstName')); + $this->assertNull($speaker->getFirstError('lastName')); + + $speaker->addError('lastName', 'Another one!'); + $this->assertEquals([ + 'firstName' => [ + 'Something is wrong!', + 'Totally wrong!', + ], + 'lastName' => ['Another one!'], + ], $speaker->getErrors()); + + $speaker->clearErrors('firstName'); + $this->assertEquals([ + 'lastName' => ['Another one!'], + ], $speaker->getErrors()); + + $speaker->clearErrors(); + $this->assertEmpty($speaker->getErrors()); + $this->assertFalse($speaker->hasErrors()); + } + + public function testAddErrors() + { + $singer = new Singer(); + + $errors = ['firstName' => ['Something is wrong!']]; + $singer->addErrors($errors); + $this->assertEquals($singer->getErrors(), $errors); + + $singer->clearErrors(); + $singer->addErrors(['firstName' => 'Something is wrong!']); + $this->assertEquals($singer->getErrors(), ['firstName' => ['Something is wrong!']]); + + $singer->clearErrors(); + $errors = ['firstName' => ['Something is wrong!', 'Totally wrong!']]; + $singer->addErrors($errors); + $this->assertEquals($singer->getErrors(), $errors); + + $singer->clearErrors(); + $errors = [ + 'firstName' => ['Something is wrong!'], + 'lastName' => ['Another one!'] + ]; + $singer->addErrors($errors); + $this->assertEquals($singer->getErrors(), $errors); + + $singer->clearErrors(); + $errors = [ + 'firstName' => ['Something is wrong!', 'Totally wrong!'], + 'lastName' => ['Another one!'] + ]; + $singer->addErrors($errors); + $this->assertEquals($singer->getErrors(), $errors); + + $singer->clearErrors(); + $errors = [ + 'firstName' => ['Something is wrong!', 'Totally wrong!'], + 'lastName' => ['Another one!', 'Totally wrong!'] + ]; + $singer->addErrors($errors); + $this->assertEquals($singer->getErrors(), $errors); + } + + public function testArraySyntax() + { + $speaker = new Speaker(); + + // get + $this->assertNull($speaker['firstName']); + + // isset + $this->assertFalse(isset($speaker['firstName'])); + + // set + $speaker['firstName'] = 'Qiang'; + + $this->assertEquals('Qiang', $speaker['firstName']); + $this->assertTrue(isset($speaker['firstName'])); + + // iteration + $attributes = []; + foreach ($speaker as $key => $attribute) { + $attributes[$key] = $attribute; + } + $this->assertEquals([ + 'firstName' => 'Qiang', + 'lastName' => null, + 'customLabel' => null, + 'underscore_style' => null, + ], $attributes); + + // unset + unset($speaker['firstName']); + + // exception isn't expected here + $this->assertNull($speaker['firstName']); + $this->assertFalse(isset($speaker['firstName'])); + } + + public function testDefaults() + { + $singer = new Model(); + $this->assertEquals([], $singer->rules()); + $this->assertEquals([], $singer->attributeLabels()); + } + + public function testDefaultScenarios() + { + $singer = new Singer(); + $this->assertEquals(['default' => ['lastName', 'underscore_style', 'test']], $singer->scenarios()); + + $scenarios = [ + 'default' => ['id', 'name', 'description'], + 'administration' => ['name', 'description', 'is_disabled'], + ]; + $model = new ComplexModel1(); + $this->assertEquals($scenarios, $model->scenarios()); + $scenarios = [ + 'default' => ['id', 'name', 'description'], + 'suddenlyUnexpectedScenario' => ['name', 'description'], + 'administration' => ['id', 'name', 'description', 'is_disabled'], + ]; + $model = new ComplexModel2(); + $this->assertEquals($scenarios, $model->scenarios()); + } + + public function testIsAttributeRequired() + { + $singer = new Singer(); + $this->assertFalse($singer->isAttributeRequired('firstName')); + $this->assertTrue($singer->isAttributeRequired('lastName')); + + // attribute is not marked as required when a conditional validation is applied using `$when`. + // the condition should not be applied because this info may be retrieved before model is loaded with data + $singer->firstName = 'qiang'; + $this->assertFalse($singer->isAttributeRequired('test')); + $singer->firstName = 'cebe'; + $this->assertFalse($singer->isAttributeRequired('test')); + } + + public function testCreateValidators() + { + $this->setExpectedException('yii\base\InvalidConfigException', 'Invalid validation rule: a rule must specify both attribute names and validator type.'); + + $invalid = new InvalidRulesModel(); + $invalid->createValidators(); + } +} + +class ComplexModel1 extends Model +{ + public function rules() + { + return [ + [['id'], 'required', 'except' => 'administration'], + [['name', 'description'], 'filter', 'filter' => 'trim'], + [['is_disabled'], 'boolean', 'on' => 'administration'], + ]; + } +} + +class ComplexModel2 extends Model +{ + public function rules() + { + return [ + [['id'], 'required', 'except' => 'suddenlyUnexpectedScenario'], + [['name', 'description'], 'filter', 'filter' => 'trim'], + [['is_disabled'], 'boolean', 'on' => 'administration'], + ]; + } +} diff --git a/tests/framework/base/ObjectTest.php b/tests/framework/base/ObjectTest.php new file mode 100644 index 0000000..06968f0 --- /dev/null +++ b/tests/framework/base/ObjectTest.php @@ -0,0 +1,200 @@ +mockApplication(); + $this->object = new NewObject; + } + + protected function tearDown() + { + parent::tearDown(); + $this->object = null; + } + + public function testHasProperty() + { + $this->assertTrue($this->object->hasProperty('Text')); + $this->assertTrue($this->object->hasProperty('text')); + $this->assertFalse($this->object->hasProperty('Caption')); + $this->assertTrue($this->object->hasProperty('content')); + $this->assertFalse($this->object->hasProperty('content', false)); + $this->assertFalse($this->object->hasProperty('Content')); + } + + public function testCanGetProperty() + { + $this->assertTrue($this->object->canGetProperty('Text')); + $this->assertTrue($this->object->canGetProperty('text')); + $this->assertFalse($this->object->canGetProperty('Caption')); + $this->assertTrue($this->object->canGetProperty('content')); + $this->assertFalse($this->object->canGetProperty('content', false)); + $this->assertFalse($this->object->canGetProperty('Content')); + } + + public function testCanSetProperty() + { + $this->assertTrue($this->object->canSetProperty('Text')); + $this->assertTrue($this->object->canSetProperty('text')); + $this->assertFalse($this->object->canSetProperty('Object')); + $this->assertFalse($this->object->canSetProperty('Caption')); + $this->assertTrue($this->object->canSetProperty('content')); + $this->assertFalse($this->object->canSetProperty('content', false)); + $this->assertFalse($this->object->canSetProperty('Content')); + } + + public function testGetProperty() + { + $this->assertTrue('default' === $this->object->Text); + $this->setExpectedException('yii\base\UnknownPropertyException'); + $value2 = $this->object->Caption; + } + + public function testSetProperty() + { + $value = 'new value'; + $this->object->Text = $value; + $this->assertEquals($value, $this->object->Text); + $this->setExpectedException('yii\base\UnknownPropertyException'); + $this->object->NewMember = $value; + } + + public function testSetReadOnlyProperty() + { + $this->setExpectedException('yii\base\InvalidCallException'); + $this->object->object = 'test'; + } + + public function testIsset() + { + $this->assertTrue(isset($this->object->Text)); + $this->assertFalse(empty($this->object->Text)); + + $this->object->Text = ''; + $this->assertTrue(isset($this->object->Text)); + $this->assertTrue(empty($this->object->Text)); + + $this->object->Text = null; + $this->assertFalse(isset($this->object->Text)); + $this->assertTrue(empty($this->object->Text)); + + $this->assertFalse(isset($this->object->unknownProperty)); + $this->assertTrue(empty($this->object->unknownProperty)); + } + + public function testUnset() + { + unset($this->object->Text); + $this->assertFalse(isset($this->object->Text)); + $this->assertTrue(empty($this->object->Text)); + } + + public function testUnsetReadOnlyProperty() + { + $this->setExpectedException('yii\base\InvalidCallException'); + unset($this->object->object); + } + + public function testCallUnknownMethod() + { + $this->setExpectedException('yii\base\UnknownMethodException'); + $this->object->unknownMethod(); + } + + public function testArrayProperty() + { + $this->assertEquals([], $this->object->items); + // the following won't work + /* + $this->object->items[] = 1; + $this->assertEquals([1], $this->object->items); + */ + } + + public function testObjectProperty() + { + $this->assertTrue($this->object->object instanceof NewObject); + $this->assertEquals('object text', $this->object->object->text); + $this->object->object->text = 'new text'; + $this->assertEquals('new text', $this->object->object->text); + } + + public function testConstruct() + { + $object = new NewObject(['text' => 'test text']); + $this->assertEquals('test text', $object->getText()); + } + + public function testGetClassName() + { + $object = $this->object; + $this->assertSame(get_class($object), $object::className()); + } + + public function testReadingWriteOnlyProperty() + { + $this->setExpectedException( + 'yii\base\InvalidCallException', + 'Getting write-only property: yiiunit\framework\base\NewObject::writeOnly' + ); + $this->object->writeOnly; + } +} + + +class NewObject extends Object +{ + private $_object = null; + private $_text = 'default'; + private $_items = []; + public $content; + + public function getText() + { + return $this->_text; + } + + public function setText($value) + { + $this->_text = $value; + } + + public function getObject() + { + if (!$this->_object) { + $this->_object = new self; + $this->_object->_text = 'object text'; + } + + return $this->_object; + } + + public function getExecute() + { + return function ($param) { + return $param * 2; + }; + } + + public function getItems() + { + return $this->_items; + } + + public function setWriteOnly() {} +} diff --git a/tests/framework/base/SecurityTest.php b/tests/framework/base/SecurityTest.php new file mode 100644 index 0000000..5af2830 --- /dev/null +++ b/tests/framework/base/SecurityTest.php @@ -0,0 +1,1062 @@ +security = new ExposedSecurity(); + $this->security->derivationIterations = 1000; // speed up test running + } + + // Tests : + + public function testHashData() + { + $data = 'known data'; + $key = 'secret'; + $hashedData = $this->security->hashData($data, $key); + $this->assertFalse($data === $hashedData); + $this->assertEquals($data, $this->security->validateData($hashedData, $key)); + $hashedData[strlen($hashedData) - 1] = 'A'; + $this->assertFalse($this->security->validateData($hashedData, $key)); + } + + /** + * Data provider for [[testPasswordHash()]] + * @return array test data + */ + public function dataProviderPasswordHash() + { + return [ + [ + 'crypt', + false + ], + [ + 'password_hash', + !function_exists('password_hash') + ], + ]; + } + + /** + * @dataProvider dataProviderPasswordHash + * + * @param string $passwordHashStrategy + * @param boolean $isSkipped + */ + public function testPasswordHash($passwordHashStrategy, $isSkipped) + { + if ($isSkipped) { + $this->markTestSkipped("Unable to test '{$passwordHashStrategy}' password hash strategy"); + return; + } + $this->security->passwordHashStrategy = $passwordHashStrategy; + + $password = 'secret'; + $hash = $this->security->generatePasswordHash($password); + $this->assertTrue($this->security->validatePassword($password, $hash)); + $this->assertFalse($this->security->validatePassword('test', $hash)); + } + + public function testEncryptByPassword() + { + $data = 'known data'; + $key = 'secret'; + + $encryptedData = $this->security->encryptByPassword($data, $key); + $this->assertFalse($data === $encryptedData); + $decryptedData = $this->security->decryptByPassword($encryptedData, $key); + $this->assertEquals($data, $decryptedData); + + $tampered = $encryptedData; + $tampered[20] = ~$tampered[20]; + $decryptedData = $this->security->decryptByPassword($tampered, $key); + $this->assertTrue(false === $decryptedData); + } + + public function testEncryptByKey() + { + $data = 'known data'; + $key = $this->security->generateRandomKey(80); + + $encryptedData = $this->security->encryptByKey($data, $key); + $this->assertFalse($data === $encryptedData); + $decryptedData = $this->security->decryptByKey($encryptedData, $key); + $this->assertEquals($data, $decryptedData); + + $encryptedData = $this->security->encryptByKey($data, $key, $key); + $decryptedData = $this->security->decryptByKey($encryptedData, $key, $key); + $this->assertEquals($data, $decryptedData); + + $tampered = $encryptedData; + $tampered[20] = ~$tampered[20]; + $decryptedData = $this->security->decryptByKey($tampered, $key); + $this->assertTrue(false === $decryptedData); + + $decryptedData = $this->security->decryptByKey($encryptedData, $key, $key . "\0"); + $this->assertTrue(false === $decryptedData); + } + + /** + * Generates test vectors like this: + * [key/password, plaintext, ciphertext] + * The output can then be used for testing compatibility of data encrypted in one + * version of Yii and decrypted in another + */ + public function notestGenerateVectors() + { + $bin1024 = + 'badec0c7d9ca734e161a1df6ca4daa8cdbf6b3bbb60ec404b47a23226ec266b1 + 3837ffc969e9c23e2bbba72facb491a6a3271193a35026a9ebc93698d689bf7b + 84fc384f544cc5d71c2945c8c48ae6348c753322fcaf75171b7d8f1e178e8545 + 3d5c79f03bae6d9705cabbe7004ec81e188812a66313297fcf5d4c61a48614d2 + 1b5379fae60736f88bc737257bc1cfbef7016108dd1f3a537aaa681544f5bb20 + c2d352212d6a2e460311ab7b93b611218b30c7402709bff89ecf814310c2db97 + 81f4142a54d6d41f82c33208c188a023c70befd697b496efb7c7b8569474a9d5 + 025a8ea8311c831b3de2b81800f28589b6aef537f6ada2e3d92a1ddd39cfd6b4 + 8113c8b36be890b099ca4e08655db0e9b5c211e706af052b776924233321412c + b1b540f08d88acd664c55854b05e31a15d4b0dc93b4514f62a88c3d4a451fe34 + 74d2fbaee742f232959b5f6c2b71a8b6ad95a0d5362f39309aca710f37a4dae2 + 228e27d35f4d3fc87ee6ece4538587fad7835f9803f5ca64dfd856ae767a3482 + c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c04 + 0f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed9273644463b + 1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334aa4 + d998a599053cd477f54fc0af62a8ef75eb91096b153751b201b8374c4956508c + 6c82ea2ceb0265e74c96032787fe01139b578c3a14fd4e32a85195375b25da60 + 4f21187ee01df6042971d7c2b9dd8b611527377f28f933559f6b2edfe7bd8896 + 00627830bcdffcb884989013585cc6da726c7cc57c69e8664a244d234465f2a5 + e736512a65e563a2a726915b50247aff165190c75d151139f2b31211a3acf94e + 236d27b441fe64e88a443778359d57ba0fed8edbb01cc60a116f9599da4e47bf + e96850ac12d1199a080f1b591c60eae613fba444f9fe31fd42ee333678532556 + 07fbfeef02cdbb2d0a8d2329adc7fba22aa4cd124c6e66e0b0aca796ba6aeb69 + f8e76a9d1aaabe351bc42fefa6054977859b51158ba7143980d76db5b2cc6aec + 9f83eac5edf79357632fb60cb4811e71892436e582375860faf8d8c518ee33ca + e08b18af7faa227d97196d7b041bcb366118751fbeaa92d80f86324ce8711cfd + 65005cad0ce30878f508eb1ea2735e212ef3e42a78467d4f31b483087c3c63a3 + 2fa62f2ae92e2acdfc3cf21b3419acc347ff51ccb17161e829cc4a24965fd930 + b983d63153b9c13dd85340d7184bf01734d4357c1aabfbdc9711193ffa974832 + 4f88cf801f35708db0901ffaa55415ca4334678633dda763b5fbfba7cfd51dc5 + 79149ec9284a4db2349dbc5264d5fca7a72034261716d90a996cb57ba09f7d07 + 29a2f10cc58eec98d86e9306a3fbf2e711046e86b5a86cc0eed7625be1a01ebf'; + $bin1024 = hex2bin(preg_replace('{\s+}', '', $bin1024)); + + $inputs = [ + '0', + '0123456789', + '0123456789abcde', + '0123456789abcdef', + '0123456789abcdef0', + mb_substr($bin1024, 7, 5, '8bit'), + base64_encode(mb_substr($bin1024, 269, 11, '8bit')), + mb_substr($bin1024, 383, 97, '8bit'), + $bin1024, + ]; + + foreach (['Key', 'Password'] as $method) { + $keygen = 'generateRandom' . ($method === 'Key' ? 'Key' : 'String'); + $encrypt = 'encryptBy' . $method; + $decrypt = 'decryptBy' . $method; + + foreach ($inputs as $data) { + $key = $this->security->$keygen(16); + $encrypted = $this->security->$encrypt($data, $key); + + $keyHex = $method === 'Key' ? bin2hex($key) : $key; + $dataHex = trim(chunk_split(bin2hex($data), 64, "\n\t")); + $encryptedHex = trim(chunk_split(bin2hex($encrypted), 64, "\n\t")); + + echo <<assertEquals($data, $this->security->$decrypt($encrypted2, $key2)); + $this->assertEquals($data2, $this->security->$decrypt($encrypted2, $key)); + } + } + } + + public function dataProviderEncryptByKeyCompat() + { + // these ciphertexts generated using Yii 2.0.2 which is based on mcrypt. + $mcrypt = [ + [ + 'b86b7529a525d148cc73798da528d8a0', + '30', + '4fb4765bea6beb208ba9395bf6d7497f37626463323730396362366338376536 + 3236656535613035373835323061343031613764393062353439623834353135 + 376435383635393065393636656663378807b00020ea10101bbfc2ef0dfee082 + fcbc1927daee7e6d061bc7a7c8d8e877', + ], + [ + '7e214bb6b27108918c007c0f9e1bdd8a', + '30313233343536373839', + '98981d39f0c985aca577e2eb9472059339623332343335646634613630616335 + 6133323639663336633533313032353164393562303434623533326331653561 + 6566346561643066643331393437623366e93fe0ef0a220ef1228be9f9195475 + eb303b841b6371841126c13ed419d931', + ], + [ + 'c139f67915206b7296bc6ab383a2786c', + '303132333435363738396162636465', + '5773028f2be0df720cb3be2cb989e9e161616430393538363437623862326264 + 6436336133643738333866353339393932326432356433306630663062613331 + 386666313033626661333065313031623d5e980deacb6369592c90e7afca6e6b + 06736654378cc93b2d238e6360969956', + ], + [ + '910c052157953194d552e3a3f0061ab7', + '30313233343536373839616263646566', + '3141c48cc0b73ee43d5cd9ae5c8a153f66343039333638396632653239623434 + 3162616664636331316238336265626536336231653764663732396638336138 + 34636438616265376138613539656164b004dd4ebddba049ae068936643dd475 + c07696b0cc173c2eb4c2d7bc3364845e6e3656b463b04e2271cb10824f1365ec', + ], + [ + '28d0ad09ce367ca8e0772bbeeea6c40d', + '3031323334353637383961626364656630', + '1f19013959a0985cf0235c4ff46a20c135626235633437383532343736613963 + 3765646334666263323832643438663361323266303264383337613736363133 + 666432373632343236313331656362354de2203149f8b4f348c06ea4e2eb94e5 + de4deaf1d198e14e7c448421002bdfa9ed979502d86750d70aebaa1c727ae79e', + ], + [ + 'b658ac4b9fa13c3c1d40699aba886b7b', + '4e161a1df6', + '154015ebb822a55869721a0b1c22497762653266663264333631373938653539 + 3465316466396535343966373738666663646232656163383733633739323334 + 316363623562353462363133623134643d118216985ac7e3f6888a95552b6a67 + 6ff70daf8dfb65b4d5f62a936b7f64d7', + ], + [ + 'baeb43072f20af0f85c6252aa9f0d472', + '5862447074634952357761764253733d', + 'beb6dcd0fb444cbf759a241bd0ea26e537336135333532656136653262303736 + 3061656635326136376230333132663839626431366265363565643064616362 + 39633830313066356330653466613232dd9cfe4f4495f34a971a25d881dd48a3 + 12093a6307a87e4544e217cf9d39dd536a5882d2b9867abefef5c1dad127447e', + ], + [ + 'd527f854e8f37c49c71b82c48d8b4775', + '82c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c + 040f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed927364446 + 3b1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334a + a4', + 'baa84c2c05b2ac8efd9fc8f9824efb5d63306366393939626532323532646433 + 6539346265383936336262303339336635333164383339326436376631353366 + 6433616639653638393063376137626574bd7aa8c5f313e2d8b7a4ca4af35090 + 9695845c9d62cd91c486307d3ae0701e4abd1fa69a255aab1e6ac2874fa1bc0a + 065340418a6669427bcdec751300ce7666a38d17d850f7dae4ea9567045356e8 + f347941226bf7b2d4dd3a21c8aa0b381f8ad06c3a55a7d2cb967ad148142c287 + f12a563f9cd2c6224e7efb8fdd130bb9', + ], + [ + '01025bfec21dda4342809cf20382de29', + 'badec0c7d9ca734e161a1df6ca4daa8cdbf6b3bbb60ec404b47a23226ec266b1 + 3837ffc969e9c23e2bbba72facb491a6a3271193a35026a9ebc93698d689bf7b + 84fc384f544cc5d71c2945c8c48ae6348c753322fcaf75171b7d8f1e178e8545 + 3d5c79f03bae6d9705cabbe7004ec81e188812a66313297fcf5d4c61a48614d2 + 1b5379fae60736f88bc737257bc1cfbef7016108dd1f3a537aaa681544f5bb20 + c2d352212d6a2e460311ab7b93b611218b30c7402709bff89ecf814310c2db97 + 81f4142a54d6d41f82c33208c188a023c70befd697b496efb7c7b8569474a9d5 + 025a8ea8311c831b3de2b81800f28589b6aef537f6ada2e3d92a1ddd39cfd6b4 + 8113c8b36be890b099ca4e08655db0e9b5c211e706af052b776924233321412c + b1b540f08d88acd664c55854b05e31a15d4b0dc93b4514f62a88c3d4a451fe34 + 74d2fbaee742f232959b5f6c2b71a8b6ad95a0d5362f39309aca710f37a4dae2 + 228e27d35f4d3fc87ee6ece4538587fad7835f9803f5ca64dfd856ae767a3482 + c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c04 + 0f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed9273644463b + 1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334aa4 + d998a599053cd477f54fc0af62a8ef75eb91096b153751b201b8374c4956508c + 6c82ea2ceb0265e74c96032787fe01139b578c3a14fd4e32a85195375b25da60 + 4f21187ee01df6042971d7c2b9dd8b611527377f28f933559f6b2edfe7bd8896 + 00627830bcdffcb884989013585cc6da726c7cc57c69e8664a244d234465f2a5 + e736512a65e563a2a726915b50247aff165190c75d151139f2b31211a3acf94e + 236d27b441fe64e88a443778359d57ba0fed8edbb01cc60a116f9599da4e47bf + e96850ac12d1199a080f1b591c60eae613fba444f9fe31fd42ee333678532556 + 07fbfeef02cdbb2d0a8d2329adc7fba22aa4cd124c6e66e0b0aca796ba6aeb69 + f8e76a9d1aaabe351bc42fefa6054977859b51158ba7143980d76db5b2cc6aec + 9f83eac5edf79357632fb60cb4811e71892436e582375860faf8d8c518ee33ca + e08b18af7faa227d97196d7b041bcb366118751fbeaa92d80f86324ce8711cfd + 65005cad0ce30878f508eb1ea2735e212ef3e42a78467d4f31b483087c3c63a3 + 2fa62f2ae92e2acdfc3cf21b3419acc347ff51ccb17161e829cc4a24965fd930 + b983d63153b9c13dd85340d7184bf01734d4357c1aabfbdc9711193ffa974832 + 4f88cf801f35708db0901ffaa55415ca4334678633dda763b5fbfba7cfd51dc5 + 79149ec9284a4db2349dbc5264d5fca7a72034261716d90a996cb57ba09f7d07 + 29a2f10cc58eec98d86e9306a3fbf2e711046e86b5a86cc0eed7625be1a01ebf', + '08ad33a166a9b39ba7522ccf5414123062643565356136373131666663323763 + 3636343466313761356339656234343064626331343366346432343062626634 + 3264393630336535353431613338653717747da97dd4d63e215dc8bb9ce231d5 + b3cc9c287dfadb1b5acce0d4da2816de16114665271204188d91b642cdfdb494 + 66a89caa29a9139354f69c4c188d76d88d36d14004268f327c98f4736ba31728 + a46d8f50d1665bcf157e3164d756286eceac4ce81ba3ffd1b79ff0862f5f529b + d44f0e2fbcb88c388095cb894fd4ce059ba8f5436f0a15b2fa9a40acd6645ad1 + c6f16365250715cb0552dcfc220e844ba67e2a1206b1725a6bbb8f0e87b7067f + b51fc0226cd963bddf549227d5eaf5f996061d9c3b7e3306bd9be1114aed6199 + 6e44ee1144bebfca9a1064d40419837e54006f54161dd028b2702faa5cde214c + bc11ed1c77d4042b333e772473f4764fcdfcabdd0319f33d96ad0ab904cd2620 + 31683afc4c96dc27fde0570aaedc922a552d46687a606bb579b6ab8050f418f8 + f6a3fc33ef5eeba8dbf54b5a90a1034ff8a68d9ea691d9a1d6b8f41376735bec + 6c0f541f927cf107f2184f96235a6fca6d1db013966d8527389f8a79f4afd7bb + 297c85d56f74faaa069679edc78b16b17ab8d72de3788f2ac2fe8a2e15ddfb3f + 14ffd9ef18c95acf340f702a974b580cac93928417650b8f9e7409619774e483 + af66b18ec7547f744099e2bb4125905e5dd553beca90d03fa7d7bba201ab97ac + 92506c305ff79afe9c99a73cb20b9048464beeb100df0ecfb40161f95dd8708a + 6fd09e1b166f1e27429b1ca50f990a45425dec25b2a29dcde4fd1c23b0d660ba + 10241bc20cdc59c3609a7d6b094538d56b878c62dca3a54fbc53d815ae0549f6 + 978ea37a644add2bd2720b37a3502d683b0a8b9ce269bb3db8a44f3e8c3ba507 + 7759de171e1d040dfe5c9a610e21e3b41d95403654122ed7b75111622f14bb50 + fd7a3e637bba73fc8c4e22702b52329c224860a9e04b38b8c23527c732a281dc + f92103d71decf673b3fa83feab2c1937811e0b41163019e1b45e664d4acc570c + 2d4b24dc138285478c3898b0567c026a1651bbada0fb62ab5ce0d96e3601aec1 + c6f04ecb1b53f1d852893edb971703dcd919c2dd883d0851e2fc491cf9abf1b7 + c1652bac73a5a9e9bdbf164db948cc5b8299fd7f5535fa927130dc4e183ef35e + bb08723625e4cf62f253111e6f016e6cfba2e9cec30e273e4b2dcefa80d1c528 + 82c91609acf5989eec18afbefc25c898763c50d2a5cc54250d2672a39758f948 + 1866c26d260bf774db05280697d2b1a95b0481afa2b80bb205186ac290bc3770 + b19a652dc2f5d6611363cd851d921edad36851d64f4cac6ff67299455e120cee + 65a0d9471d1c952d7e81ba5e67e0a8a41a9a68f50d88a2b62151b564ffc2e435 + 8373e55df6cad337589a89054c050f93b4b252aa65466029313bf7311ae735a5 + 26cd2bac41af846c069ed614485cf62bd66c939dfeb27ecaaa197aa344a5488b + b3a2dca884c7fdc4ac08816b2b5ba3b7414f7ff7a06a3a6fe75e20c9eb97a881 + ac130616f176d1f26ae24bf4392e0a0e', + ], + ]; + + // these ciphertexts generated using my branch 7215-replace-mcrypt which is based on openssl. + $openssl = [ + [ + '67ae7370e4a144523543f1e3edf35b26', + '30', + '706e1670ec6beb91c565299710e4f43231336530323838313435653933623539 + 3238313639623066323530646630653236313832333361346664623132393436 + 34326131663964636634366665306439e6142bf3d0e6a5952231d8bfabbacd83 + ff04c61400529385d63a4b8f8696982d', + ], + [ + '5d4bae62bea3c8f4c49dd1a38a4e1b2a', + '30313233343536373839', + '4c9a34e1977dd656fd3e18d4bc2b00c762353830326262373135396530643235 + 3332643937653632353331626532373336653761643866646233336365323233 + 30633138663034313665653038306161eb77ac98344a0bf946f98e892e6e15db + b9e221a7c25135a36562c3ecb2981fcd', + ], + [ + '6832851af3c63a1e303bdf1bca38dd9c', + '303132333435363738396162636465', + 'd09d2faa163e774abd020bf8cd623f8962646233313330626133613964353834 + 3436663631383139653438326563623537373830663962303531366130383130 + 3333303531613337386534626136636415db7a6885b67f69d9974f5879ae7497 + 08811fc036508f23f55f3f9d16b9ff9d', + ], + [ + 'e8a9799f4254b26484ea447918dcaad4', + '30313233343536373839616263646566', + '1a76a05af572abe9b4e7a67d7f64baff39666636363332323133373034386531 + 3761353236333263643965313139303666636535343862363737333032323331 + 313136366562336535663033316231303811542783f13798b17d40aa7ec9b489 + 34404ab50784ad1722f5f4d4462f702d3a625ef712635b274a970a47b516b137', + ], + [ + '27cbf5a7c4327582393b2ec277cfe957', + '3031323334353637383961626364656630', + '60e2e14b404c5bd55b192ef2f1c7131c32356261636361313131336265323534 + 3439623033346337346133346239363337633736663831343632626638303038 + 64653361396366356165633061666538d2137b2defca383668827b6983f86254 + bd849c3e8c9a44b6e1ed203491d73b4cb0cb83658240a89baa9261755d707879', + ], + [ + '7b157beb08e8a8ac7d74f789ccbacae5', + '4e161a1df6', + 'a17ca346c4a88404b8a345b1d075173a66356137326335343137393136353762 + 3930636535636466336534316438376437376639366535666636313235653262 + 38393464663134313430333633343232b319ce688676fde03d092d73df75705f + bde594d9b2bfe41580a458555982dc70', + ], + [ + '88704df5b4881d2246388dc7c68066cc', + '5862447074634952357761764253733d', + '9069fbdd47ee81faf34eff40f8fee94333393037333936333439653537636132 + 6561613863336165333336323562353161636330366438633264376461626563 + 3836363462646536323261333034643070e4b0a3d196f36a4afb92a7ae4ef7b8 + eb44e9db29638fa32140e379ae7aa6b7e68f454635ade137165383fd3a5c049b', + ], + [ + '1d203fba1cd2a7b92abb8f40eb985538', + '82c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c + 040f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed927364446 + 3b1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334a + a4', + 'fade5d841aa10a29a2ef5236371ffc2964343165383664636264393666383364 + 6165646139316438666531633230306537343364336166666463656466306564 + 63326239653938303332656464346463136bd6dd0b7530490b91024ed944bc3e + 3fc4050d20ce05a9ed992ede75f62bdd2523d0cbc93493baf07ef98c895a353b + 5baaf26200572aa2e5bd22508db227556c5ee9eb7425418e9852c595e6ac0e61 + 37c186e04a3f19d855d8c4b8a8e6ad1be179ea5c816fe461a4cec212297873c8 + 5f96ee5c024cd88d1c32975fd95acd73', + ], + [ + '1f93719d7a66a724c3841835fbcb33fd', + 'badec0c7d9ca734e161a1df6ca4daa8cdbf6b3bbb60ec404b47a23226ec266b1 + 3837ffc969e9c23e2bbba72facb491a6a3271193a35026a9ebc93698d689bf7b + 84fc384f544cc5d71c2945c8c48ae6348c753322fcaf75171b7d8f1e178e8545 + 3d5c79f03bae6d9705cabbe7004ec81e188812a66313297fcf5d4c61a48614d2 + 1b5379fae60736f88bc737257bc1cfbef7016108dd1f3a537aaa681544f5bb20 + c2d352212d6a2e460311ab7b93b611218b30c7402709bff89ecf814310c2db97 + 81f4142a54d6d41f82c33208c188a023c70befd697b496efb7c7b8569474a9d5 + 025a8ea8311c831b3de2b81800f28589b6aef537f6ada2e3d92a1ddd39cfd6b4 + 8113c8b36be890b099ca4e08655db0e9b5c211e706af052b776924233321412c + b1b540f08d88acd664c55854b05e31a15d4b0dc93b4514f62a88c3d4a451fe34 + 74d2fbaee742f232959b5f6c2b71a8b6ad95a0d5362f39309aca710f37a4dae2 + 228e27d35f4d3fc87ee6ece4538587fad7835f9803f5ca64dfd856ae767a3482 + c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c04 + 0f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed9273644463b + 1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334aa4 + d998a599053cd477f54fc0af62a8ef75eb91096b153751b201b8374c4956508c + 6c82ea2ceb0265e74c96032787fe01139b578c3a14fd4e32a85195375b25da60 + 4f21187ee01df6042971d7c2b9dd8b611527377f28f933559f6b2edfe7bd8896 + 00627830bcdffcb884989013585cc6da726c7cc57c69e8664a244d234465f2a5 + e736512a65e563a2a726915b50247aff165190c75d151139f2b31211a3acf94e + 236d27b441fe64e88a443778359d57ba0fed8edbb01cc60a116f9599da4e47bf + e96850ac12d1199a080f1b591c60eae613fba444f9fe31fd42ee333678532556 + 07fbfeef02cdbb2d0a8d2329adc7fba22aa4cd124c6e66e0b0aca796ba6aeb69 + f8e76a9d1aaabe351bc42fefa6054977859b51158ba7143980d76db5b2cc6aec + 9f83eac5edf79357632fb60cb4811e71892436e582375860faf8d8c518ee33ca + e08b18af7faa227d97196d7b041bcb366118751fbeaa92d80f86324ce8711cfd + 65005cad0ce30878f508eb1ea2735e212ef3e42a78467d4f31b483087c3c63a3 + 2fa62f2ae92e2acdfc3cf21b3419acc347ff51ccb17161e829cc4a24965fd930 + b983d63153b9c13dd85340d7184bf01734d4357c1aabfbdc9711193ffa974832 + 4f88cf801f35708db0901ffaa55415ca4334678633dda763b5fbfba7cfd51dc5 + 79149ec9284a4db2349dbc5264d5fca7a72034261716d90a996cb57ba09f7d07 + 29a2f10cc58eec98d86e9306a3fbf2e711046e86b5a86cc0eed7625be1a01ebf', + '712929635f5be013159aec81296b96ec36333734373565366166383031313734 + 3331623863663837343237633863376539643865643339383531363139396566 + 34313731633765393462663264316130de90698e64fa4abc91639e72baee83bc + 2caf85f91318e0cbd0db5fa08c4ffb582ec55ca43de53a43f2844af35d5f87b9 + 8faa623107aee2e083f1c7aeedcb0472c93bb9eacbd39d839d5bf94c44658d7f + d70817f5d6b120f91ef86880f93e99151bc1ed13ed263a3ccc7243e5ea97f39f + 1ce2ce6b05a2b78f05c5d72041e35466068f52fb3d2ba3afa7594d7bc0981c54 + 8b31ae7e5b7e7e0e6f2fac9a336e6516d7e4b5cc658e1fe634daf9ad097715be + 14d54ef19adc381db31db78714a09e997dc7732853d39885566e41a2c0ecb08d + ef8ab56359a0e312446d9f1555539ad29e13080d438d6817280d4dbfe6cd4ab9 + 4a357dbddcea1bc90e0d0fa6d556b1ba75c23a1d3818ea91e0fa5b8005b8020e + f7a80ed2ee60aa8ee588e101dbf3b64bf6a3dca5b1d5bcb96eed5c594bab1dcf + c1f61d74ad3ff0f5fdf176a327e8de33d123cdd61c6c4dc946429c566ac0f77f + 48215d5889365fa664a879babd4758fb4d824cfb9e4bf6500ffec0e4ebefe4f6 + 2e521a7cd563fc954a9161047461e4054f324c5cf4f9e949566c9ac17c45aac1 + abf98caed42242c51aa0d81d732c538e437c4024e8f04eeeab6619aed46599e7 + f66c2041e0c346affab1f79cd7352a66686fac2b38615f8fc172ab0967fd4435 + 9dea9f41b57ba5a752e20456f2254e8eef576867ebda0f48fe47a2e91fc8d8af + dc1bf98a8d3530b4b02996fe4b05ec3dab200f9e79a4261c233caa9a33762f1f + 4b3482ab6f16f5dbd7bd87ed17e21c30140ce61fc2468c054ce51dded2683d7c + 375d69d662729d6fb8629b8dc25dcc5596f87f627a2138a3ef368a2a1591902f + 84ffc457bd556a346815986f153fd3a99ef169444436ac81853b318c0908cb33 + cf332edadfb870cab419365312c18aeda418b8b571783a6b2d8c397c33a22b31 + 55958cef153f4d9cfc3a1c6288ff17bfdd92132e1f1e5fe8041e30a383084811 + fe892d7fc33abff10dd20db07277677b16e7f90137adfc3cb36dd85de3618769 + bf8f3ce13642f9ea430f455d388281208190b335915e256320274a904ecd0938 + d3c34d99c88e3186a132777fc7b74b43efab1a08376035061de56a4fb6de611c + 41d2139c77a516c4f8144b123696356b4b9a752a9cd857630af4ef02339172e6 + 361a2fd6a18e3baaf8a3f7e9811ad5fb61abba7ae893b1e7748df2c5b7704eb9 + 65606b0253cba6a0561b0e70593c724f99e07d3e9a857aef894a64a35969b354 + 4726d35504d7b8c0c06cbf9106c5d504674daa879b39328d2c83e0f4e5622ea1 + 4fb742458214b410e2736d8cefabfb125c4769701711c15ab870b5ff192d4c71 + e805ac5100352e33227b162ebae123e20c477719c52c59e192c2e3731806404d + d4359f840b11ad495357210e259e6b9e8fe5e8f600e8746fe1a483d45b694324 + 0809649ed7320b0022a5ef7b414635933d6d18ec7218f829121d12dcb573ed77 + 79ab0519d2df17dbd8988b32ac0711ef', + ], + ]; + + return static::CRYPT_VECTORS === 'new' ? $openssl : $mcrypt; + } + + /** + * @dataProvider dataProviderEncryptByKeyCompat + * + * @param string $key encryption key hex string + * @param string $data plaintext hex string + * @param string $encrypted ciphertext hex string + */ + public function testEncryptByKeyCompat($key, $data, $encrypted) + { + $key = hex2bin(preg_replace('{\s+}', '', $key)); + $data = hex2bin(preg_replace('{\s+}', '', $data)); + $encrypted = hex2bin(preg_replace('{\s+}', '', $encrypted)); + + $this->assertEquals($data, $this->security->decryptByKey($encrypted, $key)); + } + + public function dataProviderEncryptByPasswordCompat() + { + // these ciphertexts generated using Yii 2.0.2 which is based on mcrypt. + $mcrypt = [ + [ + 'LtogIEhy59ve0Huy', + '30', + '83325c8abe8dc0afd801acb7785dc29c32393439653930663266396466653862 + 3965303964653935326238343065363734346264633932376364376430653933 + 37303963376232336634306339396136e6f4e7dc3e2fd23be186f037e4caa6d0 + 4ae8cb894d80c08bb790417af9cc176f', + ], + [ + '1_VTumNNc7VV463t', + '30313233343536373839', + 'a247ac24f3aa60e894904f58954ce8bf39386530366165343538336132616231 + 6532353066663430646432383531333465373336646333386437323733633763 + 646665346232623635393962626162323a44a150a556addd97addfb43a32f600 + aa2c479664682a308e6cdd523967cb4a', + ], + [ + 'DBpoIPndKRm2Rfem', + '303132333435363738396162636465', + '9ed20f30824312032e5e34e2c5ab61e333313930616634396137623261363863 + 3334323832333664626265663435643633323033383862613865633961356261 + 30353634393536636465643833633531b62ce156f34b92790b2d26312f3fd7d0 + 0a646da4d636f6998f1b0d859f255dc6', + ], + [ + 's1e1oRE1iM_oortb', + '30313233343536373839616263646566', + '5b03427dba481b5af8760edc3788fa0e66666663623539353163346466663761 + 6434663337383566366265663931303662366530653633663235303532373763 + 37346330393537646630616535373230c98134da00d77753741c1f0bb483f109 + 622a889f950310cd51d7d48d63202b20d378eac85f7d0c851fc9905d322aef96', + ], + [ + 'i1E7JvOQaESAKoeH', + '3031323334353637383961626364656630', + '7cf2ed4612d07de3ecfd54ac0e576e8539613861656439333965623533626238 + 3361653764663438643330383130313462613961636462383836383862313962 + 346439313666343336313766366538637bd566b1eecb0b1e0896eb1fd0fd11d9 + dcb9eee5cc3d90c4046a6849e8ad152caf85e8f96de3b24b4d523a2d60533e0b', + ], + [ + 'QUN24gpNGodXurMM', + '4e161a1df6', + '49fc2d51b3e6325d86334ea8872699ef31613661333031373065373834643033 + 3863343734366435343035316562643438636133306233373431323066333330 + 32613330623364326162326434306637042f9b4a005ed3b9532181d020378800 + deefcfa36d77ed4abdf35546c0bb4aec', + ], + [ + '1COt9D8ZsfclCic2', + '5862447074634952357761764253733d', + 'c4d5f90054faf3699d983795f44bdb1430643734643832343265323064323434 + 6535346565323733323764376266646539366431353266666639386231626438 + 653237646165393461626435656332332b4244fccb47ad8cdea56109c7d5a417 + 13b3844d9857507db59d0000037b169f7b67cf0ea793c0254bffc55342d8e4c7', + ], + [ + 'eUqmv4chMnO1H5cq', + '82c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c + 040f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed927364446 + 3b1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334a + a4', + '31435e0bf8c0be9a395791288f6d058839336130623938343839626436636433 + 6664373131666361383739633163373130323936653730306331663836373263 + 656135303466323439326564626162378298df437dab821e8b2f7086962ffeb1 + 7a674022ee498470e5e8fdff8905aed39e424588ecee69965bb6856f0356860e + aa978ffa42ccfef6d4fb00026014e107736f3ee9b2206a2cd52b18e3068cf6aa + 077c7304128a3cd92d4fc29dfa7c180eaf85feec791618db1ed01695536cf8ec + 7923c0b3fb974fd0ff92faa62723e94f', + ], + [ + '3Cl5v2Lmn61PiQ3H', + 'badec0c7d9ca734e161a1df6ca4daa8cdbf6b3bbb60ec404b47a23226ec266b1 + 3837ffc969e9c23e2bbba72facb491a6a3271193a35026a9ebc93698d689bf7b + 84fc384f544cc5d71c2945c8c48ae6348c753322fcaf75171b7d8f1e178e8545 + 3d5c79f03bae6d9705cabbe7004ec81e188812a66313297fcf5d4c61a48614d2 + 1b5379fae60736f88bc737257bc1cfbef7016108dd1f3a537aaa681544f5bb20 + c2d352212d6a2e460311ab7b93b611218b30c7402709bff89ecf814310c2db97 + 81f4142a54d6d41f82c33208c188a023c70befd697b496efb7c7b8569474a9d5 + 025a8ea8311c831b3de2b81800f28589b6aef537f6ada2e3d92a1ddd39cfd6b4 + 8113c8b36be890b099ca4e08655db0e9b5c211e706af052b776924233321412c + b1b540f08d88acd664c55854b05e31a15d4b0dc93b4514f62a88c3d4a451fe34 + 74d2fbaee742f232959b5f6c2b71a8b6ad95a0d5362f39309aca710f37a4dae2 + 228e27d35f4d3fc87ee6ece4538587fad7835f9803f5ca64dfd856ae767a3482 + c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c04 + 0f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed9273644463b + 1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334aa4 + d998a599053cd477f54fc0af62a8ef75eb91096b153751b201b8374c4956508c + 6c82ea2ceb0265e74c96032787fe01139b578c3a14fd4e32a85195375b25da60 + 4f21187ee01df6042971d7c2b9dd8b611527377f28f933559f6b2edfe7bd8896 + 00627830bcdffcb884989013585cc6da726c7cc57c69e8664a244d234465f2a5 + e736512a65e563a2a726915b50247aff165190c75d151139f2b31211a3acf94e + 236d27b441fe64e88a443778359d57ba0fed8edbb01cc60a116f9599da4e47bf + e96850ac12d1199a080f1b591c60eae613fba444f9fe31fd42ee333678532556 + 07fbfeef02cdbb2d0a8d2329adc7fba22aa4cd124c6e66e0b0aca796ba6aeb69 + f8e76a9d1aaabe351bc42fefa6054977859b51158ba7143980d76db5b2cc6aec + 9f83eac5edf79357632fb60cb4811e71892436e582375860faf8d8c518ee33ca + e08b18af7faa227d97196d7b041bcb366118751fbeaa92d80f86324ce8711cfd + 65005cad0ce30878f508eb1ea2735e212ef3e42a78467d4f31b483087c3c63a3 + 2fa62f2ae92e2acdfc3cf21b3419acc347ff51ccb17161e829cc4a24965fd930 + b983d63153b9c13dd85340d7184bf01734d4357c1aabfbdc9711193ffa974832 + 4f88cf801f35708db0901ffaa55415ca4334678633dda763b5fbfba7cfd51dc5 + 79149ec9284a4db2349dbc5264d5fca7a72034261716d90a996cb57ba09f7d07 + 29a2f10cc58eec98d86e9306a3fbf2e711046e86b5a86cc0eed7625be1a01ebf', + '0c5164ead7f48c5d95f5907399c146a261353462323734323738656231323164 + 3962333166373062373734636630623932616638626236393339363861646366 + 35643933393537303331343436303330a927c7a879272f81e1032d57530b5e69 + 60f70e14b7607e8e17583aa8197f547e375e07b7a9d6c11be406f5e01aac59e2 + 7e54bb3c33662ea294cfbd0e7bb8e5eb886edee341509a752fc3b9706807a948 + 00edd0bff8e624275420bff50995de70d2692a052e1710a0b9135f9f44abcb02 + 24a189f1bb414e4d73fb539728d40b47ebc34fdb5ec2fa61848bb828de5179a1 + e799eb09367bda9b59b3bdc51d3f92c1bd7dacf751b9324059869bf6adc3d88d + 226a153a75cae1a2426ea187ef62c97bbd35e97450da87d4da9aed08ebf30a3c + a3369cc65a17acebb8a6ff8ff698743a3782990bc5e8cd03a6882c0f7c50868c + 6b3ce967c9ea317555eb972e9bb7beb7b3215160a0bcca8c7f92a085beca256e + 4484b1cdcaee495917d8aa4dbf7675806f7f57e77a770ea7db6e080150b43f56 + 15709b371a303e89b032eac7fec3ee954ea52940a2e59343fd0fd59ac2d4f095 + 74d2863eed13774c63a94e87f7ccdbf0741a56074a7210e2f022809ca48637d8 + 057d80fb190f339ddee2b6f7aaef3f2c1848026bd33e377ac554e2b29dede4fc + 11e040b3837c24e6cd93430c2f9c19138cd1b505681958a09f223f65e6d7b123 + 43e426e204ee32411b1590133d58fbc4806ff784db93cd0205a7b4a1f4b96ee4 + 02b06ac00520118c89a7c4f1dfb4ac941a3d6f839e9312ee8cd9c3c02ef5cf2a + 29d266fcfd29c24b994bcd3c67000999486bad6b060f87d5c843f3f132be5a7c + 6ab2aab2091a83f0673efc4bf658e6c181c800a2eab5272c9cc8e9bdcf4ee061 + de613989f107f1755385697ad64cd1c613f1f742a980c48e27638b8423b82eba + 555c59020ee5794099377e816e8983a7579fc97178e5ac0f98bdda6dbf3f38f1 + 3f8b2d12cc792e729468a8408482985ac73e831a6ca5f67176f68bf216b77147 + fe4743ae60f628defa590b0b0b7d8c39d24ef6980ffc0c47882fa0e3f04ed3e5 + 6d8654e11a0f25a2b3dd03e900e3d59922fa7ccd544f98a04828a34826fd9bfe + e8c841ca6146cc96443ab2cbed3f846f5241d27b15f81df80e2b35219044e933 + 4967334529fe949604a19f7cad76842a16928066a01fb9ec750e78ae68ddcb4f + 833b5e89377ea31c7c87666c300f36f7583383f783f979cedbd05585c50caade + 73f9f38dfcc5f915106573694ce497a0787ce3fecf9678a75b62f258aea300e8 + 2176e5c51009ea1fbdf266606cfb93cc62f9abd6c056625df053da8d9e175d63 + ca716f148365a41796889e6d24e6c9a6ee6ac57bf7c35b45d4000ec638d191e5 + 54fe6b031f87b82f6076e9672f7162de1dafedb9fed9d38adeb999c7fc46f801 + cd546342404315b06faff51d549b2eb94390d40a9ad826c1595add3f11afb909 + 16dc20173f13010008bc12a6355d582205897e7eb885f526a08bee072dabbb15 + 3b1777d8e7d96b31db8b64d64404ae82b3506f10ef198fad6321aa8cf04b5f54 + d5236014d4b5ce20fbfba77f090d3573', + ], + ]; + + // these ciphertexts generated using my branch 7215-replace-mcrypt which is based on openssl. + $openssl = [ + [ + '3DZsVH4gt5xBueho', + '30', + 'e19edc37d284b77a5a4600334b67317662393266323434393038666330653031 + 3730313664646137663830626366383363336239313664336637653133313933 + 306133613836363563643538396163642b6c12f20e7e1ae97422ee659914cc57 + e99c7c97c7a4957e78ab957b18be4551', + ], + [ + 'CVALyUpDdMOSaxJN', + '30313233343536373839', + 'a2535797ac0c83932fd9a2b8d6b2602662663439623337616631623434333233 + 3033343439313063656162373231666330333261383561356632393932386462 + 3631666364313236303962373636316296930828e0e154a0e8d262846835f242 + e42de861cba81df69fe6fe5a5970fdf7', + ], + [ + 'wBZcBIhNSFiaCWE8', + '303132333435363738396162636465', + 'd77b5d334d2820b5b5a54c5f71fce21130373832656561636661623564383766 + 6338343636626662346566623035333461653566353366656438303063376561 + 32643033343166376162376333373166c6cf828b68ff940e8de977e3471d1d51 + 2e51bab7ee0f976dd6d87727b508f7cf', + ], + [ + 'PYeAhK5nWPIxGD2F', + '30313233343536373839616263646566', + '0c2b35c26794c55b94228af98ba7378133326361353835323130363730333039 + 3531343463653763663366386462363733666537646466326339303439373730 + 64343038313234393232313362653639dbec4d9abb2dcffbf186366476df34d2 + 500744fd27eda1e0ea0e54280b091d32ebd1e786402507cb3c591503e27f195b', + ], + [ + 'B9u8Tl9tRBgmnSHk', + '3031323334353637383961626364656630', + '8401d45dbce698cf9342152c75cd8f5164356231643534643561646636316462 + 6331373265623831373165363336616165343432383161633962646333373932 + 3139323034393665303863356331363743e5873d38758489b9d5800aabf31f3e + cf36e1e47955f5c96acdf8dc6cc7280c825949d46546796ec5a114985f5fe598', + ], + [ + 'cLHX5BvVQcdlozS6', + '4e161a1df6', + 'e04aed1dc385788c3c777bc7b3cfa20c32656633363730393363366138643831 + 3866303330613461666664623039326437623739613236333566353762333461 + 34653132366163653031303134353161eefebead8d190e854c05f598adfb8d7b + ef30c86c7cc7003f261b8ce26c62da55', + ], + [ + 'r8EZMeBVex-LC3c5', + '5862447074634952357761764253733d', + 'ae03ee587e7df6407a17d43e3381b76563616366633165613463383063353930 + 6163613736656635663234613263323833393131363661333737333133356366 + 3963313236356663373035323264623224b4aa1536a8deba1dfa026efa614fb9 + 4915763a2629a00fe5ff8f1afc894f1b644f9b08ebc7baefc06229f177b5e446', + ], + [ + 'TRS5GvlQ2WCoEzHY', + '82c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c + 040f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed927364446 + 3b1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334a + a4', + 'f05611e02a2cccbfea4679e8110087a061396332303030396562663732626138 + 3530363534313362373731316330363964393564653831636566646261363265 + 38323536366666633438396566323939bce309f535fca3d1fb23e8503f8cf3b8 + bca4c4bcfb4021592268f88070b5203f5023a6a39034e34048bc944c22e037fd + e6ca8ca17e2bdc8169d1e714830de6932cfe0dcdd1728e8bf848a6f4f7154d1c + 0f8c650e0ef650ba3b90372eb6d13e93e3c79610291a523a3967a3049b04f1d4 + c899e1554b04f906c2e6408a16702d19', + ], + [ + 'x_a2LHnyqH8WAwkZ', + 'badec0c7d9ca734e161a1df6ca4daa8cdbf6b3bbb60ec404b47a23226ec266b1 + 3837ffc969e9c23e2bbba72facb491a6a3271193a35026a9ebc93698d689bf7b + 84fc384f544cc5d71c2945c8c48ae6348c753322fcaf75171b7d8f1e178e8545 + 3d5c79f03bae6d9705cabbe7004ec81e188812a66313297fcf5d4c61a48614d2 + 1b5379fae60736f88bc737257bc1cfbef7016108dd1f3a537aaa681544f5bb20 + c2d352212d6a2e460311ab7b93b611218b30c7402709bff89ecf814310c2db97 + 81f4142a54d6d41f82c33208c188a023c70befd697b496efb7c7b8569474a9d5 + 025a8ea8311c831b3de2b81800f28589b6aef537f6ada2e3d92a1ddd39cfd6b4 + 8113c8b36be890b099ca4e08655db0e9b5c211e706af052b776924233321412c + b1b540f08d88acd664c55854b05e31a15d4b0dc93b4514f62a88c3d4a451fe34 + 74d2fbaee742f232959b5f6c2b71a8b6ad95a0d5362f39309aca710f37a4dae2 + 228e27d35f4d3fc87ee6ece4538587fad7835f9803f5ca64dfd856ae767a3482 + c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c04 + 0f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed9273644463b + 1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334aa4 + d998a599053cd477f54fc0af62a8ef75eb91096b153751b201b8374c4956508c + 6c82ea2ceb0265e74c96032787fe01139b578c3a14fd4e32a85195375b25da60 + 4f21187ee01df6042971d7c2b9dd8b611527377f28f933559f6b2edfe7bd8896 + 00627830bcdffcb884989013585cc6da726c7cc57c69e8664a244d234465f2a5 + e736512a65e563a2a726915b50247aff165190c75d151139f2b31211a3acf94e + 236d27b441fe64e88a443778359d57ba0fed8edbb01cc60a116f9599da4e47bf + e96850ac12d1199a080f1b591c60eae613fba444f9fe31fd42ee333678532556 + 07fbfeef02cdbb2d0a8d2329adc7fba22aa4cd124c6e66e0b0aca796ba6aeb69 + f8e76a9d1aaabe351bc42fefa6054977859b51158ba7143980d76db5b2cc6aec + 9f83eac5edf79357632fb60cb4811e71892436e582375860faf8d8c518ee33ca + e08b18af7faa227d97196d7b041bcb366118751fbeaa92d80f86324ce8711cfd + 65005cad0ce30878f508eb1ea2735e212ef3e42a78467d4f31b483087c3c63a3 + 2fa62f2ae92e2acdfc3cf21b3419acc347ff51ccb17161e829cc4a24965fd930 + b983d63153b9c13dd85340d7184bf01734d4357c1aabfbdc9711193ffa974832 + 4f88cf801f35708db0901ffaa55415ca4334678633dda763b5fbfba7cfd51dc5 + 79149ec9284a4db2349dbc5264d5fca7a72034261716d90a996cb57ba09f7d07 + 29a2f10cc58eec98d86e9306a3fbf2e711046e86b5a86cc0eed7625be1a01ebf', + '5d841d0cb575fdb8c7e2cc48be47021d38646237366663323933346163643933 + 3861336335396666356139383066663033336333303731336263663262626136 + 643635333333393362306631333266320d73812258a45d90f8240d59c4e39e87 + 8d4d999f36403a6f0b1d69ab9416792c5e8f2cf427af8423c8213a885fde488c + db95217c64c542f5e2be6b4375ff82e5c72a9f165049546b38295006f50665b1 + 354350de4a68b5f16a18f7df53e0999f4f7ba5ba0676e416a0444d5b7accda8b + 093ae31a23e3cb63b6f404c437071435b8143f282c4cb4403a2b538af5a0d94f + 1e582c3bb9d5379ba5d576643854c232d74f303dcac91a711bf440fb24e7ab2a + 70ef69008ffb59ad2455d4f1482e77114489a3b5a250384b24062f546f86073a + 91fdd85d34bd7814b4ce70ec8d6ea34f98067d7101050f3800f9f1fd92003856 + 223f8ca142749c2ef4c8d1991a62b0ff86623bf9afce65d55fb5efe80089cee4 + e4f12e94e1748c5740f075a94a2290ba2dc892fdfde516ebc190a4db63e77f93 + 54a3bec5ef695572dddcc9d7c43609724c73bc5bfe79d5f322890e4f39a31e6b + 3fb9388c78e133c58e395ca03eca2e8ab9520e4d2e5421e0d9a1f781a564dda7 + 720d56f413312762da078e0226053672983ecf5bdf18086a6f617071814d61e4 + 27e6f02167b8d38e381607e4238f21c0b6e6d9222f1cc6348b9f7d6fb084cc3b + 306b7acbb94f4b3ab6b66fe539865fb804899d3f64c8bca6bd02ee5509022a50 + 03d63e259bb414391fc10ae9b2e42c68a2be743488b69ca77c70741820aaeeb0 + da2ff00c07787a39ec613e665d78c30b5f57a14fcbe24f00cf55eeb174e23dac + a9eb3587bc8dc8fdf5ef062b7f1659b45c48246055fda699b6ae8b9fcc46a380 + ebc6b648662ef5fed1a4fe16c9aa310cc16f5ad642b80549262f5c77335f5435 + a43d30459297b754350a9dd635b0ca5342fc798d369225f6d692eea0c901eb72 + fd10af1199b7847ffc1a0c5915902fe339772183727c31497c752e3beb1cf010 + 2c97ab270def6628bdae630172d73a9fc0afed1d893870003828f64518512886 + 57d62ba52c8d325aa8409b0a40754dc3f84d1c8898e01e20c03464b83d2dae5d + 3d9f279778fb1161ac5d8f9c466fd0c6bdd6a21553ea9252ff018ae99b0d4425 + 0e55d177fb1e0275da97474ea052d85d96b7432c1be840e5994b127b147d1a0c + 64f1cea9115a37225c8b49960e0693680ee5593c81784c850811e1f10ce4f9a3 + 365e3d2d240e0eef8da6404d5a93ebd000a98d5d33dd5a238327e88dfdad2744 + ed0c4321a543c1a3231e53550e816c531b73bafec21e32daeecd199c7a2be75f + 450ce4d39e10ad81a7ca74877e1661376d7cce557a1d4dde53b503e1512efef6 + d607d5074ca8ba29db067454e529aec867907c6eded03ce90835d72974cddcc5 + 83628bd2948a78a2d666ed89889f59b1dd5b05704b7e68a801ad9f93809e0d8a + ae72a72923883d4de81d867bf639eb5dc581429041ca78763235fe11251254c8 + cca8bfe10e8810035e4cce023b6527744d0ea839bb035db99adc3ce742a5491d + c446220a6cb416a0bd3362b424dcdf3e', + ], + ]; + + return static::CRYPT_VECTORS === 'new' ? $openssl : $mcrypt; + } + + /** + * @dataProvider dataProviderEncryptByPasswordCompat + * + * @param string $password encryption password + * @param string $data plaintext hex string + * @param string $encrypted ciphertext hex string + */ + public function testEncryptByPasswordCompat($password, $data, $encrypted) + { + $data = hex2bin(preg_replace('{\s+}', '', $data)); + $encrypted = hex2bin(preg_replace('{\s+}', '', $encrypted)); + + $this->assertEquals($data, $this->security->decryptByPassword($encrypted, $password)); + } + + public function testGenerateRandomKey() + { + $length = 21; + $key = $this->security->generateRandomKey($length); + $this->assertEquals($length, strlen($key)); + } + + public function testGenerateRandomString() + { + $length = 21; + $key = $this->security->generateRandomString($length); + $this->assertEquals($length, strlen($key)); + $this->assertEquals(1, preg_match('/[A-Za-z0-9_-]+/', $key)); + } + + public function dataProviderPbkdf2() + { + return [ + [ + 'sha1', + 'password', + 'salt', + 1, + 20, + '0c60c80f961f0e71f3a9b524af6012062fe037a6' + ], + [ + 'sha1', + 'password', + 'salt', + 2, + 20, + 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957' + ], + [ + 'sha1', + 'password', + 'salt', + 4096, + 20, + '4b007901b765489abead49d926f721d065a429c1' + ], + [ + 'sha1', + 'password', + 'salt', + 16777216, + 20, + 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984' + ], + [ + 'sha1', + 'passwordPASSWORDpassword', + 'saltSALTsaltSALTsaltSALTsaltSALTsalt', + 4096, + 25, + '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038' + ], + [ + 'sha1', + "pass\0word", + "sa\0lt", + 4096, + 16, + '56fa6aa75548099dcc37d7f03425e0c3' + ], + [ + 'sha256', + 'password', + 'salt', + 1, + 20, + '120fb6cffcf8b32c43e7225256c4f837a86548c9' + ], + [ + 'sha256', + "pass\0word", + "sa\0lt", + 4096, + 32, + '89b69d0516f829893c696226650a86878c029ac13ee276509d5ae58b6466a724' + ], + [ + 'sha256', + 'passwordPASSWORDpassword', + 'saltSALTsaltSALTsaltSALTsaltSALTsalt', + 4096, + 40, + '348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9' + ], + ]; + } + + /** + * @dataProvider dataProviderPbkdf2 + * + * @param string $hash + * @param string $password + * @param string $salt + * @param integer $iterations + * @param integer $length + * @param string $okm + */ + public function testPbkdf2($hash, $password, $salt, $iterations, $length, $okm) + { + $this->security->derivationIterations = $iterations; + $DK = $this->security->pbkdf2($hash, $password, $salt, $iterations, $length); + $this->assertEquals($okm, bin2hex($DK)); + } + + public function dataProviderDeriveKey() + { + // See Appendix A in https://tools.ietf.org/html/rfc5869 + return [ + [ + 'Hash' => 'sha256', + 'IKM' => '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', + 'salt' => '000102030405060708090a0b0c', + 'info' => 'f0f1f2f3f4f5f6f7f8f9', + 'L' => 42, + 'PRK' => '077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5', + 'OKM' => '3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865', + ], + [ + 'Hash' => 'sha256', + 'IKM' => '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f', + 'salt' => '606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf', + 'info' => 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', + 'L' => 82, + 'PRK' => '06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244', + 'OKM' => 'b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87', + ], + [ + 'Hash' => 'sha256', + 'IKM' => '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', + 'salt' => '', + 'info' => '', + 'L' => 42, + 'PRK' => '19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04', + 'OKM' => '8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8', + ], + [ + 'Hash' => 'sha1', + 'IKM' => '0b0b0b0b0b0b0b0b0b0b0b', + 'salt' => '000102030405060708090a0b0c', + 'info' => 'f0f1f2f3f4f5f6f7f8f9', + 'L' => 42, + 'PRK' => '9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243', + 'OKM' => '085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896', + ], + [ + 'Hash' => 'sha1', + 'IKM' => '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f', + 'salt' => '606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf', + 'info' => 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', + 'L' => 82, + 'PRK' => '8adae09a2a307059478d309b26c4115a224cfaf6', + 'OKM' => '0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4', + ], + [ + 'Hash' => 'sha1', + 'IKM' => '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', + 'salt' => '', + 'info' => '', + 'L' => 42, + 'PRK' => 'da8c8a73c7fa77288ec6f5e7c297786aa0d32d01', + 'OKM' => '0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918', + ], + [ + 'Hash' => 'sha1', + 'IKM' => '0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c', + 'salt' => null, + 'info' => '', + 'L' => 42, + 'PRK' => '2adccada18779e7c2077ad2eb19d3f3e731385dd', + 'OKM' => '2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48', + ] + ]; + } + + /** + * @dataProvider dataProviderDeriveKey + * + * @param string $hash + * @param string $ikm + * @param string $salt + * @param string $info + * @param integer $l + * @param string $prk + * @param string $okm + */ + public function testHkdf($hash, $ikm, $salt, $info, $l, $prk, $okm) + { + $dk = $this->security->hkdf($hash, hex2bin($ikm), hex2bin($salt), hex2bin($info), $l); + $this->assertEquals($okm, bin2hex($dk)); + } + + public function dataProviderCompareStrings() + { + return [ + ["", ""], + [false, ""], + [null, ""], + [0, ""], + [0.00, ""], + ["", null], + ["", false], + ["", 0], + ["", "\0"], + ["\0", ""], + ["\0", "\0"], + ["0", "\0"], + [0, "\0"], + ["user", "User"], + ["password", "password"], + ["password", "passwordpassword"], + ["password1", "password"], + ["password", "password2"], + ["", "password"], + ["password", ""], + ]; + } + + /** + * @dataProvider dataProviderCompareStrings + * + * @param $expected + * @param $actual + */ + public function testCompareStrings($expected, $actual) + { + $this->assertEquals(strcmp($expected, $actual) === 0, $this->security->compareString($expected, $actual)); + } +} diff --git a/tests/framework/behaviors/SluggableBehaviorTest.php b/tests/framework/behaviors/SluggableBehaviorTest.php new file mode 100644 index 0000000..3bd6b72 --- /dev/null +++ b/tests/framework/behaviors/SluggableBehaviorTest.php @@ -0,0 +1,193 @@ +mockApplication([ + 'components' => [ + 'db' => [ + 'class' => '\yii\db\Connection', + 'dsn' => 'sqlite::memory:', + ] + ] + ]); + + $columns = [ + 'id' => 'pk', + 'name' => 'string', + 'slug' => 'string', + 'category_id' => 'integer', + ]; + Yii::$app->getDb()->createCommand()->createTable('test_slug', $columns)->execute(); + } + + public function tearDown() + { + Yii::$app->getDb()->close(); + parent::tearDown(); + } + + // Tests : + + public function testSlug() + { + $model = new ActiveRecordSluggable(); + $model->name = 'test name'; + $model->validate(); + + $this->assertEquals('test-name', $model->slug); + } + + /** + * @depends testSlug + */ + public function testSlugSeveralAttributes() + { + $model = new ActiveRecordSluggable(); + $model->getBehavior('sluggable')->attribute = array('name', 'category_id'); + + $model->name = 'test'; + $model->category_id = 10; + + $model->validate(); + $this->assertEquals('test-10', $model->slug); + } + + /** + * @depends testSlug + */ + public function testUniqueByIncrement() + { + $name = 'test name'; + + $model = new ActiveRecordSluggableUnique(); + $model->name = $name; + $model->save(); + + $model = new ActiveRecordSluggableUnique(); + $model->sluggable->uniqueSlugGenerator = 'increment'; + $model->name = $name; + $model->save(); + + $this->assertEquals('test-name-2', $model->slug); + } + + /** + * @depends testUniqueByIncrement + */ + public function testUniqueByCallback() + { + $name = 'test name'; + + $model = new ActiveRecordSluggableUnique(); + $model->name = $name; + $model->save(); + + $model = new ActiveRecordSluggableUnique(); + $model->sluggable->uniqueSlugGenerator = function($baseSlug, $iteration) {return $baseSlug . '-callback';}; + $model->name = $name; + $model->save(); + + $this->assertEquals('test-name-callback', $model->slug); + } + + /** + * @depends testSlug + */ + public function testUpdateUnique() + { + $name = 'test name'; + + $model = new ActiveRecordSluggableUnique(); + $model->name = $name; + $model->save(); + + $model->save(); + $this->assertEquals('test-name', $model->slug); + + $model = ActiveRecordSluggableUnique::find()->one(); + $model->save(); + $this->assertEquals('test-name', $model->slug); + + $model->name = 'test-name'; + $model->save(); + $this->assertEquals('test-name', $model->slug); + } +} + +/** + * Test Active Record class with [[SluggableBehavior]] behavior attached. + * + * @property integer $id + * @property string $name + * @property string $slug + * @property integer $category_id + * + * @property SluggableBehavior $sluggable + */ +class ActiveRecordSluggable extends ActiveRecord +{ + public function behaviors() + { + return [ + 'sluggable' => [ + 'class' => SluggableBehavior::className(), + 'attribute' => 'name', + ], + ]; + } + + public static function tableName() + { + return 'test_slug'; + } + + /** + * @return SluggableBehavior + */ + public function getSluggable() + { + return $this->getBehavior('sluggable'); + } +} + +class ActiveRecordSluggableUnique extends ActiveRecordSluggable +{ + public function behaviors() + { + return [ + 'sluggable' => [ + 'class' => SluggableBehavior::className(), + 'attribute' => 'name', + 'ensureUnique' => true, + ], + ]; + } +} \ No newline at end of file diff --git a/tests/framework/behaviors/TimestampBehaviorTest.php b/tests/framework/behaviors/TimestampBehaviorTest.php new file mode 100644 index 0000000..40d6886 --- /dev/null +++ b/tests/framework/behaviors/TimestampBehaviorTest.php @@ -0,0 +1,110 @@ +mockApplication([ + 'components' => [ + 'db' => [ + 'class' => '\yii\db\Connection', + 'dsn' => 'sqlite::memory:', + ] + ] + ]); + + $columns = [ + 'id' => 'pk', + 'created_at' => 'integer', + 'updated_at' => 'integer', + ]; + Yii::$app->getDb()->createCommand()->createTable('test_auto_timestamp', $columns)->execute(); + } + + public function tearDown() + { + Yii::$app->getDb()->close(); + parent::tearDown(); + } + + // Tests : + + public function testNewRecord() + { + $currentTime = time(); + + $model = new ActiveRecordTimestamp(); + $model->save(false); + + $this->assertTrue($model->created_at >= $currentTime); + $this->assertTrue($model->updated_at >= $currentTime); + } + + /** + * @depends testNewRecord + */ + public function testUpdateRecord() + { + $currentTime = time(); + + $model = new ActiveRecordTimestamp(); + $model->save(false); + + $enforcedTime = $currentTime - 100; + + $model->created_at = $enforcedTime; + $model->updated_at = $enforcedTime; + $model->save(false); + + $this->assertEquals($enforcedTime, $model->created_at, 'Create time has been set on update!'); + $this->assertTrue($model->updated_at >= $currentTime, 'Update time has NOT been set on update!'); + } +} + +/** + * Test Active Record class with [[TimestampBehavior]] behavior attached. + * + * @property integer $id + * @property integer $created_at + * @property integer $updated_at + */ +class ActiveRecordTimestamp extends ActiveRecord +{ + public function behaviors() + { + return [ + TimestampBehavior::className(), + ]; + } + + public static function tableName() + { + return 'test_auto_timestamp'; + } +} diff --git a/tests/framework/caching/ApcCacheTest.php b/tests/framework/caching/ApcCacheTest.php new file mode 100644 index 0000000..126471c --- /dev/null +++ b/tests/framework/caching/ApcCacheTest.php @@ -0,0 +1,46 @@ +markTestSkipped("APC not installed. Skipping."); + } elseif ('cli' === PHP_SAPI && !ini_get('apc.enable_cli')) { + $this->markTestSkipped("APC cli is not enabled. Skipping."); + } + + if (!ini_get("apc.enabled") || !ini_get("apc.enable_cli")) { + $this->markTestSkipped("APC is installed but not enabled. Skipping."); + } + + if ($this->_cacheInstance === null) { + $this->_cacheInstance = new ApcCache(); + } + + return $this->_cacheInstance; + } + + public function testExpire() + { + $this->markTestSkipped("APC keys are expiring only on the next request."); + } + + public function testExpireAdd() + { + $this->markTestSkipped("APC keys are expiring only on the next request."); + } +} diff --git a/tests/framework/caching/ArrayCacheTest.php b/tests/framework/caching/ArrayCacheTest.php new file mode 100644 index 0000000..5ec7d73 --- /dev/null +++ b/tests/framework/caching/ArrayCacheTest.php @@ -0,0 +1,49 @@ +_cacheInstance === null) { + $this->_cacheInstance = new ArrayCache(); + } + return $this->_cacheInstance; + } + + public function testExpire() + { + $cache = $this->getCacheInstance(); + + static::$microtime = \microtime(true); + $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); + static::$microtime++; + $this->assertEquals('expire_test', $cache->get('expire_test')); + static::$microtime++; + $this->assertFalse($cache->get('expire_test')); + } + + public function testExpireAdd() + { + $cache = $this->getCacheInstance(); + + static::$microtime = \microtime(true); + $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); + static::$microtime++; + $this->assertEquals('expire_testa', $cache->get('expire_testa')); + static::$microtime++; + $this->assertFalse($cache->get('expire_testa')); + } +} diff --git a/tests/framework/caching/CacheTestCase.php b/tests/framework/caching/CacheTestCase.php new file mode 100644 index 0000000..4d976c4 --- /dev/null +++ b/tests/framework/caching/CacheTestCase.php @@ -0,0 +1,246 @@ +mockApplication(); + } + + protected function tearDown() + { + static::$time = null; + static::$microtime = null; + } + + /** + * @return Cache + */ + public function prepare() + { + $cache = $this->getCacheInstance(); + + $cache->flush(); + $cache->set('string_test', 'string_test'); + $cache->set('number_test', 42); + $cache->set('array_test', ['array_test' => 'array_test']); + $cache['arrayaccess_test'] = new \stdClass(); + + return $cache; + } + + public function testSet() + { + $cache = $this->getCacheInstance(); + + $this->assertTrue($cache->set('string_test', 'string_test')); + $this->assertTrue($cache->set('number_test', 42)); + $this->assertTrue($cache->set('array_test', ['array_test' => 'array_test'])); + } + + public function testGet() + { + $cache = $this->prepare(); + + $this->assertEquals('string_test', $cache->get('string_test')); + + $this->assertEquals(42, $cache->get('number_test')); + + $array = $cache->get('array_test'); + $this->assertArrayHasKey('array_test', $array); + $this->assertEquals('array_test', $array['array_test']); + } + + /** + * @return array testing mset with and without expiry + */ + public function msetExpiry() + { + return [[0], [2]]; + } + + /** + * @dataProvider msetExpiry + */ + public function testMset($expiry) + { + $cache = $this->getCacheInstance(); + $cache->flush(); + + $cache->mset([ + 'string_test' => 'string_test', + 'number_test' => 42, + 'array_test' => ['array_test' => 'array_test'], + ], $expiry); + + $this->assertEquals('string_test', $cache->get('string_test')); + + $this->assertEquals(42, $cache->get('number_test')); + + $array = $cache->get('array_test'); + $this->assertArrayHasKey('array_test', $array); + $this->assertEquals('array_test', $array['array_test']); + } + + public function testExists() + { + $cache = $this->prepare(); + + $this->assertTrue($cache->exists('string_test')); + // check whether exists affects the value + $this->assertEquals('string_test', $cache->get('string_test')); + + $this->assertTrue($cache->exists('number_test')); + $this->assertFalse($cache->exists('not_exists')); + } + + public function testArrayAccess() + { + $cache = $this->getCacheInstance(); + + $cache['arrayaccess_test'] = new \stdClass(); + $this->assertInstanceOf('stdClass', $cache['arrayaccess_test']); + } + + public function testGetNonExistent() + { + $cache = $this->getCacheInstance(); + + $this->assertFalse($cache->get('non_existent_key')); + } + + public function testStoreSpecialValues() + { + $cache = $this->getCacheInstance(); + + $this->assertTrue($cache->set('null_value', null)); + $this->assertNull($cache->get('null_value')); + + $this->assertTrue($cache->set('bool_value', true)); + $this->assertTrue($cache->get('bool_value')); + } + + public function testMget() + { + $cache = $this->prepare(); + + $this->assertEquals(['string_test' => 'string_test', 'number_test' => 42], $cache->mget(['string_test', 'number_test'])); + // ensure that order does not matter + $this->assertEquals(['number_test' => 42, 'string_test' => 'string_test'], $cache->mget(['number_test', 'string_test'])); + $this->assertEquals(['number_test' => 42, 'non_existent_key' => null], $cache->mget(['number_test', 'non_existent_key'])); + } + + public function testExpire() + { + $cache = $this->getCacheInstance(); + + $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); + usleep(500000); + $this->assertEquals('expire_test', $cache->get('expire_test')); + usleep(2500000); + $this->assertFalse($cache->get('expire_test')); + } + + public function testExpireAdd() + { + $cache = $this->getCacheInstance(); + + $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); + usleep(500000); + $this->assertEquals('expire_testa', $cache->get('expire_testa')); + usleep(2500000); + $this->assertFalse($cache->get('expire_testa')); + } + + public function testAdd() + { + $cache = $this->prepare(); + + // should not change existing keys + $this->assertFalse($cache->add('number_test', 13)); + $this->assertEquals(42, $cache->get('number_test')); + + // should store data if it's not there yet + $this->assertFalse($cache->get('add_test')); + $this->assertTrue($cache->add('add_test', 13)); + $this->assertEquals(13, $cache->get('add_test')); + } + + public function testMadd() + { + $cache = $this->prepare(); + + $this->assertFalse($cache->get('add_test')); + + $cache->madd([ + 'number_test' => 13, + 'add_test' => 13, + ]); + + $this->assertEquals(42, $cache->get('number_test')); + $this->assertEquals(13, $cache->get('add_test')); + } + + public function testDelete() + { + $cache = $this->prepare(); + + $this->assertNotNull($cache->get('number_test')); + $this->assertTrue($cache->delete('number_test')); + $this->assertFalse($cache->get('number_test')); + } + + public function testFlush() + { + $cache = $this->prepare(); + $this->assertTrue($cache->flush()); + $this->assertFalse($cache->get('number_test')); + } +} diff --git a/tests/framework/caching/DbCacheTest.php b/tests/framework/caching/DbCacheTest.php new file mode 100644 index 0000000..0036ffe --- /dev/null +++ b/tests/framework/caching/DbCacheTest.php @@ -0,0 +1,99 @@ +markTestSkipped('pdo and pdo_mysql extensions are required.'); + } + + parent::setUp(); + + $this->getConnection()->createCommand(" + CREATE TABLE IF NOT EXISTS cache ( + id char(128) NOT NULL, + expire int(11) DEFAULT NULL, + data LONGBLOB, + PRIMARY KEY (id), + KEY expire (expire) + ); + ")->execute(); + } + + /** + * @param boolean $reset whether to clean up the test database + * @return \yii\db\Connection + */ + public function getConnection($reset = true) + { + if ($this->_connection === null) { + $databases = self::getParam('databases'); + $params = $databases['mysql']; + $db = new \yii\db\Connection; + $db->dsn = $params['dsn']; + $db->username = $params['username']; + $db->password = $params['password']; + if ($reset) { + $db->open(); + $lines = explode(';', file_get_contents($params['fixture'])); + foreach ($lines as $line) { + if (trim($line) !== '') { + $db->pdo->exec($line); + } + } + } + $this->_connection = $db; + } + + return $this->_connection; + } + + /** + * @return DbCache + */ + protected function getCacheInstance() + { + if ($this->_cacheInstance === null) { + $this->_cacheInstance = new DbCache(['db' => $this->getConnection()]); + } + + return $this->_cacheInstance; + } + + public function testExpire() + { + $cache = $this->getCacheInstance(); + + static::$time = \time(); + $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); + static::$time++; + $this->assertEquals('expire_test', $cache->get('expire_test')); + static::$time++; + $this->assertFalse($cache->get('expire_test')); + } + + public function testExpireAdd() + { + $cache = $this->getCacheInstance(); + + static::$time = \time(); + $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); + static::$time++; + $this->assertEquals('expire_testa', $cache->get('expire_testa')); + static::$time++; + $this->assertFalse($cache->get('expire_testa')); + } +} diff --git a/tests/framework/caching/FileCacheTest.php b/tests/framework/caching/FileCacheTest.php new file mode 100644 index 0000000..1c7e183 --- /dev/null +++ b/tests/framework/caching/FileCacheTest.php @@ -0,0 +1,49 @@ +_cacheInstance === null) { + $this->_cacheInstance = new FileCache(['cachePath' => '@yiiunit/runtime/cache']); + } + + return $this->_cacheInstance; + } + + public function testExpire() + { + $cache = $this->getCacheInstance(); + + static::$time = \time(); + $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); + static::$time++; + $this->assertEquals('expire_test', $cache->get('expire_test')); + static::$time++; + $this->assertFalse($cache->get('expire_test')); + } + + public function testExpireAdd() + { + $cache = $this->getCacheInstance(); + + static::$time = \time(); + $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); + static::$time++; + $this->assertEquals('expire_testa', $cache->get('expire_testa')); + static::$time++; + $this->assertFalse($cache->get('expire_testa')); + } +} diff --git a/tests/framework/caching/MemCacheTest.php b/tests/framework/caching/MemCacheTest.php new file mode 100644 index 0000000..d3c35d3 --- /dev/null +++ b/tests/framework/caching/MemCacheTest.php @@ -0,0 +1,51 @@ +markTestSkipped("memcache not installed. Skipping."); + } + + // check whether memcached is running and skip tests if not. + if (!@stream_socket_client('127.0.0.1:11211', $errorNumber, $errorDescription, 0.5)) { + $this->markTestSkipped('No redis server running at ' . '127.0.0.1:11211' . ' : ' . $errorNumber . ' - ' . $errorDescription); + } + + if ($this->_cacheInstance === null) { + $this->_cacheInstance = new MemCache(); + } + + return $this->_cacheInstance; + } + + public function testExpire() + { + if (getenv('TRAVIS') == 'true') { + $this->markTestSkipped('Can not reliably test memcache expiry on travis-ci.'); + } + parent::testExpire(); + } + + public function testExpireAdd() + { + if (getenv('TRAVIS') == 'true') { + $this->markTestSkipped('Can not reliably test memcache expiry on travis-ci.'); + } + parent::testExpireAdd(); + } +} diff --git a/tests/framework/caching/MemCachedTest.php b/tests/framework/caching/MemCachedTest.php new file mode 100644 index 0000000..56a5570 --- /dev/null +++ b/tests/framework/caching/MemCachedTest.php @@ -0,0 +1,51 @@ +markTestSkipped("memcached not installed. Skipping."); + } + + // check whether memcached is running and skip tests if not. + if (!@stream_socket_client('127.0.0.1:11211', $errorNumber, $errorDescription, 0.5)) { + $this->markTestSkipped('No redis server running at ' . '127.0.0.1:11211' . ' : ' . $errorNumber . ' - ' . $errorDescription); + } + + if ($this->_cacheInstance === null) { + $this->_cacheInstance = new MemCache(['useMemcached' => true]); + } + + return $this->_cacheInstance; + } + + public function testExpire() + { + if (getenv('TRAVIS') == 'true') { + $this->markTestSkipped('Can not reliably test memcached expiry on travis-ci.'); + } + parent::testExpire(); + } + + public function testExpireAdd() + { + if (getenv('TRAVIS') == 'true') { + $this->markTestSkipped('Can not reliably test memcached expiry on travis-ci.'); + } + parent::testExpireAdd(); + } +} diff --git a/tests/framework/caching/TagDependencyTest.php b/tests/framework/caching/TagDependencyTest.php new file mode 100644 index 0000000..8b61b27 --- /dev/null +++ b/tests/framework/caching/TagDependencyTest.php @@ -0,0 +1,79 @@ + '@yiiunit/runtime/cache']); + + // single tag test + $cache->set('a1', 11, 0, new TagDependency(['tags' => 't1'])); + $cache->set('a2', 12, 0, new TagDependency(['tags' => 't1'])); + $cache->set('b1', 21, 0, new TagDependency(['tags' => 't2'])); + $cache->set('b2', 22, 0, new TagDependency(['tags' => 't2'])); + + $this->assertEquals(11, $cache->get('a1')); + $this->assertEquals(12, $cache->get('a2')); + $this->assertEquals(21, $cache->get('b1')); + $this->assertEquals(22, $cache->get('b2')); + + TagDependency::invalidate($cache, 't1'); + $this->assertFalse($cache->get('a1')); + $this->assertFalse($cache->get('a2')); + $this->assertEquals(21, $cache->get('b1')); + $this->assertEquals(22, $cache->get('b2')); + + TagDependency::invalidate($cache, 't2'); + $this->assertFalse($cache->get('a1')); + $this->assertFalse($cache->get('a2')); + $this->assertFalse($cache->get('b1')); + $this->assertFalse($cache->get('b2')); + + // multiple tag test + $cache->set('a1', 11, 0, new TagDependency(['tags' => ['t1', 't2']])); + $cache->set('a2', 12, 0, new TagDependency(['tags' => 't1'])); + $cache->set('b1', 21, 0, new TagDependency(['tags' => ['t1', 't2']])); + $cache->set('b2', 22, 0, new TagDependency(['tags' => 't2'])); + + $this->assertEquals(11, $cache->get('a1')); + $this->assertEquals(12, $cache->get('a2')); + $this->assertEquals(21, $cache->get('b1')); + $this->assertEquals(22, $cache->get('b2')); + + TagDependency::invalidate($cache, 't1'); + $this->assertFalse($cache->get('a1')); + $this->assertFalse($cache->get('a2')); + $this->assertFalse($cache->get('b1')); + $this->assertEquals(22, $cache->get('b2')); + + TagDependency::invalidate($cache, 't2'); + $this->assertFalse($cache->get('a1')); + $this->assertFalse($cache->get('a2')); + $this->assertFalse($cache->get('b1')); + $this->assertFalse($cache->get('b2')); + + $cache->set('a1', 11, 0, new TagDependency(['tags' => ['t1', 't2']])); + $cache->set('a2', 12, 0, new TagDependency(['tags' => 't1'])); + $cache->set('b1', 21, 0, new TagDependency(['tags' => ['t1', 't2']])); + $cache->set('b2', 22, 0, new TagDependency(['tags' => 't2'])); + + $this->assertEquals(11, $cache->get('a1')); + $this->assertEquals(12, $cache->get('a2')); + $this->assertEquals(21, $cache->get('b1')); + $this->assertEquals(22, $cache->get('b2')); + + TagDependency::invalidate($cache, ['t1', 't2']); + $this->assertFalse($cache->get('a1')); + $this->assertFalse($cache->get('a2')); + $this->assertFalse($cache->get('b1')); + $this->assertFalse($cache->get('b2')); + } +} diff --git a/tests/framework/caching/WinCacheTest.php b/tests/framework/caching/WinCacheTest.php new file mode 100644 index 0000000..ccf0fdc --- /dev/null +++ b/tests/framework/caching/WinCacheTest.php @@ -0,0 +1,34 @@ +markTestSkipped("Wincache not installed. Skipping."); + } + + if (!ini_get('wincache.ucenabled')) { + $this->markTestSkipped("Wincache user cache disabled. Skipping."); + } + + if ($this->_cacheInstance === null) { + $this->_cacheInstance = new WinCache(); + } + + return $this->_cacheInstance; + } +} diff --git a/tests/framework/caching/XCacheTest.php b/tests/framework/caching/XCacheTest.php new file mode 100644 index 0000000..ca2b79c --- /dev/null +++ b/tests/framework/caching/XCacheTest.php @@ -0,0 +1,30 @@ +markTestSkipped("XCache not installed. Skipping."); + } + + if ($this->_cacheInstance === null) { + $this->_cacheInstance = new XCache(); + } + + return $this->_cacheInstance; + } +} diff --git a/tests/framework/caching/ZendDataCacheTest.php b/tests/framework/caching/ZendDataCacheTest.php new file mode 100644 index 0000000..63c0d10 --- /dev/null +++ b/tests/framework/caching/ZendDataCacheTest.php @@ -0,0 +1,30 @@ +markTestSkipped("Zend Data cache not installed. Skipping."); + } + + if ($this->_cacheInstance === null) { + $this->_cacheInstance = new ZendDataCache(); + } + + return $this->_cacheInstance; + } +} diff --git a/tests/framework/console/controllers/AssetControllerTest.php b/tests/framework/console/controllers/AssetControllerTest.php new file mode 100644 index 0000000..8ef7532 --- /dev/null +++ b/tests/framework/console/controllers/AssetControllerTest.php @@ -0,0 +1,602 @@ +mockApplication(); + $this->testFilePath = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . str_replace('\\', '_', get_class($this)) . uniqid(); + $this->createDir($this->testFilePath); + $this->testAssetsBasePath = $this->testFilePath . DIRECTORY_SEPARATOR . 'assets'; + $this->createDir($this->testAssetsBasePath); + } + + public function tearDown() + { + $this->removeDir($this->testFilePath); + } + + /** + * Creates directory. + * @param string $dirName directory full name. + */ + protected function createDir($dirName) + { + if (!file_exists($dirName)) { + mkdir($dirName, 0777, true); + } + } + + /** + * Removes directory. + * @param string $dirName directory full name + */ + protected function removeDir($dirName) + { + if (!empty($dirName) && file_exists($dirName)) { + exec("rm -rf {$dirName}"); + } + } + + /** + * Creates test asset controller instance. + * @return AssetControllerMock + */ + protected function createAssetController() + { + $module = $this->getMock('yii\\base\\Module', ['fake'], ['console']); + $assetController = new AssetControllerMock('asset', $module); + $assetController->interactive = false; + $assetController->jsCompressor = 'cp {from} {to}'; + $assetController->cssCompressor = 'cp {from} {to}'; + + return $assetController; + } + + /** + * Emulates running of the asset controller action. + * @param string $actionID id of action to be run. + * @param array $args action arguments. + * @return string command output. + */ + protected function runAssetControllerAction($actionID, array $args = []) + { + $controller = $this->createAssetController(); + $controller->run($actionID, $args); + return $controller->flushStdOutBuffer(); + } + + /** + * Creates test compress config. + * @param array[] $bundles asset bundles config. + * @return array config array. + */ + protected function createCompressConfig(array $bundles) + { + static $classNumber = 0; + $classNumber++; + $className = $this->declareAssetBundleClass(['class' => 'AssetBundleAll' . $classNumber]); + $baseUrl = '/test'; + $config = [ + 'bundles' => $bundles, + 'targets' => [ + $className => [ + 'basePath' => $this->testAssetsBasePath, + 'baseUrl' => $baseUrl, + 'js' => 'all.js', + 'css' => 'all.css', + ], + ], + 'assetManager' => [ + 'basePath' => $this->testAssetsBasePath, + 'baseUrl' => '', + ], + ]; + + return $config; + } + + /** + * Creates test compress config file. + * @param string $fileName output file name. + * @param array[] $bundles asset bundles config. + * @throws \Exception on failure. + */ + protected function createCompressConfigFile($fileName, array $bundles) + { + $content = 'createCompressConfig($bundles), true) . ';'; + if (file_put_contents($fileName, $content) <= 0) { + throw new \Exception("Unable to create file '{$fileName}'!"); + } + } + + /** + * Creates test asset file. + * @param string $fileRelativeName file name relative to [[testFilePath]] + * @param string $content file content + * @throws \Exception on failure. + */ + protected function createAssetSourceFile($fileRelativeName, $content) + { + $fileFullName = $this->testFilePath . DIRECTORY_SEPARATOR . $fileRelativeName; + $this->createDir(dirname($fileFullName)); + if (file_put_contents($fileFullName, $content) <= 0) { + throw new \Exception("Unable to create file '{$fileFullName}'!"); + } + } + + /** + * Creates a list of asset source files. + * @param array $files assert source files in format: file/relative/name => fileContent + */ + protected function createAssetSourceFiles(array $files) + { + foreach ($files as $name => $content) { + $this->createAssetSourceFile($name, $content); + } + } + + /** + * Invokes the asset controller method even if it is protected. + * @param string $methodName name of the method to be invoked. + * @param array $args method arguments. + * @return mixed method invoke result. + */ + protected function invokeAssetControllerMethod($methodName, array $args = []) + { + $controller = $this->createAssetController(); + $controllerClassReflection = new \ReflectionClass(get_class($controller)); + $methodReflection = $controllerClassReflection->getMethod($methodName); + $methodReflection->setAccessible(true); + $result = $methodReflection->invokeArgs($controller, $args); + $methodReflection->setAccessible(false); + + return $result; + } + + /** + * Composes asset bundle class source code. + * @param array $config asset bundle config. + * @return string class source code. + */ + protected function composeAssetBundleClassSource(array &$config) + { + $config = array_merge( + [ + 'namespace' => StringHelper::dirname(get_class($this)), + 'class' => 'AppAsset', + 'basePath' => $this->testFilePath, + 'baseUrl' => '', + 'css' => [], + 'js' => [], + 'depends' => [], + ], + $config + ); + foreach ($config as $name => $value) { + if (is_array($value)) { + $config[$name] = var_export($value, true); + } + } + + $source = <<composeAssetBundleClassSource($config); + eval($sourceCode); + + return $config['namespace'] . '\\' . $config['class']; + } + + // Tests : + + public function testActionTemplate() + { + $configFileName = $this->testFilePath . DIRECTORY_SEPARATOR . 'config.php'; + $this->runAssetControllerAction('template', [$configFileName]); + $this->assertTrue(file_exists($configFileName), 'Unable to create config file template!'); + $config = require($configFileName); + $this->assertTrue(is_array($config), 'Invalid config created!'); + } + + public function testActionCompress() + { + // Given : + $cssFiles = [ + 'css/test_body.css' => 'body { + padding-top: 20px; + padding-bottom: 60px; + }', + 'css/test_footer.css' => '.footer { + margin: 20px; + display: block; + }', + ]; + $this->createAssetSourceFiles($cssFiles); + + $jsFiles = [ + 'js/test_alert.js' => "function test() { + alert('Test message'); + }", + 'js/test_sum_ab.js' => "function sumAB(a, b) { + return a + b; + }", + ]; + $this->createAssetSourceFiles($jsFiles); + $assetBundleClassName = $this->declareAssetBundleClass([ + 'css' => array_keys($cssFiles), + 'js' => array_keys($jsFiles), + ]); + + $bundles = [ + $assetBundleClassName + ]; + $bundleFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'bundle.php'; + + $configFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'config2.php'; + $this->createCompressConfigFile($configFile, $bundles); + + // When : + $this->runAssetControllerAction('compress', [$configFile, $bundleFile]); + + // Then : + $this->assertTrue(file_exists($bundleFile), 'Unable to create output bundle file!'); + $compressedBundleConfig = require($bundleFile); + $this->assertTrue(is_array($compressedBundleConfig), 'Output bundle file has incorrect format!'); + $this->assertCount(2, $compressedBundleConfig, 'Output bundle config contains wrong bundle count!'); + + $this->assertArrayHasKey($assetBundleClassName, $compressedBundleConfig, 'Source bundle is lost!'); + $compressedAssetBundleConfig = $compressedBundleConfig[$assetBundleClassName]; + $this->assertEmpty($compressedAssetBundleConfig['css'], 'Compressed bundle css is not empty!'); + $this->assertEmpty($compressedAssetBundleConfig['js'], 'Compressed bundle js is not empty!'); + $this->assertNotEmpty($compressedAssetBundleConfig['depends'], 'Compressed bundle dependency is invalid!'); + + $compressedCssFileName = $this->testAssetsBasePath . DIRECTORY_SEPARATOR . 'all.css'; + $this->assertTrue(file_exists($compressedCssFileName), 'Unable to compress CSS files!'); + $compressedJsFileName = $this->testAssetsBasePath . DIRECTORY_SEPARATOR . 'all.js'; + $this->assertTrue(file_exists($compressedJsFileName), 'Unable to compress JS files!'); + + $compressedCssFileContent = file_get_contents($compressedCssFileName); + foreach ($cssFiles as $name => $content) { + $this->assertContains($content, $compressedCssFileContent, "Source of '{$name}' is missing in combined file!"); + } + $compressedJsFileContent = file_get_contents($compressedJsFileName); + foreach ($jsFiles as $name => $content) { + $this->assertContains($content, $compressedJsFileContent, "Source of '{$name}' is missing in combined file!"); + } + } + + /** + * @depends testActionCompress + * + * @see https://github.com/yiisoft/yii2/issues/5194 + */ + public function testCompressExternalAsset() + { + // Given : + $externalAssetConfig = [ + 'class' => 'ExternalAsset', + 'sourcePath' => null, + 'basePath' => null, + 'js' => [ + '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js', + ], + 'css' => [ + '//ajax.googleapis.com/css/libs/jquery/2.1.1/jquery.ui.min.css' + ], + ]; + $externalAssetBundleClassName = $this->declareAssetBundleClass($externalAssetConfig); + + $cssFiles = [ + 'css/test.css' => 'body { + padding-top: 20px; + padding-bottom: 60px; + }', + ]; + $this->createAssetSourceFiles($cssFiles); + $jsFiles = [ + 'js/test.js' => "function test() { + alert('Test message'); + }", + ]; + $this->createAssetSourceFiles($jsFiles); + $regularAssetBundleClassName = $this->declareAssetBundleClass([ + 'class' => 'RegularAsset', + 'css' => array_keys($cssFiles), + 'js' => array_keys($jsFiles), + 'depends' => [ + $externalAssetBundleClassName + ], + ]); + $bundles = [ + $regularAssetBundleClassName + ]; + $bundleFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'bundle.php'; + + $configFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'config.php'; + $this->createCompressConfigFile($configFile, $bundles); + + // When : + $this->runAssetControllerAction('compress', [$configFile, $bundleFile]); + + // Then : + $this->assertTrue(file_exists($bundleFile), 'Unable to create output bundle file!'); + $compressedBundleConfig = require($bundleFile); + $this->assertTrue(is_array($compressedBundleConfig), 'Output bundle file has incorrect format!'); + $this->assertArrayHasKey($externalAssetBundleClassName, $compressedBundleConfig, 'External bundle is lost!'); + + $compressedExternalAssetConfig = $compressedBundleConfig[$externalAssetBundleClassName]; + $this->assertEquals($externalAssetConfig['js'], $compressedExternalAssetConfig['js'], 'External bundle js is lost!'); + $this->assertEquals($externalAssetConfig['css'], $compressedExternalAssetConfig['css'], 'External bundle css is lost!'); + + $compressedRegularAssetConfig = $compressedBundleConfig[$regularAssetBundleClassName]; + $this->assertContains($externalAssetBundleClassName, $compressedRegularAssetConfig['depends'], 'Dependency on external bundle is lost!'); + } + + /** + * @depends testActionCompress + * + * @see https://github.com/yiisoft/yii2/issues/7539 + */ + public function testDetectCircularDependency() + { + // Given : + $namespace = __NAMESPACE__; + + $this->declareAssetBundleClass([ + 'namespace' => $namespace, + 'class' => 'AssetStart', + 'depends' => [ + $namespace . '\AssetA' + ], + ]); + $this->declareAssetBundleClass([ + 'namespace' => $namespace, + 'class' => 'AssetA', + 'depends' => [ + $namespace . '\AssetB' + ], + ]); + $this->declareAssetBundleClass([ + 'namespace' => $namespace, + 'class' => 'AssetB', + 'depends' => [ + $namespace . '\AssetC' + ], + ]); + $this->declareAssetBundleClass([ + 'namespace' => $namespace, + 'class' => 'AssetC', + 'depends' => [ + $namespace . '\AssetA' + ], + ]); + + $bundles = [ + $namespace . '\AssetStart' + ]; + $bundleFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'bundle.php'; + + $configFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'config.php'; + $this->createCompressConfigFile($configFile, $bundles); + + // Assert : + $expectedExceptionMessage = ": {$namespace}\AssetA -> {$namespace}\AssetB -> {$namespace}\AssetC -> {$namespace}\AssetA"; + $this->setExpectedException('yii\console\Exception', $expectedExceptionMessage); + + // When : + $this->runAssetControllerAction('compress', [$configFile, $bundleFile]); + } + + /** + * Data provider for [[testAdjustCssUrl()]]. + * @return array test data. + */ + public function adjustCssUrlDataProvider() + { + return [ + [ + '.published-same-dir-class {background-image: url(published_same_dir.png);}', + '/test/base/path/assets/input', + '/test/base/path/assets/output', + '.published-same-dir-class {background-image: url(../input/published_same_dir.png);}', + ], + [ + '.published-relative-dir-class {background-image: url(../img/published_relative_dir.png);}', + '/test/base/path/assets/input', + '/test/base/path/assets/output', + '.published-relative-dir-class {background-image: url(../img/published_relative_dir.png);}', + ], + [ + '.static-same-dir-class {background-image: url(\'static_same_dir.png\');}', + '/test/base/path/css', + '/test/base/path/assets/output', + '.static-same-dir-class {background-image: url(\'../../css/static_same_dir.png\');}', + ], + [ + '.static-relative-dir-class {background-image: url("../img/static_relative_dir.png");}', + '/test/base/path/css', + '/test/base/path/assets/output', + '.static-relative-dir-class {background-image: url("../../img/static_relative_dir.png");}', + ], + [ + '.absolute-url-class {background-image: url(http://domain.com/img/image.gif);}', + '/test/base/path/assets/input', + '/test/base/path/assets/output', + '.absolute-url-class {background-image: url(http://domain.com/img/image.gif);}', + ], + [ + '.absolute-url-secure-class {background-image: url(https://secure.domain.com/img/image.gif);}', + '/test/base/path/assets/input', + '/test/base/path/assets/output', + '.absolute-url-secure-class {background-image: url(https://secure.domain.com/img/image.gif);}', + ], + [ + "@font-face { + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'); + }", + '/test/base/path/assets/input/css', + '/test/base/path/assets/output', + "@font-face { + src: url('../input/fonts/glyphicons-halflings-regular.eot'); + src: url('../input/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'); + }", + ], + [ + "@font-face { + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'); + }", + '/test/base/path/assets/input/css', + '/test/base/path/assets', + "@font-face { + src: url('input/fonts/glyphicons-halflings-regular.eot'); + src: url('input/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'); + }", + ], + [ + "@font-face { + src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT==) format('truetype'); + }", + '/test/base/path/assets/input/css', + '/test/base/path/assets/output', + "@font-face { + src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT==) format('truetype'); + }", + ], + [ + '.published-same-dir-class {background-image: url(published_same_dir.png);}', + 'C:\test\base\path\assets\input', + 'C:\test\base\path\assets\output', + '.published-same-dir-class {background-image: url(../input/published_same_dir.png);}', + ], + [ + '.static-root-relative-class {background-image: url(\'/images/static_root_relative.png\');}', + '/test/base/path/css', + '/test/base/path/assets/output', + '.static-root-relative-class {background-image: url(\'/images/static_root_relative.png\');}', + ], + [ + '.published-relative-dir-class {background-image: url(../img/same_relative_dir.png);}', + '/test/base/path/assets/css', + '/test/base/path/assets/css', + '.published-relative-dir-class {background-image: url(../img/same_relative_dir.png);}', + ], + ]; + } + + /** + * @dataProvider adjustCssUrlDataProvider + * + * @param $cssContent + * @param $inputFilePath + * @param $outputFilePath + * @param $expectedCssContent + */ + public function testAdjustCssUrl($cssContent, $inputFilePath, $outputFilePath, $expectedCssContent) + { + $adjustedCssContent = $this->invokeAssetControllerMethod('adjustCssUrl', [$cssContent, $inputFilePath, $outputFilePath]); + + $this->assertEquals($expectedCssContent, $adjustedCssContent, 'Unable to adjust CSS correctly!'); + } + + /** + * Data provider for [[testFindRealPath()]] + * @return array test data + */ + public function findRealPathDataProvider() + { + return [ + [ + '/linux/absolute/path', + '/linux/absolute/path', + ], + [ + '/linux/up/../path', + '/linux/path', + ], + [ + '/linux/twice/up/../../path', + '/linux/path', + ], + [ + '/linux/../mix/up/../path', + '/mix/path', + ], + [ + 'C:\\windows\\absolute\\path', + 'C:\\windows\\absolute\\path', + ], + [ + 'C:\\windows\\up\\..\\path', + 'C:\\windows\\path', + ], + ]; + } + + /** + * @dataProvider findRealPathDataProvider + * + * @param string $sourcePath + * @param string $expectedRealPath + */ + public function testFindRealPath($sourcePath, $expectedRealPath) + { + $expectedRealPath = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $expectedRealPath); + $realPath = $this->invokeAssetControllerMethod('findRealPath', [$sourcePath]); + $this->assertEquals($expectedRealPath, $realPath); + } +} + +/** + * Mock class for [[\yii\console\controllers\AssetController]] + */ +class AssetControllerMock extends AssetController +{ + use StdOutBufferControllerTrait; +} \ No newline at end of file diff --git a/tests/framework/console/controllers/BaseMessageControllerTest.php b/tests/framework/console/controllers/BaseMessageControllerTest.php new file mode 100644 index 0000000..f720837 --- /dev/null +++ b/tests/framework/console/controllers/BaseMessageControllerTest.php @@ -0,0 +1,385 @@ +mockApplication(); + $this->sourcePath = Yii::getAlias('@yiiunit/runtime/test_source'); + FileHelper::createDirectory($this->sourcePath, 0777); + if (!file_exists($this->sourcePath)) { + $this->markTestIncomplete('Unit tests runtime directory should have writable permissions!'); + } + $this->configFileName = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . 'message_controller_test_config.php'; + } + + public function tearDown() + { + FileHelper::removeDirectory($this->sourcePath); + if (file_exists($this->configFileName)) { + unlink($this->configFileName); + } + } + + /** + * Creates test message controller instance. + * @return MessageControllerMock message command instance. + */ + protected function createMessageController() + { + $module = $this->getMock('yii\\base\\Module', ['fake'], ['console']); + $messageController = new MessageControllerMock('message', $module); + $messageController->interactive = false; + + return $messageController; + } + + /** + * Emulates running of the message controller action. + * @param string $actionID id of action to be run. + * @param array $args action arguments. + * @return string command output. + */ + protected function runMessageControllerAction($actionID, array $args = []) + { + $controller = $this->createMessageController(); + $controller->run($actionID, $args); + return $controller->flushStdOutBuffer(); + } + + /** + * Creates message command config file named as [[configFileName]]. + * @param array $config message command config. + */ + protected function saveConfigFile(array $config) + { + if (file_exists($this->configFileName)) { + unlink($this->configFileName); + } + $fileContent = 'configFileName, $fileContent); + } + + /** + * Creates source file with given content + * @param string $content file content + * @return string path to source file + */ + protected function createSourceFile($content) + { + $fileName = $this->sourcePath . DIRECTORY_SEPARATOR . md5(uniqid()) . '.php'; + file_put_contents($fileName, "getDefaultConfig(), $additionalConfig); + } + + // Tests: + + public function testActionConfig() + { + $configFileName = $this->configFileName; + $out = $this->runMessageControllerAction('config', [$configFileName]); + $this->assertTrue(file_exists($configFileName), "Unable to create config file from template. Command output:\n\n" . $out); + } + + public function testConfigFileNotExist() + { + $this->setExpectedException('yii\\console\\Exception'); + $this->runMessageControllerAction('extract', ['not_existing_file.php']); + } + + public function testCreateTranslation() + { + $category = 'test.category1'; + $message = 'test message'; + $sourceFileContent = "Yii::t('{$category}', '{$message}');"; + $this->createSourceFile($sourceFileContent); + + $this->saveConfigFile($this->getConfig()); + $out = $this->runMessageControllerAction('extract', [$this->configFileName]); + + $messages = $this->loadMessages($category); + $this->assertArrayHasKey($message, $messages, "\"$message\" is missing in translation file. Command output:\n\n" . $out); + } + + /** + * @depends testCreateTranslation + */ + public function testNothingToSave() + { + $category = 'test_category2'; + $message = 'test message'; + $sourceFileContent = "Yii::t('{$category}', '{$message}')"; + $this->createSourceFile($sourceFileContent); + + $this->saveConfigFile($this->getConfig()); + $out = $this->runMessageControllerAction('extract', [$this->configFileName]); + $out .= $this->runMessageControllerAction('extract', [$this->configFileName]); + + $this->assertTrue(strpos($out, 'Nothing to save') !== false, "Controller should respond with \"Nothing to save\" if there's nothing to update. Command output:\n\n" . $out); + } + + /** + * @depends testCreateTranslation + */ + public function testMerge() + { + $category = 'test_category3'; + + $existingMessage = 'test existing message'; + $existingMessageTranslation = 'test existing message translation'; + $this->saveMessages( + [$existingMessage => $existingMessageTranslation], + $category + ); + + $newMessage = 'test new message'; + $sourceFileContent = "Yii::t('{$category}', '{$existingMessage}');"; + $sourceFileContent .= "Yii::t('{$category}', '{$newMessage}');"; + $this->createSourceFile($sourceFileContent); + + $this->saveConfigFile($this->getConfig()); + $out = $this->runMessageControllerAction('extract', [$this->configFileName]); + + $messages = $this->loadMessages($category); + $this->assertArrayHasKey($newMessage, $messages, "Unable to add new message: \"$newMessage\". Command output:\n\n" . $out); + $this->assertArrayHasKey($existingMessage, $messages, "Unable to keep existing message: \"$existingMessage\". Command output:\n\n" . $out); + $this->assertEquals('', $messages[$newMessage], "Wrong new message content. Command output:\n\n" . $out); + $this->assertEquals($existingMessageTranslation, $messages[$existingMessage], "Unable to keep existing message content. Command output:\n\n" . $out); + } + + /** + * @depends testMerge + */ + public function testMarkObsoleteMessages() + { + $category = 'category'; + + $obsoleteMessage = 'obsolete message'; + $obsoleteTranslation = 'obsolete translation'; + $this->saveMessages([$obsoleteMessage => $obsoleteTranslation], $category); + + $sourceFileContent = "Yii::t('{$category}', 'any new message');"; + $this->createSourceFile($sourceFileContent); + + $this->saveConfigFile($this->getConfig(['removeUnused' => false])); + $out = $this->runMessageControllerAction('extract', [$this->configFileName]); + + $messages = $this->loadMessages($category); + + $this->assertArrayHasKey($obsoleteMessage, $messages, "Obsolete message should not be removed. Command output:\n\n" . $out); + $this->assertEquals('@@' . $obsoleteTranslation . '@@', $messages[$obsoleteMessage], "Obsolete message was not marked properly. Command output:\n\n" . $out); + } + + /** + * @depends testMerge + */ + public function removeObsoleteMessages() + { + $category = 'category'; + + $obsoleteMessage = 'obsolete message'; + $obsoleteTranslation = 'obsolete translation'; + $this->saveMessages([$obsoleteMessage => $obsoleteTranslation], $category); + + $sourceFileContent = "Yii::t('{$category}', 'any new message');"; + $this->createSourceFile($sourceFileContent); + + $this->saveConfigFile($this->getConfig(['removeUnused' => true])); + $out = $this->runMessageControllerAction('extract', [$this->configFileName]); + + $messages = $this->loadMessages($category); + + $this->assertArrayHasKey($obsoleteMessage, $messages, "Obsolete message should be removed. Command output:\n\n" . $out); + } + + /** + * @depends testMerge + */ + public function testMergeWithContentZero() + { + $category = 'test_category5'; + + $zeroMessage = 'test zero message'; + $zeroMessageContent = '0'; + $falseMessage = 'test false message'; + $falseMessageContent = 'false'; + $this->saveMessages([ + $zeroMessage => $zeroMessageContent, + $falseMessage => $falseMessageContent, + ], $category); + + $newMessage = 'test new message'; + $sourceFileContent = "Yii::t('{$category}', '{$zeroMessage}')"; + $sourceFileContent .= "Yii::t('{$category}', '{$falseMessage}')"; + $sourceFileContent .= "Yii::t('{$category}', '{$newMessage}')"; + $this->createSourceFile($sourceFileContent); + + $this->saveConfigFile($this->getConfig()); + $out = $this->runMessageControllerAction('extract', [$this->configFileName]); + + $messages = $this->loadMessages($category); + $this->assertTrue($zeroMessageContent === $messages[$zeroMessage], "Message content \"0\" is lost. Command output:\n\n" . $out); + $this->assertTrue($falseMessageContent === $messages[$falseMessage], "Message content \"false\" is lost. Command output:\n\n" . $out); + } + + /** + * @depends testCreateTranslation + */ + public function testMultipleTranslators() + { + $category = 'test_category6'; + + $translators = [ + 'Yii::t', + 'Custom::translate', + ]; + + $sourceMessages = [ + 'first message', + 'second message', + ]; + $sourceFileContent = ''; + foreach ($sourceMessages as $key => $message) { + $sourceFileContent .= $translators[$key] . "('{$category}', '{$message}');\n"; + } + $this->createSourceFile($sourceFileContent); + + $this->saveConfigFile($this->getConfig(['translator' => $translators])); + $this->runMessageControllerAction('extract', [$this->configFileName]); + + $messages = $this->loadMessages($category); + + foreach ($sourceMessages as $sourceMessage) { + $this->assertArrayHasKey($sourceMessage, $messages); + } + } + + /** + * @depends testCreateTranslation + */ + public function testMultipleCategories() + { + $category1 = 'category1'; + $category2 = 'category2'; + + $message1 = 'message1'; + $message2 = 'message2'; + $message3 = 'message3'; + + $this->saveConfigFile($this->getConfig(['removeUnused' => true])); + + // Generate initial translation + $sourceFileContent = "Yii::t('{$category1}', '{$message1}'); Yii::t('{$category2}', '{$message2}');"; + $source = $this->createSourceFile($sourceFileContent); + $out = $this->runMessageControllerAction('extract', [$this->configFileName]); + unlink($source); + + $messages1 = $this->loadMessages($category1); + $messages2 = $this->loadMessages($category2); + + $this->assertArrayHasKey($message1, $messages1, "message1 not found in category1. Command output:\n\n" . $out); + $this->assertArrayHasKey($message2, $messages2, "message2 not found in category2. Command output:\n\n" . $out); + $this->assertArrayNotHasKey($message3, $messages2, "message3 found in category2. Command output:\n\n" . $out); + + // Change source code, run translation again + $sourceFileContent = "Yii::t('{$category1}', '{$message1}'); Yii::t('{$category2}', '{$message3}');"; + $source = $this->createSourceFile($sourceFileContent); + $out .= "\n" . $this->runMessageControllerAction('extract', [$this->configFileName]); + unlink($source); + + $messages1 = $this->loadMessages($category1); + $messages2 = $this->loadMessages($category2); + $this->assertArrayHasKey($message1, $messages1, "message1 not found in category1. Command output:\n\n" . $out); + $this->assertArrayHasKey($message3, $messages2, "message3 not found in category2. Command output:\n\n" . $out); + $this->assertArrayNotHasKey($message2, $messages2, "message2 found in category2. Command output:\n\n" . $out); + } + + public function testIgnoreCategories() + { + $category1 = 'category1'; + $category2 = 'category2'; + + $message1 = 'message1'; + $message2 = 'message2'; + $message3 = 'message3'; + + $this->saveConfigFile($this->getConfig(['ignoreCategories' => ['category2']])); + + // Generate initial translation + $sourceFileContent = "Yii::t('{$category1}', '{$message1}'); Yii::t('{$category2}', '{$message2}');"; + $source = $this->createSourceFile($sourceFileContent); + $out = $this->runMessageControllerAction('extract', [$this->configFileName]); + unlink($source); + + $messages1 = $this->loadMessages($category1); + $messages2 = $this->loadMessages($category2, false); + + $this->assertArrayHasKey($message1, $messages1, "message1 not found in category1. Command output:\n\n" . $out); + $this->assertArrayNotHasKey($message2, $messages2, "message2 found in category2. Command output:\n\n" . $out); + $this->assertArrayNotHasKey($message3, $messages2, "message3 found in category2. Command output:\n\n" . $out); + + // Change source code, run translation again + $sourceFileContent = "Yii::t('{$category1}', '{$message1}'); Yii::t('{$category2}', '{$message3}');"; + $source = $this->createSourceFile($sourceFileContent); + $out .= "\n" . $this->runMessageControllerAction('extract', [$this->configFileName]); + unlink($source); + + $messages1 = $this->loadMessages($category1); + $messages2 = $this->loadMessages($category2, false); + $this->assertArrayHasKey($message1, $messages1, "message1 not found in category1. Command output:\n\n" . $out); + $this->assertArrayNotHasKey($message3, $messages2, "message3 not found in category2. Command output:\n\n" . $out); + $this->assertArrayNotHasKey($message2, $messages2, "message2 found in category2. Command output:\n\n" . $out); + } +} + +class MessageControllerMock extends MessageController +{ + use StdOutBufferControllerTrait; +} \ No newline at end of file diff --git a/tests/framework/console/controllers/CacheControllerTest.php b/tests/framework/console/controllers/CacheControllerTest.php new file mode 100644 index 0000000..73e00d1 --- /dev/null +++ b/tests/framework/console/controllers/CacheControllerTest.php @@ -0,0 +1,143 @@ +_cacheController = Yii::createObject([ + 'class' => 'yiiunit\framework\console\controllers\SilencedCacheController', + 'interactive' => false, + ],[null, null]); //id and module are null + + $databases = self::getParam('databases'); + $config = $databases[$this->driverName]; + $pdoDriver = 'pdo_' . $this->driverName; + + if (!extension_loaded('pdo') || !extension_loaded($pdoDriver)) { + $this->markTestSkipped('pdo and ' . $pdoDriver . ' extensions are required.'); + } + + + $this->mockApplication([ + 'components' => [ + 'firstCache' => 'yii\caching\ArrayCache', + 'secondCache' => 'yii\caching\ArrayCache', + 'session' => 'yii\web\CacheSession', // should be ignored at `actionFlushAll()` + 'db' => [ + 'class' => isset($config['class']) ? $config['class'] : 'yii\db\Connection', + 'dsn' => $config['dsn'], + 'username' => isset($config['username']) ? $config['username'] : null, + 'password' => isset($config['password']) ? $config['password'] : null, + 'enableSchemaCache' => true, + 'schemaCache' => 'firstCache', + ], + ], + ]); + + if(isset($config['fixture'])) { + Yii::$app->db->open(); + $lines = explode(';', file_get_contents($config['fixture'])); + foreach ($lines as $line) { + if (trim($line) !== '') { + Yii::$app->db->pdo->exec($line); + } + } + } + } + + public function testFlushOne() + { + Yii::$app->firstCache->set('firstKey', 'firstValue'); + Yii::$app->firstCache->set('secondKey', 'secondValue'); + Yii::$app->secondCache->set('thirdKey', 'thirdValue'); + + $this->_cacheController->actionFlush('firstCache'); + + $this->assertFalse(Yii::$app->firstCache->get('firstKey'),'first cache data should be flushed'); + $this->assertFalse(Yii::$app->firstCache->get('secondKey'),'first cache data should be flushed'); + $this->assertEquals('thirdValue', Yii::$app->secondCache->get('thirdKey'), 'second cache data should not be flushed'); + } + + public function testClearSchema() + { + $schema = Yii::$app->db->schema; + Yii::$app->db->createCommand()->createTable('test_schema_cache', ['id' => 'pk'])->execute(); + $noCacheSchemas = $schema->getTableSchemas('', true); + $cacheSchema = $schema->getTableSchemas('', false); + + $this->assertEquals($noCacheSchemas, $cacheSchema, 'Schema should not be modified.'); + + Yii::$app->db->createCommand()->dropTable('test_schema_cache')->execute(); + $noCacheSchemas = $schema->getTableSchemas('', true); + $this->assertNotEquals($noCacheSchemas, $cacheSchema, 'Schemas should be different.'); + + $this->_cacheController->actionFlushSchema('db'); + $cacheSchema = $schema->getTableSchemas('', false); + $this->assertEquals($noCacheSchemas, $cacheSchema, 'Schema cache should be flushed.'); + + } + + public function testFlushBoth() + { + Yii::$app->firstCache->set('firstKey', 'firstValue'); + Yii::$app->firstCache->set('secondKey', 'secondValue'); + Yii::$app->secondCache->set('thirdKey', 'secondValue'); + + $this->_cacheController->actionFlush('firstCache', 'secondCache'); + + $this->assertFalse(Yii::$app->firstCache->get('firstKey'),'first cache data should be flushed'); + $this->assertFalse(Yii::$app->firstCache->get('secondKey'),'first cache data should be flushed'); + $this->assertFalse(Yii::$app->secondCache->get('thirdKey'), 'second cache data should be flushed'); + } + + public function testNotFoundFlush() + { + Yii::$app->firstCache->set('firstKey', 'firstValue'); + + $this->_cacheController->actionFlush('notExistingCache'); + + $this->assertEquals('firstValue', Yii::$app->firstCache->get('firstKey'), 'first cache data should not be flushed'); + } + + /** + * @expectedException \yii\console\Exception + */ + public function testNothingToFlushException() + { + $this->_cacheController->actionFlush(); + } + + public function testFlushAll() + { + Yii::$app->firstCache->set('firstKey', 'firstValue'); + Yii::$app->secondCache->set('thirdKey', 'secondValue'); + + $this->_cacheController->actionFlushAll(); + + $this->assertFalse(Yii::$app->firstCache->get('firstKey'),'first cache data should be flushed'); + $this->assertFalse(Yii::$app->secondCache->get('thirdKey'), 'second cache data should be flushed'); + } + +} diff --git a/tests/framework/console/controllers/EchoMigrateController.php b/tests/framework/console/controllers/EchoMigrateController.php new file mode 100644 index 0000000..9e362bd --- /dev/null +++ b/tests/framework/console/controllers/EchoMigrateController.php @@ -0,0 +1,18 @@ +_fixtureController = Yii::createObject([ + 'class' => 'yiiunit\framework\console\controllers\FixtureConsoledController', + 'interactive' => false, + 'globalFixtures' => [], + 'namespace' => 'yiiunit\data\console\controllers\fixtures', + ],[null, null]); //id and module are null + } + + protected function tearDown() + { + $this->_fixtureController = null; + FixtureStorage::clear(); + + parent::tearDown(); + } + + public function testLoadGlobalFixture() + { + $this->_fixtureController->globalFixtures = [ + '\yiiunit\data\console\controllers\fixtures\Global' + ]; + + $this->_fixtureController->actionLoad('First'); + + $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + } + + public function testUnloadGlobalFixture() + { + $this->_fixtureController->globalFixtures = [ + '\yiiunit\data\console\controllers\fixtures\Global' + ]; + + FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; + FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; + + $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + + $this->_fixtureController->actionUnload('First'); + + $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should be unloaded'); + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); + } + + public function testLoadAll() + { + $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should be empty'); + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be empty'); + $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should be empty'); + + $this->_fixtureController->actionLoad('*'); + + $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$secondFixtureData, 'second fixture data should be loaded'); + } + + public function testUnloadAll() + { + FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; + FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; + FixtureStorage::$secondFixtureData[] = 'some seeded second fixture data'; + + $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$secondFixtureData, 'second fixture data should be loaded'); + + $this->_fixtureController->actionUnload('*'); + + $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should be unloaded'); + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); + $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should be unloaded'); + } + + public function testLoadParticularExceptOnes() + { + $this->_fixtureController->actionLoad('First', '-Second', '-Global'); + + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be loaded'); + $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be loaded'); + } + + public function testUnloadParticularExceptOnes() + { + FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; + FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; + FixtureStorage::$secondFixtureData[] = 'some seeded second fixture data'; + + $this->_fixtureController->actionUnload('First', '-Second', '-Global'); + + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); + $this->assertNotEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be unloaded'); + $this->assertNotEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be unloaded'); + } + + public function testLoadAllExceptOnes() + { + $this->_fixtureController->actionLoad('*', '-Second', '-Global'); + + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be loaded'); + $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be loaded'); + } + + public function testUnloadAllExceptOnes() + { + FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; + FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; + FixtureStorage::$secondFixtureData[] = 'some seeded second fixture data'; + + $this->_fixtureController->actionUnload('*', '-Second', '-Global'); + + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); + $this->assertNotEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be unloaded'); + $this->assertNotEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be unloaded'); + } + + public function testNothingToLoadParticularExceptOnes() + { + $this->_fixtureController->actionLoad('First', '-First'); + + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should not be loaded'); + } + + public function testNothingToUnloadParticularExceptOnes() + { + $this->_fixtureController->actionUnload('First', '-First'); + + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should not be loaded'); + } + + /** + * @expectedException \yii\console\Exception + */ + public function testNoFixturesWereFoundInLoad() + { + $this->_fixtureController->actionLoad('NotExistingFixture'); + } + + /** + * @expectedException \yii\console\Exception + */ + public function testNoFixturesWereFoundInUnload() + { + $this->_fixtureController->actionUnload('NotExistingFixture'); + } + +} + +class FixtureConsoledController extends FixtureController +{ + + public function stdout($string) + { + } + +} diff --git a/tests/framework/console/controllers/MigrateControllerTest.php b/tests/framework/console/controllers/MigrateControllerTest.php new file mode 100644 index 0000000..02346fe --- /dev/null +++ b/tests/framework/console/controllers/MigrateControllerTest.php @@ -0,0 +1,53 @@ +migrateControllerClass = EchoMigrateController::className(); + $this->migrationBaseClass = Migration::className(); + + $this->mockApplication([ + 'components' => [ + 'db' => [ + 'class' => 'yii\db\Connection', + 'dsn' => 'sqlite::memory:', + ], + ], + ]); + + $this->setUpMigrationPath(); + parent::setUp(); + } + + public function tearDown() + { + $this->tearDownMigrationPath(); + parent::tearDown(); + } + + /** + * @return array applied migration entries + */ + protected function getMigrationHistory() + { + $query = new Query(); + return $query->from('migration')->all(); + } +} \ No newline at end of file diff --git a/tests/framework/console/controllers/MigrateControllerTestTrait.php b/tests/framework/console/controllers/MigrateControllerTestTrait.php new file mode 100644 index 0000000..ec8315b --- /dev/null +++ b/tests/framework/console/controllers/MigrateControllerTestTrait.php @@ -0,0 +1,258 @@ +migrationPath = Yii::getAlias('@yiiunit/runtime/test_migrations'); + FileHelper::createDirectory($this->migrationPath); + if (!file_exists($this->migrationPath)) { + $this->markTestIncomplete('Unit tests runtime directory should have writable permissions!'); + } + } + + public function tearDownMigrationPath() + { + FileHelper::removeDirectory($this->migrationPath); + } + + /** + * @return array applied migration entries + */ + abstract protected function getMigrationHistory(); + + /** + * Creates test migrate controller instance. + * @return BaseMigrateController migrate command instance. + */ + protected function createMigrateController() + { + $module = $this->getMock('yii\\base\\Module', ['fake'], ['console']); + $class = $this->migrateControllerClass; + $migrateController = new $class('migrate', $module); + $migrateController->interactive = false; + $migrateController->migrationPath = $this->migrationPath; + return $migrateController; + } + + /** + * Emulates running of the migrate controller action. + * @param string $actionID id of action to be run. + * @param array $args action arguments. + * @return string command output. + */ + protected function runMigrateControllerAction($actionID, array $args = []) + { + $controller = $this->createMigrateController(); + ob_start(); + ob_implicit_flush(false); + $controller->run($actionID, $args); + + return ob_get_clean(); + } + + /** + * @param string $name + * @param string|null $date + * @return string generated class name + */ + protected function createMigration($name, $date = null) + { + if ($date === null) { + $date = gmdate('ymd_His'); + } + $class = 'm' . $date . '_' . $name; + $baseClass = $this->migrationBaseClass; + + $code = <<migrationPath . DIRECTORY_SEPARATOR . $class . '.php', $code); + return $class; + } + + /** + * Checks if applied migration history matches expected one. + * @param array $expectedMigrations migration names in expected order + * @param string $message failure message + */ + protected function assertMigrationHistory(array $expectedMigrations, $message = '') + { + $success = true; + $migrationHistory = $this->getMigrationHistory(); + $appliedMigrations = $migrationHistory; + foreach ($expectedMigrations as $expectedMigrationName) { + $appliedMigration = array_shift($appliedMigrations); + if (strpos($appliedMigration['version'], $expectedMigrationName) === false) { + $success = false; + break; + } + } + if (!$success) { + $message .= "\n"; + $message .= "Expected: " . var_export($expectedMigrations, true) . "\n"; + + $actualMigrations = []; + foreach ($migrationHistory as $row) { + $actualMigrations[] = $row['version']; + } + $message .= "Actual: " . var_export($actualMigrations, true) . "\n"; + } + $this->assertTrue($success, $message); + } + + // Tests : + + public function testCreate() + { + $migrationName = 'test_migration'; + $this->runMigrateControllerAction('create', [$migrationName]); + $files = FileHelper::findFiles($this->migrationPath); + $this->assertCount(1, $files, 'Unable to create new migration!'); + $this->assertContains($migrationName, basename($files[0]), 'Wrong migration name!'); + } + + public function testUp() + { + $this->createMigration('test1'); + $this->createMigration('test2'); + + $this->runMigrateControllerAction('up'); + + $this->assertMigrationHistory(['base', 'test1', 'test2']); + } + + /** + * @depends testUp + */ + public function testUpCount() + { + $this->createMigration('test1'); + $this->createMigration('test2'); + + $this->runMigrateControllerAction('up', [1]); + + $this->assertMigrationHistory(['base', 'test1']); + } + + /** + * @depends testUp + */ + public function testDownCount() + { + $this->createMigration('test1'); + $this->createMigration('test2'); + + $this->runMigrateControllerAction('up'); + $this->runMigrateControllerAction('down', [1]); + + $this->assertMigrationHistory(['base', 'test1']); + } + + /** + * @depends testDownCount + */ + public function testDownAll() + { + $this->createMigration('test1'); + $this->createMigration('test2'); + + $this->runMigrateControllerAction('up'); + $this->runMigrateControllerAction('down', ['all']); + + $this->assertMigrationHistory(['base']); + } + + /** + * @depends testUp + */ + public function testHistory() + { + $output = $this->runMigrateControllerAction('history'); + $this->assertContains('No migration', $output); + + $this->createMigration('test1'); + $this->createMigration('test2'); + $this->runMigrateControllerAction('up'); + + $output = $this->runMigrateControllerAction('history'); + $this->assertContains('_test1', $output); + $this->assertContains('_test2', $output); + } + + /** + * @depends testUp + */ + public function testNew() + { + $this->createMigration('test1'); + + $output = $this->runMigrateControllerAction('new'); + $this->assertContains('_test1', $output); + + $this->runMigrateControllerAction('up'); + + $output = $this->runMigrateControllerAction('new'); + $this->assertNotContains('_test1', $output); + } + + public function testMark() + { + $version = '010101_000001'; + $this->createMigration('test1', $version); + + $this->runMigrateControllerAction('mark', [$version]); + + $this->assertMigrationHistory(['base', 'test1']); + } + + /** + * @depends testUp + */ + public function testRedo() + { + $this->createMigration('test1'); + $this->runMigrateControllerAction('up'); + + $this->runMigrateControllerAction('redo'); + + $this->assertMigrationHistory(['base', 'test1']); + } +} \ No newline at end of file diff --git a/tests/framework/console/controllers/PHPMessageControllerTest.php b/tests/framework/console/controllers/PHPMessageControllerTest.php new file mode 100644 index 0000000..918c49d --- /dev/null +++ b/tests/framework/console/controllers/PHPMessageControllerTest.php @@ -0,0 +1,87 @@ +messagePath = Yii::getAlias('@yiiunit/runtime/test_messages'); + FileHelper::createDirectory($this->messagePath, 0777); + } + + public function tearDown() + { + parent::tearDown(); + FileHelper::removeDirectory($this->messagePath); + } + + /** + * @inheritdoc + */ + protected function getDefaultConfig() + { + return [ + 'format' => 'php', + 'languages' => [$this->language], + 'sourcePath' => $this->sourcePath, + 'messagePath' => $this->messagePath, + 'overwrite' => true, + ]; + } + + /** + * @param string $category + * @return string message file path + */ + protected function getMessageFilePath($category) + { + return $this->messagePath . '/' . $this->language . '/' . $category . '.php'; + } + + /** + * @inheritdoc + */ + protected function saveMessages($messages, $category) + { + $fileName = $this->getMessageFilePath($category); + if (file_exists($fileName)) { + unlink($fileName); + } else { + $dirName = dirname($fileName); + if (!file_exists($dirName)) { + mkdir($dirName, 0777, true); + } + } + $fileContent = 'getMessageFilePath($category); + + if (!file_exists($messageFilePath)) { + return []; + } + return require $messageFilePath; + } +} \ No newline at end of file diff --git a/tests/framework/console/controllers/POMessageControllerTest.php b/tests/framework/console/controllers/POMessageControllerTest.php new file mode 100644 index 0000000..18f2c74 --- /dev/null +++ b/tests/framework/console/controllers/POMessageControllerTest.php @@ -0,0 +1,87 @@ +markTestSkipped('POMessageControllerTest can not run on HHVM because it relies on saving and re-including PHP files which is not supported by HHVM.'); + } + + $this->messagePath = Yii::getAlias('@yiiunit/runtime/test_messages'); + FileHelper::createDirectory($this->messagePath, 0777); + } + + public function tearDown() + { + parent::tearDown(); + FileHelper::removeDirectory($this->messagePath); + } + + /** + * @inheritdoc + */ + protected function getDefaultConfig() + { + return [ + 'format' => 'po', + 'languages' => [$this->language], + 'sourcePath' => $this->sourcePath, + 'messagePath' => $this->messagePath, + 'overwrite' => true, + ]; + } + + /** + * @return string message file path + */ + protected function getMessageFilePath() + { + return $this->messagePath . '/' . $this->language . '/' . $this->catalog . '.po'; + } + + /** + * @inheritdoc + */ + protected function saveMessages($messages, $category) + { + $messageFilePath = $this->getMessageFilePath(); + FileHelper::createDirectory(dirname($messageFilePath), 0777); + $gettext = new GettextPoFile(); + + $data = []; + foreach ($messages as $message => $translation) { + $data[$category . chr(4) . $message] = $translation; + } + + $gettext->save($messageFilePath, $data); + } + + /** + * @inheritdoc + */ + protected function loadMessages($category) + { + $messageFilePath = $this->getMessageFilePath(); + if (!file_exists($messageFilePath)) { + return []; + } + + $gettext = new GettextPoFile(); + return $gettext->load($messageFilePath, $category); + } +} \ No newline at end of file diff --git a/tests/framework/console/controllers/SilencedCacheController.php b/tests/framework/console/controllers/SilencedCacheController.php new file mode 100644 index 0000000..40eed6e --- /dev/null +++ b/tests/framework/console/controllers/SilencedCacheController.php @@ -0,0 +1,20 @@ +stdOutBuffer .= $string; + } + + public function flushStdOutBuffer() + { + $result = $this->stdOutBuffer; + $this->stdOutBuffer = ''; + return $result; + } +} \ No newline at end of file diff --git a/tests/framework/data/ActiveDataProviderTest.php b/tests/framework/data/ActiveDataProviderTest.php new file mode 100644 index 0000000..f62b012 --- /dev/null +++ b/tests/framework/data/ActiveDataProviderTest.php @@ -0,0 +1,180 @@ + + * @since 2.0 + * + * @group data + * @group db + */ +class ActiveDataProviderTest extends DatabaseTestCase +{ + protected function setUp() + { + parent::setUp(); + ActiveRecord::$db = $this->getConnection(); + } + + public function testActiveQuery() + { + $provider = new ActiveDataProvider([ + 'query' => Order::find()->orderBy('id'), + ]); + $orders = $provider->getModels(); + $this->assertEquals(3, count($orders)); + $this->assertTrue($orders[0] instanceof Order); + $this->assertTrue($orders[1] instanceof Order); + $this->assertTrue($orders[2] instanceof Order); + $this->assertEquals([1, 2, 3], $provider->getKeys()); + + $provider = new ActiveDataProvider([ + 'query' => Order::find(), + 'pagination' => [ + 'pageSize' => 2, + ] + ]); + $orders = $provider->getModels(); + $this->assertEquals(2, count($orders)); + } + + public function testActiveRelation() + { + /* @var $customer Customer */ + $customer = Customer::findOne(2); + $provider = new ActiveDataProvider([ + 'query' => $customer->getOrders(), + ]); + $orders = $provider->getModels(); + $this->assertEquals(2, count($orders)); + $this->assertTrue($orders[0] instanceof Order); + $this->assertTrue($orders[1] instanceof Order); + $this->assertEquals([2, 3], $provider->getKeys()); + + $provider = new ActiveDataProvider([ + 'query' => $customer->getOrders(), + 'pagination' => [ + 'pageSize' => 1, + ] + ]); + $orders = $provider->getModels(); + $this->assertEquals(1, count($orders)); + } + + public function testActiveRelationVia() + { + /* @var $order Order */ + $order = Order::findOne(2); + $provider = new ActiveDataProvider([ + 'query' => $order->getItems(), + ]); + $items = $provider->getModels(); + $this->assertEquals(3, count($items)); + $this->assertTrue($items[0] instanceof Item); + $this->assertTrue($items[1] instanceof Item); + $this->assertTrue($items[2] instanceof Item); + $this->assertEquals([3, 4, 5], $provider->getKeys()); + + $provider = new ActiveDataProvider([ + 'query' => $order->getItems(), + 'pagination' => [ + 'pageSize' => 2, + ] + ]); + $items = $provider->getModels(); + $this->assertEquals(2, count($items)); + } + + public function testActiveRelationViaTable() + { + /* @var $order Order */ + $order = Order::findOne(1); + $provider = new ActiveDataProvider([ + 'query' => $order->getBooks(), + ]); + $items = $provider->getModels(); + $this->assertEquals(2, count($items)); + $this->assertTrue($items[0] instanceof Item); + $this->assertTrue($items[1] instanceof Item); + + $provider = new ActiveDataProvider([ + 'query' => $order->getBooks(), + 'pagination' => [ + 'pageSize' => 1, + ] + ]); + $items = $provider->getModels(); + $this->assertEquals(1, count($items)); + } + + public function testQuery() + { + $query = new Query; + $provider = new ActiveDataProvider([ + 'db' => $this->getConnection(), + 'query' => $query->from('order')->orderBy('id'), + ]); + $orders = $provider->getModels(); + $this->assertEquals(3, count($orders)); + $this->assertTrue(is_array($orders[0])); + $this->assertEquals([0, 1, 2], $provider->getKeys()); + + $query = new Query; + $provider = new ActiveDataProvider([ + 'db' => $this->getConnection(), + 'query' => $query->from('order'), + 'pagination' => [ + 'pageSize' => 2, + ] + ]); + $orders = $provider->getModels(); + $this->assertEquals(2, count($orders)); + } + + public function testRefresh() + { + $query = new Query; + $provider = new ActiveDataProvider([ + 'db' => $this->getConnection(), + 'query' => $query->from('order')->orderBy('id'), + ]); + $this->assertEquals(3, count($provider->getModels())); + + $provider->getPagination()->pageSize = 2; + $this->assertEquals(3, count($provider->getModels())); + $provider->refresh(); + $this->assertEquals(2, count($provider->getModels())); + } + + public function testPaginationBeforeModels() + { + $query = new Query; + $provider = new ActiveDataProvider([ + 'db' => $this->getConnection(), + 'query' => $query->from('order')->orderBy('id'), + ]); + $pagination = $provider->getPagination(); + $this->assertEquals(0, $pagination->getPageCount()); + $this->assertCount(3, $provider->getModels()); + $this->assertEquals(1, $pagination->getPageCount()); + + $provider->getPagination()->pageSize = 2; + $this->assertEquals(3, count($provider->getModels())); + $provider->refresh(); + $this->assertEquals(2, count($provider->getModels())); + } +} diff --git a/tests/framework/data/ArrayDataProviderTest.php b/tests/framework/data/ArrayDataProviderTest.php new file mode 100644 index 0000000..2a6290d --- /dev/null +++ b/tests/framework/data/ArrayDataProviderTest.php @@ -0,0 +1,182 @@ +mockApplication(); + } + + public function testGetModels() + { + $simpleArray = [ + ['name' => 'zero'], + ['name' => 'one'] + ]; + $dataProvider = new ArrayDataProvider(['allModels' => $simpleArray]); + $this->assertEquals($simpleArray, $dataProvider->getModels()); + } + + public function testGetSortedData() + { + $simpleArray = [['sortField' => 1], ['sortField' => 0]]; + $dataProvider = new ArrayDataProvider( + [ + 'allModels' => $simpleArray, + 'sort' => [ + 'attributes' => [ + 'sort' => [ + 'asc' => ['sortField' => SORT_ASC], + 'desc' => ['sortField' => SORT_DESC], + 'label' => 'Sorting', + 'default' => 'asc', + ], + ], + 'defaultOrder' => [ + 'sort' => SORT_ASC, + ] + ], + ] + ); + $sortedArray = [['sortField' => 0], ['sortField' => 1]]; + $this->assertEquals($sortedArray, $dataProvider->getModels()); + } + + public function testGetSortedDataByInnerArrayField() + { + $simpleArray = [ + ['innerArray' => ['sortField' => 1]], + ['innerArray' => ['sortField' => 0]] + ]; + $dataProvider = new ArrayDataProvider( + [ + 'allModels' => $simpleArray, + 'sort' => [ + 'attributes' => [ + 'sort' => [ + 'asc' => ['innerArray.sortField' => SORT_ASC], + 'desc' => ['innerArray.sortField' => SORT_DESC], + 'label' => 'Sorting', + 'default' => 'asc', + ], + ], + 'defaultOrder' => [ + 'sort' => SORT_ASC, + ] + ], + ] + ); + $sortedArray = [ + ['innerArray' => ['sortField' => 0]], + ['innerArray' => ['sortField' => 1]] + ]; + $this->assertEquals($sortedArray, $dataProvider->getModels()); + } + + public function testCaseSensitiveSort() + { + // source data + $unsortedProjects = [ + ['title'=>'Zabbix', 'license'=>'GPL'], + ['title'=>'munin', 'license'=>'GPL'], + ['title'=>'Arch Linux', 'license'=>'GPL'], + ['title'=>'Nagios', 'license'=>'GPL'], + ['title'=>'zend framework', 'license'=>'BSD'], + ['title'=>'Zope', 'license'=>'ZPL'], + ['title'=>'active-record', 'license'=>false], + ['title'=>'ActiveState', 'license'=>false], + ['title'=>'mach', 'license'=>false], + ['title'=>'MySQL', 'license'=>'GPL'], + ['title'=>'mssql', 'license'=>'EULA'], + ['title'=>'Master-Master', 'license'=>false], + ['title'=>'Zend Engine', 'license'=>false], + ['title'=>'Mageia Linux', 'license'=>'GNU GPL'], + ['title'=>'nginx', 'license'=>'BSD'], + ['title'=>'Mozilla Firefox', 'license'=>'MPL'], + ]; + + // expected data + $sortedProjects = [ + // upper cased titles + ['title'=>'ActiveState', 'license'=>false], + ['title'=>'Arch Linux', 'license'=>'GPL'], + ['title'=>'Mageia Linux', 'license'=>'GNU GPL'], + ['title'=>'Master-Master', 'license'=>false], + ['title'=>'Mozilla Firefox', 'license'=>'MPL'], + ['title'=>'MySQL', 'license'=>'GPL'], + ['title'=>'Nagios', 'license'=>'GPL'], + ['title'=>'Zabbix', 'license'=>'GPL'], + ['title'=>'Zend Engine', 'license'=>false], + ['title'=>'Zope', 'license'=>'ZPL'], + // lower cased titles + ['title'=>'active-record', 'license'=>false], + ['title'=>'mach', 'license'=>false], + ['title'=>'mssql', 'license'=>'EULA'], + ['title'=>'munin', 'license'=>'GPL'], + ['title'=>'nginx', 'license'=>'BSD'], + ['title'=>'zend framework', 'license'=>'BSD'], + ]; + + $dataProvider = new ArrayDataProvider( + [ + 'allModels' => $unsortedProjects, + 'sort' => [ + 'attributes' => [ + 'sort' => [ + 'asc' => ['title' => SORT_ASC], + 'desc' => ['title' => SORT_DESC], + 'label' => 'Title', + 'default' => 'desc', + ], + ], + 'defaultOrder' => [ + 'sort' => SORT_ASC, + ] + ], + 'pagination' => [ + 'pageSize' => 100500, + ], + ] + ); + + $this->assertEquals($sortedProjects, $dataProvider->getModels()); + } + + public function testGetKeys() + { + $pagination = ['pageSize' => 2]; + + $simpleArray = [ + ['name' => 'zero'], + ['name' => 'one'], + ['name' => 'tow'], + ]; + $dataProvider = new ArrayDataProvider(['allModels' => $simpleArray, 'pagination' => $pagination]); + $this->assertEquals([0, 1], $dataProvider->getKeys()); + + $namedArray = [ + 'key1' => ['name' => 'zero'], + 'key2' => ['name' => 'one'], + 'key3' => ['name' => 'two'], + ]; + $dataProvider = new ArrayDataProvider(['allModels' => $namedArray, 'pagination' => $pagination]); + $this->assertEquals(['key1', 'key2'], $dataProvider->getKeys()); + + $mixedArray = [ + 'key1' => ['name' => 'zero'], + 9 => ['name' => 'one'], + 'key3' => ['name' => 'two'], + ]; + $dataProvider = new ArrayDataProvider(['allModels' => $mixedArray, 'pagination' => $pagination]); + $this->assertEquals(['key1', 9], $dataProvider->getKeys()); + } +} \ No newline at end of file diff --git a/tests/framework/data/SortTest.php b/tests/framework/data/SortTest.php new file mode 100644 index 0000000..11b18f6 --- /dev/null +++ b/tests/framework/data/SortTest.php @@ -0,0 +1,180 @@ + + * @since 2.0 + * + * @group data + */ +class SortTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + + public function testGetOrders() + { + $sort = new Sort([ + 'attributes' => [ + 'age', + 'name' => [ + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], + ], + ], + 'params' => [ + 'sort' => 'age,-name' + ], + 'enableMultiSort' => true, + ]); + + $orders = $sort->getOrders(); + $this->assertEquals(3, count($orders)); + $this->assertEquals(SORT_ASC, $orders['age']); + $this->assertEquals(SORT_DESC, $orders['first_name']); + $this->assertEquals(SORT_DESC, $orders['last_name']); + + $sort->enableMultiSort = false; + $orders = $sort->getOrders(true); + $this->assertEquals(1, count($orders)); + $this->assertEquals(SORT_ASC, $orders['age']); + } + + public function testGetAttributeOrders() + { + $sort = new Sort([ + 'attributes' => [ + 'age', + 'name' => [ + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], + ], + ], + 'params' => [ + 'sort' => 'age,-name' + ], + 'enableMultiSort' => true, + ]); + + $orders = $sort->getAttributeOrders(); + $this->assertEquals(2, count($orders)); + $this->assertEquals(SORT_ASC, $orders['age']); + $this->assertEquals(SORT_DESC, $orders['name']); + + $sort->enableMultiSort = false; + $orders = $sort->getAttributeOrders(true); + $this->assertEquals(1, count($orders)); + $this->assertEquals(SORT_ASC, $orders['age']); + } + + public function testGetAttributeOrder() + { + $sort = new Sort([ + 'attributes' => [ + 'age', + 'name' => [ + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], + ], + ], + 'params' => [ + 'sort' => 'age,-name' + ], + 'enableMultiSort' => true, + ]); + + $this->assertEquals(SORT_ASC, $sort->getAttributeOrder('age')); + $this->assertEquals(SORT_DESC, $sort->getAttributeOrder('name')); + $this->assertNull($sort->getAttributeOrder('xyz')); + } + + public function testCreateSortParam() + { + $sort = new Sort([ + 'attributes' => [ + 'age', + 'name' => [ + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], + ], + ], + 'params' => [ + 'sort' => 'age,-name' + ], + 'enableMultiSort' => true, + 'route' => 'site/index', + ]); + + $this->assertEquals('-age,-name', $sort->createSortParam('age')); + $this->assertEquals('name,age', $sort->createSortParam('name')); + } + + public function testCreateUrl() + { + $manager = new UrlManager([ + 'baseUrl' => '/', + 'ScriptUrl' => '/index.php', + 'cache' => null, + ]); + + $sort = new Sort([ + 'attributes' => [ + 'age', + 'name' => [ + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], + ], + ], + 'params' => [ + 'sort' => 'age,-name' + ], + 'enableMultiSort' => true, + 'urlManager' => $manager, + 'route' => 'site/index', + ]); + + $this->assertEquals('/index.php?r=site%2Findex&sort=-age%2C-name', $sort->createUrl('age')); + $this->assertEquals('/index.php?r=site%2Findex&sort=name%2Cage', $sort->createUrl('name')); + } + + public function testLink() + { + $this->mockApplication(); + $manager = new UrlManager([ + 'baseUrl' => '/', + 'scriptUrl' => '/index.php', + 'cache' => null, + ]); + + $sort = new Sort([ + 'attributes' => [ + 'age', + 'name' => [ + 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], + 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], + ], + ], + 'params' => [ + 'sort' => 'age,-name' + ], + 'enableMultiSort' => true, + 'urlManager' => $manager, + 'route' => 'site/index', + ]); + + $this->assertEquals('Age', $sort->link('age')); + } +} diff --git a/tests/framework/db/ActiveRecordTest.php b/tests/framework/db/ActiveRecordTest.php new file mode 100644 index 0000000..f9eef97 --- /dev/null +++ b/tests/framework/db/ActiveRecordTest.php @@ -0,0 +1,694 @@ +getConnection(); + } + + public function getCustomerClass() + { + return Customer::className(); + } + + public function getItemClass() + { + return Item::className(); + } + + public function getOrderClass() + { + return Order::className(); + } + + public function getOrderItemClass() + { + return OrderItem::className(); + } + + public function getOrderWithNullFKClass() + { + return OrderWithNullFK::className(); + } + public function getOrderItemWithNullFKmClass() + { + return OrderItemWithNullFK::className(); + } + + public function testCustomColumns() + { + // find custom column + if ($this->driverName === 'oci') { + $customer = Customer::find()->select(['{{customer}}.*', '([[status]]*2) AS [[status2]]']) + ->where(['name' => 'user3'])->one(); + } else { + $customer = Customer::find()->select(['*', '([[status]]*2) AS [[status2]]']) + ->where(['name' => 'user3'])->one(); + } + $this->assertEquals(3, $customer->id); + $this->assertEquals(4, $customer->status2); + } + + public function testStatisticalFind() + { + // find count, sum, average, min, max, scalar + $this->assertEquals(3, Customer::find()->count()); + $this->assertEquals(2, Customer::find()->where('[[id]]=1 OR [[id]]=2')->count()); + $this->assertEquals(6, Customer::find()->sum('[[id]]')); + $this->assertEquals(2, Customer::find()->average('[[id]]')); + $this->assertEquals(1, Customer::find()->min('[[id]]')); + $this->assertEquals(3, Customer::find()->max('[[id]]')); + $this->assertEquals(3, Customer::find()->select('COUNT(*)')->scalar()); + } + + public function testFindScalar() + { + // query scalar + $customerName = Customer::find()->where(['[[id]]' => 2])->select('[[name]]')->scalar(); + $this->assertEquals('user2', $customerName); + } + + public function testFindColumn() + { + /* @var $this TestCase|ActiveRecordTestTrait */ + $this->assertEquals(['user1', 'user2', 'user3'], Customer::find()->select('[[name]]')->column()); + $this->assertEquals(['user3', 'user2', 'user1'], Customer::find()->orderBy(['[[name]]' => SORT_DESC])->select('[[name]]')->column()); + } + + public function testFindBySql() + { + // find one + $customer = Customer::findBySql('SELECT * FROM {{customer}} ORDER BY [[id]] DESC')->one(); + $this->assertTrue($customer instanceof Customer); + $this->assertEquals('user3', $customer->name); + + // find all + $customers = Customer::findBySql('SELECT * FROM {{customer}}')->all(); + $this->assertEquals(3, count($customers)); + + // find with parameter binding + $customer = Customer::findBySql('SELECT * FROM {{customer}} WHERE [[id]]=:id', [':id' => 2])->one(); + $this->assertTrue($customer instanceof Customer); + $this->assertEquals('user2', $customer->name); + } + + public function testFindLazyViaTable() + { + /* @var $order Order */ + $order = Order::findOne(1); + $this->assertEquals(1, $order->id); + $this->assertEquals(2, count($order->books)); + $this->assertEquals(1, $order->items[0]->id); + $this->assertEquals(2, $order->items[1]->id); + + $order = Order::findOne(2); + $this->assertEquals(2, $order->id); + $this->assertEquals(0, count($order->books)); + + $order = Order::find()->where(['id' => 1])->asArray()->one(); + $this->assertTrue(is_array($order)); + } + + public function testFindEagerViaTable() + { + $orders = Order::find()->with('books')->orderBy('id')->all(); + $this->assertEquals(3, count($orders)); + + $order = $orders[0]; + $this->assertEquals(1, $order->id); + $this->assertEquals(2, count($order->books)); + $this->assertEquals(1, $order->books[0]->id); + $this->assertEquals(2, $order->books[1]->id); + + $order = $orders[1]; + $this->assertEquals(2, $order->id); + $this->assertEquals(0, count($order->books)); + + $order = $orders[2]; + $this->assertEquals(3, $order->id); + $this->assertEquals(1, count($order->books)); + $this->assertEquals(2, $order->books[0]->id); + + // https://github.com/yiisoft/yii2/issues/1402 + $orders = Order::find()->with('books')->orderBy('id')->asArray()->all(); + $this->assertEquals(3, count($orders)); + $this->assertTrue(is_array($orders[0]['orderItems'][0])); + + $order = $orders[0]; + $this->assertTrue(is_array($order)); + $this->assertEquals(1, $order['id']); + $this->assertEquals(2, count($order['books'])); + $this->assertEquals(1, $order['books'][0]['id']); + $this->assertEquals(2, $order['books'][1]['id']); + } + + // deeply nested table relation + public function testDeeplyNestedTableRelation() + { + /* @var $customer Customer */ + $customer = Customer::findOne(1); + $this->assertNotNull($customer); + + $items = $customer->orderItems; + + $this->assertEquals(2, count($items)); + $this->assertInstanceOf(Item::className(), $items[0]); + $this->assertInstanceOf(Item::className(), $items[1]); + $this->assertEquals(1, $items[0]->id); + $this->assertEquals(2, $items[1]->id); + } + + /** + * https://github.com/yiisoft/yii2/issues/5341 + * + * Issue: Plan 1 -- * Account * -- * User + * Our Tests: Category 1 -- * Item * -- * Order + */ + public function testDeeplyNestedTableRelation2() + { + /* @var $category Category */ + $category = Category::findOne(1); + $this->assertNotNull($category); + $orders = $category->orders; + $this->assertEquals(2, count($orders)); + $this->assertInstanceOf(Order::className(), $orders[0]); + $this->assertInstanceOf(Order::className(), $orders[1]); + $ids = [$orders[0]->id, $orders[1]->id]; + sort($ids); + $this->assertEquals([1, 3], $ids); + + $category = Category::findOne(2); + $this->assertNotNull($category); + $orders = $category->orders; + $this->assertEquals(1, count($orders)); + $this->assertInstanceOf(Order::className(), $orders[0]); + $this->assertEquals(2, $orders[0]->id); + + } + + public function testStoreNull() + { + $record = new NullValues(); + $this->assertNull($record->var1); + $this->assertNull($record->var2); + $this->assertNull($record->var3); + $this->assertNull($record->stringcol); + + $record->id = 1; + + $record->var1 = 123; + $record->var2 = 456; + $record->var3 = 789; + $record->stringcol = 'hello!'; + + $record->save(false); + $this->assertTrue($record->refresh()); + + $this->assertEquals(123, $record->var1); + $this->assertEquals(456, $record->var2); + $this->assertEquals(789, $record->var3); + $this->assertEquals('hello!', $record->stringcol); + + $record->var1 = null; + $record->var2 = null; + $record->var3 = null; + $record->stringcol = null; + + $record->save(false); + $this->assertTrue($record->refresh()); + + $this->assertNull($record->var1); + $this->assertNull($record->var2); + $this->assertNull($record->var3); + $this->assertNull($record->stringcol); + + $record->var1 = 0; + $record->var2 = 0; + $record->var3 = 0; + $record->stringcol = ''; + + $record->save(false); + $this->assertTrue($record->refresh()); + + $this->assertEquals(0, $record->var1); + $this->assertEquals(0, $record->var2); + $this->assertEquals(0, $record->var3); + $this->assertEquals('', $record->stringcol); + } + + public function testStoreEmpty() + { + $record = new NullValues(); + $record->id = 1; + + // this is to simulate empty html form submission + $record->var1 = ''; + $record->var2 = ''; + $record->var3 = ''; + $record->stringcol = ''; + + $record->save(false); + $this->assertTrue($record->refresh()); + + // https://github.com/yiisoft/yii2/commit/34945b0b69011bc7cab684c7f7095d837892a0d4#commitcomment-4458225 + $this->assertTrue($record->var1 === $record->var2); + $this->assertTrue($record->var2 === $record->var3); + } + + public function testIsPrimaryKey() + { + $this->assertFalse(Customer::isPrimaryKey([])); + $this->assertTrue(Customer::isPrimaryKey(['id'])); + $this->assertFalse(Customer::isPrimaryKey(['id', 'name'])); + $this->assertFalse(Customer::isPrimaryKey(['name'])); + $this->assertFalse(Customer::isPrimaryKey(['name', 'email'])); + + $this->assertFalse(OrderItem::isPrimaryKey([])); + $this->assertFalse(OrderItem::isPrimaryKey(['order_id'])); + $this->assertFalse(OrderItem::isPrimaryKey(['item_id'])); + $this->assertFalse(OrderItem::isPrimaryKey(['quantity'])); + $this->assertFalse(OrderItem::isPrimaryKey(['quantity', 'subtotal'])); + $this->assertTrue(OrderItem::isPrimaryKey(['order_id', 'item_id'])); + $this->assertFalse(OrderItem::isPrimaryKey(['order_id', 'item_id', 'quantity'])); + } + + public function testJoinWith() + { + // left join and eager loading + $orders = Order::find()->joinWith('customer')->orderBy('customer.id DESC, order.id')->all(); + $this->assertEquals(3, count($orders)); + $this->assertEquals(2, $orders[0]->id); + $this->assertEquals(3, $orders[1]->id); + $this->assertEquals(1, $orders[2]->id); + $this->assertTrue($orders[0]->isRelationPopulated('customer')); + $this->assertTrue($orders[1]->isRelationPopulated('customer')); + $this->assertTrue($orders[2]->isRelationPopulated('customer')); + + // inner join filtering and eager loading + $orders = Order::find()->innerJoinWith([ + 'customer' => function ($query) { + $query->where('{{customer}}.[[id]]=2'); + }, + ])->orderBy('order.id')->all(); + $this->assertEquals(2, count($orders)); + $this->assertEquals(2, $orders[0]->id); + $this->assertEquals(3, $orders[1]->id); + $this->assertTrue($orders[0]->isRelationPopulated('customer')); + $this->assertTrue($orders[1]->isRelationPopulated('customer')); + + // inner join filtering, eager loading, conditions on both primary and relation + $orders = Order::find()->innerJoinWith([ + 'customer' => function ($query) { + $query->where(['customer.id' => 2]); + }, + ])->where(['order.id' => [1, 2]])->orderBy('order.id')->all(); + $this->assertEquals(1, count($orders)); + $this->assertEquals(2, $orders[0]->id); + $this->assertTrue($orders[0]->isRelationPopulated('customer')); + + // inner join filtering without eager loading + $orders = Order::find()->innerJoinWith([ + 'customer' => function ($query) { + $query->where('{{customer}}.[[id]]=2'); + }, + ], false)->orderBy('order.id')->all(); + $this->assertEquals(2, count($orders)); + $this->assertEquals(2, $orders[0]->id); + $this->assertEquals(3, $orders[1]->id); + $this->assertFalse($orders[0]->isRelationPopulated('customer')); + $this->assertFalse($orders[1]->isRelationPopulated('customer')); + + // inner join filtering without eager loading, conditions on both primary and relation + $orders = Order::find()->innerJoinWith([ + 'customer' => function ($query) { + $query->where(['customer.id' => 2]); + }, + ], false)->where(['order.id' => [1, 2]])->orderBy('order.id')->all(); + $this->assertEquals(1, count($orders)); + $this->assertEquals(2, $orders[0]->id); + $this->assertFalse($orders[0]->isRelationPopulated('customer')); + + // join with via-relation + $orders = Order::find()->innerJoinWith('books')->orderBy('order.id')->all(); + $this->assertEquals(2, count($orders)); + $this->assertEquals(1, $orders[0]->id); + $this->assertEquals(3, $orders[1]->id); + $this->assertTrue($orders[0]->isRelationPopulated('books')); + $this->assertTrue($orders[1]->isRelationPopulated('books')); + $this->assertEquals(2, count($orders[0]->books)); + $this->assertEquals(1, count($orders[1]->books)); + + // join with sub-relation + $orders = Order::find()->innerJoinWith([ + 'items' => function ($q) { + $q->orderBy('item.id'); + }, + 'items.category' => function ($q) { + $q->where('{{category}}.[[id]] = 2'); + }, + ])->orderBy('order.id')->all(); + $this->assertEquals(1, count($orders)); + $this->assertTrue($orders[0]->isRelationPopulated('items')); + $this->assertEquals(2, $orders[0]->id); + $this->assertEquals(3, count($orders[0]->items)); + $this->assertTrue($orders[0]->items[0]->isRelationPopulated('category')); + $this->assertEquals(2, $orders[0]->items[0]->category->id); + + // join with table alias + $orders = Order::find()->joinWith([ + 'customer' => function ($q) { + $q->from('customer c'); + } + ])->orderBy('c.id DESC, order.id')->all(); + $this->assertEquals(3, count($orders)); + $this->assertEquals(2, $orders[0]->id); + $this->assertEquals(3, $orders[1]->id); + $this->assertEquals(1, $orders[2]->id); + $this->assertTrue($orders[0]->isRelationPopulated('customer')); + $this->assertTrue($orders[1]->isRelationPopulated('customer')); + $this->assertTrue($orders[2]->isRelationPopulated('customer')); + + // join with ON condition + $orders = Order::find()->joinWith('books2')->orderBy('order.id')->all(); + $this->assertEquals(3, count($orders)); + $this->assertEquals(1, $orders[0]->id); + $this->assertEquals(2, $orders[1]->id); + $this->assertEquals(3, $orders[2]->id); + $this->assertTrue($orders[0]->isRelationPopulated('books2')); + $this->assertTrue($orders[1]->isRelationPopulated('books2')); + $this->assertTrue($orders[2]->isRelationPopulated('books2')); + $this->assertEquals(2, count($orders[0]->books2)); + $this->assertEquals(0, count($orders[1]->books2)); + $this->assertEquals(1, count($orders[2]->books2)); + + // lazy loading with ON condition + $order = Order::findOne(1); + $this->assertEquals(2, count($order->books2)); + $order = Order::findOne(2); + $this->assertEquals(0, count($order->books2)); + $order = Order::findOne(3); + $this->assertEquals(1, count($order->books2)); + + // eager loading with ON condition + $orders = Order::find()->with('books2')->all(); + $this->assertEquals(3, count($orders)); + $this->assertEquals(1, $orders[0]->id); + $this->assertEquals(2, $orders[1]->id); + $this->assertEquals(3, $orders[2]->id); + $this->assertTrue($orders[0]->isRelationPopulated('books2')); + $this->assertTrue($orders[1]->isRelationPopulated('books2')); + $this->assertTrue($orders[2]->isRelationPopulated('books2')); + $this->assertEquals(2, count($orders[0]->books2)); + $this->assertEquals(0, count($orders[1]->books2)); + $this->assertEquals(1, count($orders[2]->books2)); + + // join with count and query + $query = Order::find()->joinWith('customer'); + $count = $query->count(); + $this->assertEquals(3, $count); + $orders = $query->all(); + $this->assertEquals(3, count($orders)); + + // https://github.com/yiisoft/yii2/issues/2880 + $query = Order::findOne(1); + $customer = $query->getCustomer()->joinWith([ + 'orders' => function ($q) { $q->orderBy([]); } + ])->one(); + $this->assertEquals(1, $customer->id); + $order = Order::find()->joinWith([ + 'items' => function ($q) { + $q->from(['items' => 'item']) + ->orderBy('items.id'); + }, + ])->orderBy('order.id')->one(); + + // join with sub-relation called inside Closure + $orders = Order::find()->joinWith([ + 'items' => function ($q) { + $q->orderBy('item.id'); + $q->joinWith([ + 'category'=> function ($q) { + $q->where('{{category}}.[[id]] = 2'); + } + ]); + }, + ])->orderBy('order.id')->all(); + $this->assertEquals(1, count($orders)); + $this->assertTrue($orders[0]->isRelationPopulated('items')); + $this->assertEquals(2, $orders[0]->id); + $this->assertEquals(3, count($orders[0]->items)); + $this->assertTrue($orders[0]->items[0]->isRelationPopulated('category')); + $this->assertEquals(2, $orders[0]->items[0]->category->id); + } + + public function testJoinWithAndScope() + { + // hasOne inner join + $customers = Customer::find()->active()->innerJoinWith('profile')->orderBy('customer.id')->all(); + $this->assertEquals(1, count($customers)); + $this->assertEquals(1, $customers[0]->id); + $this->assertTrue($customers[0]->isRelationPopulated('profile')); + + // hasOne outer join + $customers = Customer::find()->active()->joinWith('profile')->orderBy('customer.id')->all(); + $this->assertEquals(2, count($customers)); + $this->assertEquals(1, $customers[0]->id); + $this->assertEquals(2, $customers[1]->id); + $this->assertTrue($customers[0]->isRelationPopulated('profile')); + $this->assertTrue($customers[1]->isRelationPopulated('profile')); + $this->assertInstanceOf(Profile::className(), $customers[0]->profile); + $this->assertNull($customers[1]->profile); + + // hasMany + $customers = Customer::find()->active()->joinWith([ + 'orders' => function ($q) { + $q->orderBy('order.id'); + } + ])->orderBy('customer.id DESC, order.id')->all(); + $this->assertEquals(2, count($customers)); + $this->assertEquals(2, $customers[0]->id); + $this->assertEquals(1, $customers[1]->id); + $this->assertTrue($customers[0]->isRelationPopulated('orders')); + $this->assertTrue($customers[1]->isRelationPopulated('orders')); + } + + /** + * This query will do the same join twice, ensure duplicated JOIN gets removed + * https://github.com/yiisoft/yii2/pull/2650 + */ + public function testJoinWithVia() + { + Order::getDb()->getQueryBuilder()->separator = "\n"; + Order::find()->joinWith('itemsInOrder1')->joinWith([ + 'items' => function ($q) { + $q->orderBy('item.id'); + }, + ])->all(); + } + + public function testInverseOf() + { + // eager loading: find one and all + $customer = Customer::find()->with('orders2')->where(['id' => 1])->one(); + $this->assertTrue($customer->orders2[0]->customer2 === $customer); + $customers = Customer::find()->with('orders2')->where(['id' => [1, 3]])->all(); + $this->assertTrue($customers[0]->orders2[0]->customer2 === $customers[0]); + $this->assertTrue(empty($customers[1]->orders2)); + // lazy loading + $customer = Customer::findOne(2); + $orders = $customer->orders2; + $this->assertTrue(count($orders) === 2); + $this->assertTrue($customer->orders2[0]->customer2 === $customer); + $this->assertTrue($customer->orders2[1]->customer2 === $customer); + // ad-hoc lazy loading + $customer = Customer::findOne(2); + $orders = $customer->getOrders2()->all(); + $this->assertTrue(count($orders) === 2); + $this->assertTrue($customer->orders2[0]->customer2 === $customer); + $this->assertTrue($customer->orders2[1]->customer2 === $customer); + + // the other way around + $customer = Customer::find()->with('orders2')->where(['id' => 1])->asArray()->one(); + $this->assertTrue($customer['orders2'][0]['customer2']['id'] === $customer['id']); + $customers = Customer::find()->with('orders2')->where(['id' => [1, 3]])->asArray()->all(); + $this->assertTrue($customer['orders2'][0]['customer2']['id'] === $customers[0]['id']); + $this->assertTrue(empty($customers[1]['orders2'])); + + $orders = Order::find()->with('customer2')->where(['id' => 1])->all(); + $this->assertTrue($orders[0]->customer2->orders2 === [$orders[0]]); + $order = Order::find()->with('customer2')->where(['id' => 1])->one(); + $this->assertTrue($order->customer2->orders2 === [$order]); + + $orders = Order::find()->with('customer2')->where(['id' => 1])->asArray()->all(); + $this->assertTrue($orders[0]['customer2']['orders2'][0]['id'] === $orders[0]['id']); + $order = Order::find()->with('customer2')->where(['id' => 1])->asArray()->one(); + $this->assertTrue($order['customer2']['orders2'][0]['id'] === $orders[0]['id']); + + $orders = Order::find()->with('customer2')->where(['id' => [1, 3]])->all(); + $this->assertTrue($orders[0]->customer2->orders2 === [$orders[0]]); + $this->assertTrue($orders[1]->customer2->orders2 === [$orders[1]]); + + $orders = Order::find()->with('customer2')->where(['id' => [2, 3]])->orderBy('id')->all(); + $this->assertTrue($orders[0]->customer2->orders2 === $orders); + $this->assertTrue($orders[1]->customer2->orders2 === $orders); + + $orders = Order::find()->with('customer2')->where(['id' => [2, 3]])->orderBy('id')->asArray()->all(); + $this->assertTrue($orders[0]['customer2']['orders2'][0]['id'] === $orders[0]['id']); + $this->assertTrue($orders[0]['customer2']['orders2'][1]['id'] === $orders[1]['id']); + $this->assertTrue($orders[1]['customer2']['orders2'][0]['id'] === $orders[0]['id']); + $this->assertTrue($orders[1]['customer2']['orders2'][1]['id'] === $orders[1]['id']); + } + + public function testDefaultValues() + { + $model = new Type(); + $model->loadDefaultValues(); + $this->assertEquals(1, $model->int_col2); + $this->assertEquals('something', $model->char_col2); + $this->assertEquals(1.23, $model->float_col2); + $this->assertEquals(33.22, $model->numeric_col); + $this->assertEquals(true, $model->bool_col2); + + if ($this instanceof CubridActiveRecordTest) { + // cubrid has non-standard timestamp representation + $this->assertEquals('12:00:00 AM 01/01/2002', $model->time); + } else { + $this->assertEquals('2002-01-01 00:00:00', $model->time); + } + + $model = new Type(); + $model->char_col2 = 'not something'; + + $model->loadDefaultValues(); + $this->assertEquals('not something', $model->char_col2); + + $model = new Type(); + $model->char_col2 = 'not something'; + + $model->loadDefaultValues(false); + $this->assertEquals('something', $model->char_col2); + } + + public function testUnlinkAllViaTable() + { + /* @var $orderClass \yii\db\ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + /* @var $orderItemClass \yii\db\ActiveRecordInterface */ + $orderItemClass = $this->getOrderItemClass(); + /* @var $itemClass \yii\db\ActiveRecordInterface */ + $itemClass = $this->getItemClass(); + /* @var $orderItemsWithNullFKClass \yii\db\ActiveRecordInterface */ + $orderItemsWithNullFKClass = $this->getOrderItemWithNullFKmClass(); + + // via table with delete + /* @var $order Order */ + $order = $orderClass::findOne(1); + $this->assertEquals(2, count($order->booksViaTable)); + $orderItemCount = $orderItemClass::find()->count(); + $this->assertEquals(5, $itemClass::find()->count()); + $order->unlinkAll('booksViaTable', true); + $this->afterSave(); + $this->assertEquals(5, $itemClass::find()->count()); + $this->assertEquals($orderItemCount - 2, $orderItemClass::find()->count()); + $this->assertEquals(0, count($order->booksViaTable)); + + // via table without delete + $this->assertEquals(2, count($order->booksWithNullFKViaTable)); + $orderItemCount = $orderItemsWithNullFKClass::find()->count(); + $this->assertEquals(5, $itemClass::find()->count()); + $order->unlinkAll('booksWithNullFKViaTable',false); + $this->assertEquals(0, count($order->booksWithNullFKViaTable)); + $this->assertEquals(2,$orderItemsWithNullFKClass::find()->where(['AND', ['item_id' => [1, 2]], ['order_id' => null]])->count()); + $this->assertEquals($orderItemCount, $orderItemsWithNullFKClass::find()->count()); + $this->assertEquals(5, $itemClass::find()->count()); + } + + public function testCastValues() + { + $model = new Type(); + $model->int_col = 123; + $model->int_col2 = 456; + $model->smallint_col = 42; + $model->char_col = '1337'; + $model->char_col2 = 'test'; + $model->char_col3 = 'test123'; + $model->float_col = 3.742; + $model->float_col2 = 42.1337; + $model->bool_col = true; + $model->bool_col2 = false; + $model->save(false); + + /* @var $model Type */ + $model = Type::find()->one(); + $this->assertSame(123, $model->int_col); + $this->assertSame(456, $model->int_col2); + $this->assertSame(42, $model->smallint_col); + $this->assertSame('1337', trim($model->char_col)); + $this->assertSame('test', $model->char_col2); + $this->assertSame('test123', $model->char_col3); +// $this->assertSame(1337.42, $model->float_col); +// $this->assertSame(42.1337, $model->float_col2); +// $this->assertSame(true, $model->bool_col); +// $this->assertSame(false, $model->bool_col2); + } + + public function testIssues() + { + // https://github.com/yiisoft/yii2/issues/4938 + $category = Category::findOne(2); + $this->assertTrue($category instanceof Category); + $this->assertEquals(3, $category->getItems()->count()); + $this->assertEquals(1, $category->getLimitedItems()->count()); + $this->assertEquals(1, $category->getLimitedItems()->distinct(true)->count()); + + // https://github.com/yiisoft/yii2/issues/3197 + $orders = Order::find()->with('orderItems')->orderBy('id')->all(); + $this->assertEquals(3, count($orders)); + $this->assertEquals(2, count($orders[0]->orderItems)); + $this->assertEquals(3, count($orders[1]->orderItems)); + $this->assertEquals(1, count($orders[2]->orderItems)); + $orders = Order::find()->with(['orderItems' => function ($q) { $q->indexBy('item_id'); }])->orderBy('id')->all(); + $this->assertEquals(3, count($orders)); + $this->assertEquals(2, count($orders[0]->orderItems)); + $this->assertEquals(3, count($orders[1]->orderItems)); + $this->assertEquals(1, count($orders[2]->orderItems)); + } + + public function testPopulateRecordCallWhenQueryingOnParentClass() + { + (new Cat())->save(false); + (new Dog())->save(false); + + $animal = Animal::find()->where(['type' => Dog::className()])->one(); + $this->assertEquals('bark', $animal->getDoes()); + + $animal = Animal::find()->where(['type' => Cat::className()])->one(); + $this->assertEquals('meow', $animal->getDoes()); + } +} diff --git a/tests/framework/db/BatchQueryResultTest.php b/tests/framework/db/BatchQueryResultTest.php new file mode 100644 index 0000000..b5b10b3 --- /dev/null +++ b/tests/framework/db/BatchQueryResultTest.php @@ -0,0 +1,136 @@ +getConnection(); + } + + public function testQuery() + { + $db = $this->getConnection(); + + // initialize property test + $query = new Query(); + $query->from('customer')->orderBy('id'); + $result = $query->batch(2, $db); + $this->assertTrue($result instanceof BatchQueryResult); + $this->assertEquals(2, $result->batchSize); + $this->assertTrue($result->query === $query); + + // normal query + $query = new Query(); + $query->from('customer')->orderBy('id'); + $allRows = []; + $batch = $query->batch(2, $db); + foreach ($batch as $rows) { + $allRows = array_merge($allRows, $rows); + } + $this->assertEquals(3, count($allRows)); + $this->assertEquals('user1', $allRows[0]['name']); + $this->assertEquals('user2', $allRows[1]['name']); + $this->assertEquals('user3', $allRows[2]['name']); + // rewind + $allRows = []; + foreach ($batch as $rows) { + $allRows = array_merge($allRows, $rows); + } + $this->assertEquals(3, count($allRows)); + // reset + $batch->reset(); + + // empty query + $query = new Query(); + $query->from('customer')->where(['id' => 100]); + $allRows = []; + $batch = $query->batch(2, $db); + foreach ($batch as $rows) { + $allRows = array_merge($allRows, $rows); + } + $this->assertEquals(0, count($allRows)); + + // query with index + $query = new Query(); + $query->from('customer')->indexBy('name'); + $allRows = []; + foreach ($query->batch(2, $db) as $rows) { + $allRows = array_merge($allRows, $rows); + } + $this->assertEquals(3, count($allRows)); + $this->assertEquals('address1', $allRows['user1']['address']); + $this->assertEquals('address2', $allRows['user2']['address']); + $this->assertEquals('address3', $allRows['user3']['address']); + + // each + $query = new Query(); + $query->from('customer')->orderBy('id'); + $allRows = []; + foreach ($query->each(100, $db) as $rows) { + $allRows[] = $rows; + } + $this->assertEquals(3, count($allRows)); + $this->assertEquals('user1', $allRows[0]['name']); + $this->assertEquals('user2', $allRows[1]['name']); + $this->assertEquals('user3', $allRows[2]['name']); + + // each with key + $query = new Query(); + $query->from('customer')->orderBy('id')->indexBy('name'); + $allRows = []; + foreach ($query->each(100, $db) as $key => $row) { + $allRows[$key] = $row; + } + $this->assertEquals(3, count($allRows)); + $this->assertEquals('address1', $allRows['user1']['address']); + $this->assertEquals('address2', $allRows['user2']['address']); + $this->assertEquals('address3', $allRows['user3']['address']); + } + + public function testActiveQuery() + { + $db = $this->getConnection(); + + $query = Customer::find()->orderBy('id'); + $customers = []; + foreach ($query->batch(2, $db) as $models) { + $customers = array_merge($customers, $models); + } + $this->assertEquals(3, count($customers)); + $this->assertEquals('user1', $customers[0]->name); + $this->assertEquals('user2', $customers[1]->name); + $this->assertEquals('user3', $customers[2]->name); + + // batch with eager loading + $query = Customer::find()->with('orders')->orderBy('id'); + $customers = []; + foreach ($query->batch(2, $db) as $models) { + $customers = array_merge($customers, $models); + foreach ($models as $model) { + $this->assertTrue($model->isRelationPopulated('orders')); + } + } + $this->assertEquals(3, count($customers)); + $this->assertEquals(1, count($customers[0]->orders)); + $this->assertEquals(2, count($customers[1]->orders)); + $this->assertEquals(0, count($customers[2]->orders)); + } +} diff --git a/tests/framework/db/CommandTest.php b/tests/framework/db/CommandTest.php new file mode 100644 index 0000000..21dd6f1 --- /dev/null +++ b/tests/framework/db/CommandTest.php @@ -0,0 +1,403 @@ +getConnection(false); + + // null + $command = $db->createCommand(); + $this->assertEquals(null, $command->sql); + + // string + $sql = 'SELECT * FROM customer'; + $command = $db->createCommand($sql); + $this->assertEquals($sql, $command->sql); + } + + public function testGetSetSql() + { + $db = $this->getConnection(false); + + $sql = 'SELECT * FROM customer'; + $command = $db->createCommand($sql); + $this->assertEquals($sql, $command->sql); + + $sql2 = 'SELECT * FROM order'; + $command->sql = $sql2; + $this->assertEquals($sql2, $command->sql); + } + + public function testAutoQuoting() + { + $db = $this->getConnection(false); + + $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; + $command = $db->createCommand($sql); + $this->assertEquals("SELECT `id`, `t`.`name` FROM `customer` t", $command->sql); + } + + public function testPrepareCancel() + { + $db = $this->getConnection(false); + + $command = $db->createCommand('SELECT * FROM {{customer}}'); + $this->assertEquals(null, $command->pdoStatement); + $command->prepare(); + $this->assertNotEquals(null, $command->pdoStatement); + $command->cancel(); + $this->assertEquals(null, $command->pdoStatement); + } + + public function testExecute() + { + $db = $this->getConnection(); + + $sql = 'INSERT INTO {{customer}}([[email]], [[name]], [[address]]) VALUES (\'user4@example.com\', \'user4\', \'address4\')'; + $command = $db->createCommand($sql); + $this->assertEquals(1, $command->execute()); + + $sql = 'SELECT COUNT(*) FROM {{customer}} WHERE [[name]] = \'user4\''; + $command = $db->createCommand($sql); + $this->assertEquals(1, $command->queryScalar()); + + $command = $db->createCommand('bad SQL'); + $this->setExpectedException('\yii\db\Exception'); + $command->execute(); + } + + public function testQuery() + { + $db = $this->getConnection(); + + // query + $sql = 'SELECT * FROM {{customer}}'; + $reader = $db->createCommand($sql)->query(); + $this->assertTrue($reader instanceof DataReader); + + // queryAll + $rows = $db->createCommand('SELECT * FROM {{customer}}')->queryAll(); + $this->assertEquals(3, count($rows)); + $row = $rows[2]; + $this->assertEquals(3, $row['id']); + $this->assertEquals('user3', $row['name']); + + $rows = $db->createCommand('SELECT * FROM {{customer}} WHERE [[id]] = 10')->queryAll(); + $this->assertEquals([], $rows); + + // queryOne + $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]'; + $row = $db->createCommand($sql)->queryOne(); + $this->assertEquals(1, $row['id']); + $this->assertEquals('user1', $row['name']); + + $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]'; + $command = $db->createCommand($sql); + $command->prepare(); + $row = $command->queryOne(); + $this->assertEquals(1, $row['id']); + $this->assertEquals('user1', $row['name']); + + $sql = 'SELECT * FROM {{customer}} WHERE [[id]] = 10'; + $command = $db->createCommand($sql); + $this->assertFalse($command->queryOne()); + + // queryColumn + $sql = 'SELECT * FROM {{customer}}'; + $column = $db->createCommand($sql)->queryColumn(); + $this->assertEquals(range(1, 3), $column); + + $command = $db->createCommand('SELECT [[id]] FROM {{customer}} WHERE [[id]] = 10'); + $this->assertEquals([], $command->queryColumn()); + + // queryScalar + $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]'; + $this->assertEquals($db->createCommand($sql)->queryScalar(), 1); + + $sql = 'SELECT [[id]] FROM {{customer}} ORDER BY [[id]]'; + $command = $db->createCommand($sql); + $command->prepare(); + $this->assertEquals(1, $command->queryScalar()); + + $command = $db->createCommand('SELECT [[id]] FROM {{customer}} WHERE [[id]] = 10'); + $this->assertFalse($command->queryScalar()); + + $command = $db->createCommand('bad SQL'); + $this->setExpectedException('\yii\db\Exception'); + $command->query(); + } + + public function testBindParamValue() + { + $db = $this->getConnection(); + + // bindParam + $sql = 'INSERT INTO {{customer}}([[email]], [[name]], [[address]]) VALUES (:email, :name, :address)'; + $command = $db->createCommand($sql); + $email = 'user4@example.com'; + $name = 'user4'; + $address = 'address4'; + $command->bindParam(':email', $email); + $command->bindParam(':name', $name); + $command->bindParam(':address', $address); + $command->execute(); + + $sql = 'SELECT [[name]] FROM {{customer}} WHERE [[email]] = :email'; + $command = $db->createCommand($sql); + $command->bindParam(':email', $email); + $this->assertEquals($name, $command->queryScalar()); + + $sql = <<createCommand($sql); + $intCol = 123; + $charCol = str_repeat('abc', 33) . 'x'; // a 100 char string + $boolCol = false; + $command->bindParam(':int_col', $intCol, \PDO::PARAM_INT); + $command->bindParam(':char_col', $charCol); + $command->bindParam(':bool_col', $boolCol, \PDO::PARAM_BOOL); + if ($this->driverName === 'oci') { + // can't bind floats without support from a custom PDO driver + $floatCol = 2; + $numericCol = 3; + // can't use blobs without support from a custom PDO driver + $blobCol = null; + $command->bindParam(':float_col', $floatCol, \PDO::PARAM_INT); + $command->bindParam(':numeric_col', $numericCol, \PDO::PARAM_INT); + $command->bindParam(':blob_col', $blobCol); + } else { + $floatCol = 1.23; + $numericCol = '1.23'; + $blobCol = "\x10\x11\x12"; + $command->bindParam(':float_col', $floatCol); + $command->bindParam(':numeric_col', $numericCol); + $command->bindParam(':blob_col', $blobCol); + } + $this->assertEquals(1, $command->execute()); + + $command = $db->createCommand('SELECT [[int_col]], [[char_col]], [[float_col]], [[blob_col]], [[numeric_col]], [[bool_col]] FROM {{type}}'); +// $command->prepare(); +// $command->pdoStatement->bindColumn('blob_col', $bc, \PDO::PARAM_LOB); + $row = $command->queryOne(); + $this->assertEquals($intCol, $row['int_col']); + $this->assertEquals($charCol, $row['char_col']); + $this->assertEquals($floatCol, $row['float_col']); + if ($this->driverName === 'mysql' || $this->driverName === 'sqlite' || $this->driverName === 'oci') { + $this->assertEquals($blobCol, $row['blob_col']); + } else { + $this->assertTrue(is_resource($row['blob_col'])); + $this->assertEquals($blobCol, stream_get_contents($row['blob_col'])); + } + $this->assertEquals($numericCol, $row['numeric_col']); + if ($this->driverName === 'mysql' || (defined('HHVM_VERSION') && $this->driverName === 'sqlite') || $this->driverName === 'oci') { + $this->assertEquals($boolCol, (int) $row['bool_col']); + } else { + $this->assertEquals($boolCol, $row['bool_col']); + } + + // bindValue + $sql = 'INSERT INTO {{customer}}([[email]], [[name]], [[address]]) VALUES (:email, \'user5\', \'address5\')'; + $command = $db->createCommand($sql); + $command->bindValue(':email', 'user5@example.com'); + $command->execute(); + + $sql = 'SELECT [[email]] FROM {{customer}} WHERE [[name]] = :name'; + $command = $db->createCommand($sql); + $command->bindValue(':name', 'user5'); + $this->assertEquals('user5@example.com', $command->queryScalar()); + } + + public function testFetchMode() + { + $db = $this->getConnection(); + + // default: FETCH_ASSOC + $sql = 'SELECT * FROM {{customer}}'; + $command = $db->createCommand($sql); + $result = $command->queryOne(); + $this->assertTrue(is_array($result) && isset($result['id'])); + + // FETCH_OBJ, customized via fetchMode property + $sql = 'SELECT * FROM {{customer}}'; + $command = $db->createCommand($sql); + $command->fetchMode = \PDO::FETCH_OBJ; + $result = $command->queryOne(); + $this->assertTrue(is_object($result)); + + // FETCH_NUM, customized in query method + $sql = 'SELECT * FROM {{customer}}'; + $command = $db->createCommand($sql); + $result = $command->queryOne([], \PDO::FETCH_NUM); + $this->assertTrue(is_array($result) && isset($result[0])); + } + + public function testBatchInsert() + { + $command = $this->getConnection()->createCommand(); + $command->batchInsert( + '{{customer}}', + ['email', 'name', 'address'], + [ + ['t1@example.com', 't1', 't1 address'], + ['t2@example.com', null, false], + ] + ); + $this->assertEquals(2, $command->execute()); + } + + /* + public function testInsert() + { + } + + public function testUpdate() + { + } + + public function testDelete() + { + } + + public function testCreateTable() + { + } + + public function testRenameTable() + { + } + + public function testDropTable() + { + } + + public function testTruncateTable() + { + } + + public function testAddColumn() + { + } + + public function testDropColumn() + { + } + + public function testRenameColumn() + { + } + + public function testAlterColumn() + { + } + + public function testAddForeignKey() + { + } + + public function testDropForeignKey() + { + } + + public function testCreateIndex() + { + } + + public function testDropIndex() + { + } + */ + + public function testIntegrityViolation() + { + $this->setExpectedException('\yii\db\IntegrityException'); + + $db = $this->getConnection(); + + $sql = 'INSERT INTO {{profile}}([[id]], [[description]]) VALUES (123, \'duplicate\')'; + $command = $db->createCommand($sql); + $command->execute(); + $command->execute(); + } + + public function testQueryCache() + { + $db = $this->getConnection(); + $db->enableQueryCache = true; + $db->queryCache = new FileCache(['cachePath' => '@yiiunit/runtime/cache']); + $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id'); + + $this->assertEquals('user1', $command->bindValue(':id', 1)->queryScalar()); + $update = $db->createCommand('UPDATE {{customer}} SET [[name]] = :name WHERE [[id]] = :id'); + $update->bindValues([':id' => 1, ':name' => 'user11'])->execute(); + $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar()); + + $db->cache(function (Connection $db) use ($command, $update) { + $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar()); + $update->bindValues([':id' => 2, ':name' => 'user22'])->execute(); + $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar()); + + $db->noCache(function () use ($command) { + $this->assertEquals('user22', $command->bindValue(':id', 2)->queryScalar()); + }); + + $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar()); + }, 10); + + $db->enableQueryCache = false; + $db->cache(function ($db) use ($command, $update) { + $this->assertEquals('user22', $command->bindValue(':id', 2)->queryScalar()); + $update->bindValues([':id' => 2, ':name' => 'user2'])->execute(); + $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar()); + }, 10); + + $db->enableQueryCache = true; + $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id')->cache(); + $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar()); + $update->bindValues([':id' => 1, ':name' => 'user1'])->execute(); + $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar()); + $this->assertEquals('user1', $command->noCache()->bindValue(':id', 1)->queryScalar()); + + $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id'); + $db->cache(function (Connection $db) use ($command, $update) { + $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar()); + $this->assertEquals('user1', $command->noCache()->bindValue(':id', 1)->queryScalar()); + }, 10); + } + + public function testColumnCase() + { + $db = $this->getConnection(false); + $this->assertEquals(\PDO::CASE_NATURAL, $db->slavePdo->getAttribute(\PDO::ATTR_CASE)); + + $sql = 'SELECT [[customer_id]], [[total]] FROM {{order}}'; + $rows = $db->createCommand($sql)->queryAll(); + $this->assertTrue(isset($rows[0])); + $this->assertTrue(isset($rows[0]['customer_id'])); + $this->assertTrue(isset($rows[0]['total'])); + + $db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER); + $rows = $db->createCommand($sql)->queryAll(); + $this->assertTrue(isset($rows[0])); + $this->assertTrue(isset($rows[0]['customer_id'])); + $this->assertTrue(isset($rows[0]['total'])); + + $db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_UPPER); + $rows = $db->createCommand($sql)->queryAll(); + $this->assertTrue(isset($rows[0])); + $this->assertTrue(isset($rows[0]['CUSTOMER_ID'])); + $this->assertTrue(isset($rows[0]['TOTAL'])); + } +} diff --git a/tests/framework/db/ConnectionTest.php b/tests/framework/db/ConnectionTest.php new file mode 100644 index 0000000..d9084a3 --- /dev/null +++ b/tests/framework/db/ConnectionTest.php @@ -0,0 +1,169 @@ +getConnection(false); + $params = $this->database; + + $this->assertEquals($params['dsn'], $connection->dsn); + $this->assertEquals($params['username'], $connection->username); + $this->assertEquals($params['password'], $connection->password); + } + + public function testOpenClose() + { + $connection = $this->getConnection(false, false); + + $this->assertFalse($connection->isActive); + $this->assertEquals(null, $connection->pdo); + + $connection->open(); + $this->assertTrue($connection->isActive); + $this->assertTrue($connection->pdo instanceof \PDO); + + $connection->close(); + $this->assertFalse($connection->isActive); + $this->assertEquals(null, $connection->pdo); + + $connection = new Connection; + $connection->dsn = 'unknown::memory:'; + $this->setExpectedException('yii\db\Exception'); + $connection->open(); + } + + public function testGetDriverName() + { + $connection = $this->getConnection(false, false); + $this->assertEquals($this->driverName, $connection->driverName); + } + + public function testQuoteValue() + { + $connection = $this->getConnection(false); + $this->assertEquals(123, $connection->quoteValue(123)); + $this->assertEquals("'string'", $connection->quoteValue('string')); + $this->assertEquals("'It\\'s interesting'", $connection->quoteValue("It's interesting")); + } + + public function testQuoteTableName() + { + $connection = $this->getConnection(false); + $this->assertEquals('`table`', $connection->quoteTableName('table')); + $this->assertEquals('`table`', $connection->quoteTableName('`table`')); + $this->assertEquals('`schema`.`table`', $connection->quoteTableName('schema.table')); + $this->assertEquals('`schema`.`table`', $connection->quoteTableName('schema.`table`')); + $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); + $this->assertEquals('(table)', $connection->quoteTableName('(table)')); + } + + public function testQuoteColumnName() + { + $connection = $this->getConnection(false); + $this->assertEquals('`column`', $connection->quoteColumnName('column')); + $this->assertEquals('`column`', $connection->quoteColumnName('`column`')); + $this->assertEquals('`table`.`column`', $connection->quoteColumnName('table.column')); + $this->assertEquals('`table`.`column`', $connection->quoteColumnName('table.`column`')); + $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); + $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); + $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); + } + + public function testTransaction() + { + $connection = $this->getConnection(false); + $this->assertNull($connection->transaction); + $transaction = $connection->beginTransaction(); + $this->assertNotNull($connection->transaction); + $this->assertTrue($transaction->isActive); + + $connection->createCommand()->insert('profile', ['description' => 'test transaction'])->execute(); + + $transaction->rollBack(); + $this->assertFalse($transaction->isActive); + $this->assertNull($connection->transaction); + + $this->assertEquals(0, $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction';")->queryScalar()); + + $transaction = $connection->beginTransaction(); + $connection->createCommand()->insert('profile', ['description' => 'test transaction'])->execute(); + $transaction->commit(); + $this->assertFalse($transaction->isActive); + $this->assertNull($connection->transaction); + + $this->assertEquals(1, $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction';")->queryScalar()); + } + + public function testTransactionIsolation() + { + $connection = $this->getConnection(true); + + $transaction = $connection->beginTransaction(Transaction::READ_UNCOMMITTED); + $transaction->commit(); + + $transaction = $connection->beginTransaction(Transaction::READ_COMMITTED); + $transaction->commit(); + + $transaction = $connection->beginTransaction(Transaction::REPEATABLE_READ); + $transaction->commit(); + + $transaction = $connection->beginTransaction(Transaction::SERIALIZABLE); + $transaction->commit(); + } + + /** + * @expectedException \Exception + */ + public function testTransactionShortcutException() + { + $connection = $this->getConnection(true); + $connection->transaction(function () use ($connection) { + $connection->createCommand()->insert('profile', ['description' => 'test transaction shortcut'])->execute(); + throw new \Exception('Exception in transaction shortcut'); + }); + + $profilesCount = $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction shortcut';")->queryScalar(); + $this->assertEquals(0, $profilesCount, 'profile should not be inserted in transaction shortcut'); + } + + public function testTransactionShortcutCorrect() + { + $connection = $this->getConnection(true); + + $result = $connection->transaction(function () use ($connection) { + $connection->createCommand()->insert('profile', ['description' => 'test transaction shortcut'])->execute(); + return true; + }); + + $this->assertTrue($result, 'transaction shortcut valid value should be returned from callback'); + + $profilesCount = $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction shortcut';")->queryScalar(); + $this->assertEquals(1, $profilesCount, 'profile should be inserted in transaction shortcut'); + } + + public function testTransactionShortcutCustom() + { + $connection = $this->getConnection(true); + + $result = $connection->transaction(function (Connection $db) { + $db->createCommand()->insert('profile', ['description' => 'test transaction shortcut'])->execute(); + return true; + }, Transaction::READ_UNCOMMITTED); + + $this->assertTrue($result, 'transaction shortcut valid value should be returned from callback'); + + $profilesCount = $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction shortcut';")->queryScalar(); + $this->assertEquals(1, $profilesCount, 'profile should be inserted in transaction shortcut'); + } + +} diff --git a/tests/framework/db/DatabaseTestCase.php b/tests/framework/db/DatabaseTestCase.php new file mode 100644 index 0000000..e500e6c --- /dev/null +++ b/tests/framework/db/DatabaseTestCase.php @@ -0,0 +1,92 @@ +database = $databases[$this->driverName]; + $pdo_database = 'pdo_'.$this->driverName; + if ($this->driverName === 'oci') { + $pdo_database = 'oci8'; + } + + if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) { + $this->markTestSkipped('pdo and '.$pdo_database.' extension are required.'); + } + $this->mockApplication(); + } + + protected function tearDown() + { + if ($this->_db) { + $this->_db->close(); + } + $this->destroyApplication(); + } + + /** + * @param boolean $reset whether to clean up the test database + * @param boolean $open whether to open and populate test database + * @return \yii\db\Connection + */ + public function getConnection($reset = true, $open = true) + { + if (!$reset && $this->_db) { + return $this->_db; + } + $config = $this->database; + if (isset($config['fixture'])) { + $fixture = $config['fixture']; + unset($config['fixture']); + } else { + $fixture = null; + } + try { + $this->_db = $this->prepareDatabase($config, $fixture, $open); + } catch (\Exception $e) { + $this->markTestSkipped("Something wrong when preparing database: " . $e->getMessage()); + } + return $this->_db; + } + + public function prepareDatabase($config, $fixture, $open = true) + { + if (!isset($config['class'])) { + $config['class'] = 'yii\db\Connection'; + } + /* @var $db \yii\db\Connection */ + $db = \Yii::createObject($config); + if (!$open) { + return $db; + } + $db->open(); + if ($fixture !== null) { + if ($this->driverName === 'oci') { + list($drops, $creates) = explode('/* STATEMENTS */', file_get_contents($fixture), 2); + list($statements, $triggers, $data) = explode('/* TRIGGERS */', $creates, 3); + $lines = array_merge(explode('--', $drops), explode(';', $statements), explode('/', $triggers), explode(';', $data)); + } else { + $lines = explode(';', file_get_contents($fixture)); + } + foreach ($lines as $line) { + if (trim($line) !== '') { + $db->pdo->exec($line); + } + } + } + return $db; + } +} diff --git a/tests/framework/db/QueryBuilderTest.php b/tests/framework/db/QueryBuilderTest.php new file mode 100644 index 0000000..3c265e5 --- /dev/null +++ b/tests/framework/db/QueryBuilderTest.php @@ -0,0 +1,480 @@ +driverName) { + case 'mysql': + return new MysqlQueryBuilder($this->getConnection(true, false)); + case 'sqlite': + return new SqliteQueryBuilder($this->getConnection(true, false)); + case 'mssql': + return new MssqlQueryBuilder($this->getConnection(true, false)); + case 'pgsql': + return new PgsqlQueryBuilder($this->getConnection(true, false)); + case 'cubrid': + return new CubridQueryBuilder($this->getConnection(true, false)); + } + throw new \Exception('Test is not implemented for ' . $this->driverName); + } + + /** + * adjust dbms specific escaping + * @param $sql + * @return mixed + */ + protected function replaceQuotes($sql) + { + if (!in_array($this->driverName, ['mssql', 'mysql', 'sqlite'])) { + return str_replace('`', '"', $sql); + } + return $sql; + } + + /** + * this is not used as a dataprovider for testGetColumnType to speed up the test + * when used as dataprovider every single line will cause a reconnect with the database which is not needed here + */ + public function columnTypes() + { + return [ + [Schema::TYPE_PK, 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY'], + [Schema::TYPE_PK . '(8)', 'int(8) NOT NULL AUTO_INCREMENT PRIMARY KEY'], + [Schema::TYPE_PK . ' CHECK (value > 5)', 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], + [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'int(8) NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], + [Schema::TYPE_STRING, 'varchar(255)'], + [Schema::TYPE_STRING . '(32)', 'varchar(32)'], + [Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'], + [Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'], + [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], + [Schema::TYPE_TEXT, 'text'], + [Schema::TYPE_TEXT . '(255)', 'text'], + [Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], + [Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], + [Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'], + [Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'], + [Schema::TYPE_SMALLINT, 'smallint(6)'], + [Schema::TYPE_SMALLINT . '(8)', 'smallint(8)'], + [Schema::TYPE_INTEGER, 'int(11)'], + [Schema::TYPE_INTEGER . '(8)', 'int(8)'], + [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'int(11) CHECK (value > 5)'], + [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'int(8) CHECK (value > 5)'], + [Schema::TYPE_INTEGER . ' NOT NULL', 'int(11) NOT NULL'], + [Schema::TYPE_BIGINT, 'bigint(20)'], + [Schema::TYPE_BIGINT . '(8)', 'bigint(8)'], + [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint(20) CHECK (value > 5)'], + [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint(8) CHECK (value > 5)'], + [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint(20) NOT NULL'], + [Schema::TYPE_FLOAT, 'float'], + [Schema::TYPE_FLOAT . '(16,5)', 'float'], + [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], + [Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], + [Schema::TYPE_FLOAT . ' NOT NULL', 'float NOT NULL'], + [Schema::TYPE_DOUBLE, 'double'], + [Schema::TYPE_DOUBLE . '(16,5)', 'double'], + [Schema::TYPE_DOUBLE . ' CHECK (value > 5.6)', 'double CHECK (value > 5.6)'], + [Schema::TYPE_DOUBLE . '(16,5) CHECK (value > 5.6)', 'double CHECK (value > 5.6)'], + [Schema::TYPE_DOUBLE . ' NOT NULL', 'double NOT NULL'], + [Schema::TYPE_DECIMAL, 'decimal(10,0)'], + [Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'], + [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'], + [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'], + [Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'], + [Schema::TYPE_DATETIME, 'datetime'], + [Schema::TYPE_DATETIME . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'], + [Schema::TYPE_TIMESTAMP, 'timestamp'], + [Schema::TYPE_TIMESTAMP . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'], + [Schema::TYPE_TIME, 'time'], + [Schema::TYPE_TIME . " CHECK(value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK(value BETWEEN '12:00:00' AND '13:01:01')"], + [Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'], + [Schema::TYPE_DATE, 'date'], + [Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], + [Schema::TYPE_BINARY, 'blob'], + [Schema::TYPE_BOOLEAN, 'tinyint(1)'], + [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'tinyint(1) NOT NULL DEFAULT 1'], + [Schema::TYPE_MONEY, 'decimal(19,4)'], + [Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'], + [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'], + [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'], + [Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'], + ]; + } + + public function testGetColumnType() + { + $qb = $this->getQueryBuilder(); + foreach ($this->columnTypes() as $item) { + list ($column, $expected) = $item; + $this->assertEquals($expected, $qb->getColumnType($column)); + } + } + + public function testCreateTableColumnTypes() + { + $qb = $this->getQueryBuilder(); + if ($qb->db->getTableSchema('column_type_table', true) !== null) { + $this->getConnection(false)->createCommand($qb->dropTable('column_type_table'))->execute(); + } + $columns = []; + $i = 0; + foreach ($this->columnTypes() as $item) { + list ($column, $expected) = $item; + if (strncmp($column, 'pk', 2) !== 0) { + $columns['col' . ++$i] = str_replace('CHECK (value', 'CHECK (col' . $i, $column); + } + } + $this->getConnection(false)->createCommand($qb->createTable('column_type_table', $columns))->execute(); + } + + public function conditionProvider() + { + $conditions = [ + // empty values + [ ['like', 'name', []], '0=1', [] ], + [ ['not like', 'name', []], '', [] ], + [ ['or like', 'name', []], '0=1', [] ], + [ ['or not like', 'name', []], '', [] ], + + // simple like + [ ['like', 'name', 'heyho'], '`name` LIKE :qp0', [':qp0' => '%heyho%'] ], + [ ['not like', 'name', 'heyho'], '`name` NOT LIKE :qp0', [':qp0' => '%heyho%'] ], + [ ['or like', 'name', 'heyho'], '`name` LIKE :qp0', [':qp0' => '%heyho%'] ], + [ ['or not like', 'name', 'heyho'], '`name` NOT LIKE :qp0', [':qp0' => '%heyho%'] ], + + // like for many values + [ ['like', 'name', ['heyho', 'abc']], '`name` LIKE :qp0 AND `name` LIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], + [ ['not like', 'name', ['heyho', 'abc']], '`name` NOT LIKE :qp0 AND `name` NOT LIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], + [ ['or like', 'name', ['heyho', 'abc']], '`name` LIKE :qp0 OR `name` LIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], + [ ['or not like', 'name', ['heyho', 'abc']], '`name` NOT LIKE :qp0 OR `name` NOT LIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], + + // like with Expression + [ ['like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` LIKE CONCAT("test", colname, "%")', [] ], + [ ['not like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` NOT LIKE CONCAT("test", colname, "%")', [] ], + [ ['or like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` LIKE CONCAT("test", colname, "%")', [] ], + [ ['or not like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` NOT LIKE CONCAT("test", colname, "%")', [] ], + [ ['like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` LIKE CONCAT("test", colname, "%") AND `name` LIKE :qp0', [':qp0' => '%abc%'] ], + [ ['not like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` NOT LIKE CONCAT("test", colname, "%") AND `name` NOT LIKE :qp0', [':qp0' => '%abc%'] ], + [ ['or like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` LIKE CONCAT("test", colname, "%") OR `name` LIKE :qp0', [':qp0' => '%abc%'] ], + [ ['or not like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` NOT LIKE CONCAT("test", colname, "%") OR `name` NOT LIKE :qp0', [':qp0' => '%abc%'] ], + + // not + [ ['not', 'name'], 'NOT (name)', [] ], + + // and + [ ['and', 'id=1', 'id=2'], '(id=1) AND (id=2)', [] ], + [ ['and', 'type=1', ['or', 'id=1', 'id=2']], '(type=1) AND ((id=1) OR (id=2))', [] ], + + // or + [ ['or', 'id=1', 'id=2'], '(id=1) OR (id=2)', [] ], + [ ['or', 'type=1', ['or', 'id=1', 'id=2']], '(type=1) OR ((id=1) OR (id=2))', [] ], + + // between + [ ['between', 'id', 1, 10], '`id` BETWEEN :qp0 AND :qp1', [':qp0' => 1, ':qp1' => 10] ], + [ ['not between', 'id', 1, 10], '`id` NOT BETWEEN :qp0 AND :qp1', [':qp0' => 1, ':qp1' => 10] ], + [ ['between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), new Expression('NOW()')], '`date` BETWEEN (NOW() - INTERVAL 1 MONTH) AND NOW()', [] ], + [ ['between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), 123], '`date` BETWEEN (NOW() - INTERVAL 1 MONTH) AND :qp0', [':qp0' => 123] ], + [ ['not between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), new Expression('NOW()')], '`date` NOT BETWEEN (NOW() - INTERVAL 1 MONTH) AND NOW()', [] ], + [ ['not between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), 123], '`date` NOT BETWEEN (NOW() - INTERVAL 1 MONTH) AND :qp0', [':qp0' => 123] ], + + // in + [ ['in', 'id', [1, 2, 3]], '`id` IN (:qp0, :qp1, :qp2)', [':qp0' => 1, ':qp1' => 2, ':qp2' => 3] ], + [ ['not in', 'id', [1, 2, 3]], '`id` NOT IN (:qp0, :qp1, :qp2)', [':qp0' => 1, ':qp1' => 2, ':qp2' => 3] ], + [ ['in', 'id', (new Query())->select('id')->from('users')->where(['active' => 1])], '`id` IN (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], + [ ['not in', 'id', (new Query())->select('id')->from('users')->where(['active' => 1])], '`id` NOT IN (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], + + // exists + [ ['exists', (new Query())->select('id')->from('users')->where(['active' => 1])], 'EXISTS (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], + [ ['not exists', (new Query())->select('id')->from('users')->where(['active' => 1])], 'NOT EXISTS (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], + + // simple conditions + [ ['=', 'a', 'b'], '`a` = :qp0', [':qp0' => 'b'] ], + [ ['>', 'a', 1], '`a` > :qp0', [':qp0' => 1] ], + [ ['>=', 'a', 'b'], '`a` >= :qp0', [':qp0' => 'b'] ], + [ ['<', 'a', 2], '`a` < :qp0', [':qp0' => 2] ], + [ ['<=', 'a', 'b'], '`a` <= :qp0', [':qp0' => 'b'] ], + [ ['<>', 'a', 3], '`a` <> :qp0', [':qp0' => 3] ], + [ ['!=', 'a', 'b'], '`a` != :qp0', [':qp0' => 'b'] ], + [ ['>=', 'date', new Expression('DATE_SUB(NOW(), INTERVAL 1 MONTH)')], '`date` >= DATE_SUB(NOW(), INTERVAL 1 MONTH)', [] ], + [ ['>=', 'date', new Expression('DATE_SUB(NOW(), INTERVAL :month MONTH)', [':month' => 2])], '`date` >= DATE_SUB(NOW(), INTERVAL :month MONTH)', [':month' => 2] ], + [ ['=', 'date', (new Query())->select('max(date)')->from('test')->where(['id' => 5])], '`date` = (SELECT max(date) FROM `test` WHERE `id`=:qp0)', [':qp0' => 5] ], + + // hash condition + [ ['a' => 1, 'b' => 2], '(`a`=:qp0) AND (`b`=:qp1)', [':qp0' => 1, ':qp1' => 2] ], + [ ['a' => new Expression('CONCAT(col1, col2)'), 'b' => 2], '(`a`=CONCAT(col1, col2)) AND (`b`=:qp0)', [':qp0' => 2] ], + + ]; + + switch ($this->driverName) { + case 'mssql': + case 'sqlite': + $conditions = array_merge($conditions, [ + [ ['in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '((`id` = :qp0 AND `name` = :qp1) OR (`id` = :qp2 AND `name` = :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ], + [ ['not in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '((`id` != :qp0 OR `name` != :qp1) AND (`id` != :qp2 OR `name` != :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ], + //[ ['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], 'EXISTS (SELECT 1 FROM (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0) AS a WHERE a.`id` = `id AND a.`name` = `name`)', [':qp0' => 1] ], + //[ ['not in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], 'NOT EXISTS (SELECT 1 FROM (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0) AS a WHERE a.`id` = `id` AND a.`name = `name`)', [':qp0' => 1] ], + ]); + break; + default: + $conditions = array_merge($conditions, [ + [ ['in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(`id`, `name`) IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ], + [ ['not in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(`id`, `name`) NOT IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ], + [ ['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], '(`id`, `name`) IN (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], + [ ['not in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], '(`id`, `name`) NOT IN (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], + ]); + break; + } + + // adjust dbms specific escaping + foreach($conditions as $i => $condition) { + $conditions[$i][1] = $this->replaceQuotes($condition[1]); + } + return $conditions; + } + + public function filterConditionProvider() + { + $conditions = [ + // like + [ ['like', 'name', []], '', [] ], + [ ['not like', 'name', []], '', [] ], + [ ['or like', 'name', []], '', [] ], + [ ['or not like', 'name', []], '', [] ], + + // not + [ ['not', ''], '', [] ], + + // and + [ ['and', '', ''], '', [] ], + [ ['and', '', 'id=2'], '(id=2)', [] ], + [ ['and', 'id=1', ''], '(id=1)', [] ], + [ ['and', 'type=1', ['or', '', 'id=2']], '(type=1) AND ((id=2))', [] ], + + // or + [ ['or', 'id=1', ''], '(id=1)', [] ], + [ ['or', 'type=1', ['or', '', 'id=2']], '(type=1) OR ((id=2))', [] ], + + + // between + [ ['between', 'id', 1, null], '', [] ], + [ ['not between', 'id', null, 10], '', [] ], + + // in + [ ['in', 'id', []], '', [] ], + [ ['not in', 'id', []], '', [] ], + + // simple conditions + [ ['=', 'a', ''], '', [] ], + [ ['>', 'a', ''], '', [] ], + [ ['>=', 'a', ''], '', [] ], + [ ['<', 'a', ''], '', [] ], + [ ['<=', 'a', ''], '', [] ], + [ ['<>', 'a', ''], '', [] ], + [ ['!=', 'a', ''], '', [] ], + ]; + + // adjust dbms specific escaping + foreach($conditions as $i => $condition) { + $conditions[$i][1] = $this->replaceQuotes($condition[1]); + } + return $conditions; + } + + /** + * @dataProvider conditionProvider + */ + public function testBuildCondition($condition, $expected, $expectedParams) + { + $query = (new Query())->where($condition); + list($sql, $params) = $this->getQueryBuilder()->build($query); + $this->assertEquals('SELECT *' . (empty($expected) ? '' : ' WHERE ' . $expected), $sql); + $this->assertEquals($expectedParams, $params); + } + + /** + * @dataProvider filterConditionProvider + */ + public function testBuildFilterCondition($condition, $expected, $expectedParams) + { + $query = (new Query())->filterWhere($condition); + list($sql, $params) = $this->getQueryBuilder()->build($query); + $this->assertEquals('SELECT *' . (empty($expected) ? '' : ' WHERE ' . $expected), $sql); + $this->assertEquals($expectedParams, $params); + } + + public function testAddDropPrimaryKey() + { + $tableName = 'constraints'; + $pkeyName = $tableName . "_pkey"; + + // ADD + $qb = $this->getQueryBuilder(); + $qb->db->createCommand()->addPrimaryKey($pkeyName, $tableName, ['id'])->execute(); + $tableSchema = $qb->db->getSchema()->getTableSchema($tableName); + $this->assertEquals(1, count($tableSchema->primaryKey)); + + //DROP + $qb->db->createCommand()->dropPrimaryKey($pkeyName, $tableName)->execute(); + $qb = $this->getQueryBuilder(); // resets the schema + $tableSchema = $qb->db->getSchema()->getTableSchema($tableName); + $this->assertEquals(0, count($tableSchema->primaryKey)); + } + + public function existsParamsProvider() + { + return [ + ['exists', $this->replaceQuotes("SELECT `id` FROM `TotalExample` `t` WHERE EXISTS (SELECT `1` FROM `Website` `w`)")], + ['not exists', $this->replaceQuotes("SELECT `id` FROM `TotalExample` `t` WHERE NOT EXISTS (SELECT `1` FROM `Website` `w`)")] + ]; + } + + /** + * @dataProvider existsParamsProvider + */ + public function testBuildWhereExists($cond, $expectedQuerySql) + { + $expectedQueryParams = []; + + $subQuery = new Query(); + $subQuery->select('1') + ->from('Website w'); + + $query = new Query(); + $query->select('id') + ->from('TotalExample t') + ->where([$cond, $subQuery]); + + list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query); + $this->assertEquals($expectedQuerySql, $actualQuerySql); + $this->assertEquals($expectedQueryParams, $actualQueryParams); + } + + + public function testBuildWhereExistsWithParameters() + { + $expectedQuerySql = $this->replaceQuotes( + "SELECT `id` FROM `TotalExample` `t` WHERE (EXISTS (SELECT `1` FROM `Website` `w` WHERE (w.id = t.website_id) AND (w.merchant_id = :merchant_id))) AND (t.some_column = :some_value)" + ); + $expectedQueryParams = [':some_value' => "asd", ':merchant_id' => 6]; + + $subQuery = new Query(); + $subQuery->select('1') + ->from('Website w') + ->where('w.id = t.website_id') + ->andWhere('w.merchant_id = :merchant_id', [':merchant_id' => 6]); + + $query = new Query(); + $query->select('id') + ->from('TotalExample t') + ->where(['exists', $subQuery]) + ->andWhere('t.some_column = :some_value', [':some_value' => "asd"]); + + list($actualQuerySql, $queryParams) = $this->getQueryBuilder()->build($query); + $this->assertEquals($expectedQuerySql, $actualQuerySql); + $this->assertEquals($expectedQueryParams, $queryParams); + } + + public function testBuildWhereExistsWithArrayParameters() + { + $expectedQuerySql = $this->replaceQuotes( + "SELECT `id` FROM `TotalExample` `t` WHERE (EXISTS (SELECT `1` FROM `Website` `w` WHERE (w.id = t.website_id) AND ((`w`.`merchant_id`=:qp0) AND (`w`.`user_id`=:qp1)))) AND (`t`.`some_column`=:qp2)" + ); + $expectedQueryParams = [':qp0' => 6, ':qp1' => 210, ':qp2' => 'asd']; + + $subQuery = new Query(); + $subQuery->select('1') + ->from('Website w') + ->where('w.id = t.website_id') + ->andWhere(['w.merchant_id' => 6, 'w.user_id' => '210']); + + $query = new Query(); + $query->select('id') + ->from('TotalExample t') + ->where(['exists', $subQuery]) + ->andWhere(['t.some_column' => "asd"]); + + list($actualQuerySql, $queryParams) = $this->getQueryBuilder()->build($query); + $this->assertEquals($expectedQuerySql, $actualQuerySql); + $this->assertEquals($expectedQueryParams, $queryParams); + } + + /** + * This test contains three select queries connected with UNION and UNION ALL constructions. + * It could be useful to use "phpunit --group=db --filter testBuildUnion" command for run it. + */ + public function testBuildUnion() + { + $expectedQuerySql = $this->replaceQuotes( + "(SELECT `id` FROM `TotalExample` `t1` WHERE (w > 0) AND (x < 2)) UNION ( SELECT `id` FROM `TotalTotalExample` `t2` WHERE w > 5 ) UNION ALL ( SELECT `id` FROM `TotalTotalExample` `t3` WHERE w = 3 )" + ); + $query = new Query(); + $secondQuery = new Query(); + $secondQuery->select('id') + ->from('TotalTotalExample t2') + ->where('w > 5'); + $thirdQuery = new Query(); + $thirdQuery->select('id') + ->from('TotalTotalExample t3') + ->where('w = 3'); + $query->select('id') + ->from('TotalExample t1') + ->where(['and', 'w > 0', 'x < 2']) + ->union($secondQuery) + ->union($thirdQuery, TRUE); + list($actualQuerySql, $queryParams) = $this->getQueryBuilder()->build($query); + $this->assertEquals($expectedQuerySql, $actualQuerySql); + $this->assertEquals([], $queryParams); + } + + public function testSelectSubquery() + { + $subquery = (new Query()) + ->select('COUNT(*)') + ->from('operations') + ->where('account_id = accounts.id'); + $query = (new Query()) + ->select('*') + ->from('accounts') + ->addSelect(['operations_count' => $subquery]); + list ($sql, $params) = $this->getQueryBuilder()->build($query); + $expected = $this->replaceQuotes('SELECT *, (SELECT COUNT(*) FROM `operations` WHERE account_id = accounts.id) AS `operations_count` FROM `accounts`'); + $this->assertEquals($expected, $sql); + $this->assertEmpty($params); + } + + public function testCompositeInCondition() + { + $condition = [ + 'in', + ['id', 'name'], + [ + ['id' => 1, 'name' => 'foo'], + ['id' => 2, 'name' => 'bar'], + ], + ]; + (new Query())->from('customer')->where($condition)->all($this->getConnection()); + } +} diff --git a/tests/framework/db/QueryTest.php b/tests/framework/db/QueryTest.php new file mode 100644 index 0000000..9af0781 --- /dev/null +++ b/tests/framework/db/QueryTest.php @@ -0,0 +1,239 @@ +select('*'); + $this->assertEquals(['*'], $query->select); + $this->assertNull($query->distinct); + $this->assertEquals(null, $query->selectOption); + + $query = new Query; + $query->select('id, name', 'something')->distinct(true); + $this->assertEquals(['id', 'name'], $query->select); + $this->assertTrue($query->distinct); + $this->assertEquals('something', $query->selectOption); + + $query = new Query(); + $query->addSelect('email'); + $this->assertEquals(['email'], $query->select); + + $query = new Query(); + $query->select('id, name'); + $query->addSelect('email'); + $this->assertEquals(['id', 'name', 'email'], $query->select); + } + + public function testFrom() + { + $query = new Query; + $query->from('user'); + $this->assertEquals(['user'], $query->from); + } + + public function testWhere() + { + $query = new Query; + $query->where('id = :id', [':id' => 1]); + $this->assertEquals('id = :id', $query->where); + $this->assertEquals([':id' => 1], $query->params); + + $query->andWhere('name = :name', [':name' => 'something']); + $this->assertEquals(['and', 'id = :id', 'name = :name'], $query->where); + $this->assertEquals([':id' => 1, ':name' => 'something'], $query->params); + + $query->orWhere('age = :age', [':age' => '30']); + $this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->where); + $this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params); + } + + public function testFilterWhere() + { + // should work with hash format + $query = new Query; + $query->filterWhere([ + 'id' => 0, + 'title' => ' ', + 'author_ids' => [], + ]); + $this->assertEquals(['id' => 0], $query->where); + + $query->andFilterWhere(['status' => null]); + $this->assertEquals(['id' => 0], $query->where); + + $query->orFilterWhere(['name' => '']); + $this->assertEquals(['id' => 0], $query->where); + + // should work with operator format + $query = new Query; + $condition = ['like', 'name', 'Alex']; + $query->filterWhere($condition); + $this->assertEquals($condition, $query->where); + + $query->andFilterWhere(['between', 'id', null, null]); + $this->assertEquals($condition, $query->where); + + $query->orFilterWhere(['not between', 'id', null, null]); + $this->assertEquals($condition, $query->where); + + $query->andFilterWhere(['in', 'id', []]); + $this->assertEquals($condition, $query->where); + + $query->andFilterWhere(['not in', 'id', []]); + $this->assertEquals($condition, $query->where); + + $query->andFilterWhere(['not in', 'id', []]); + $this->assertEquals($condition, $query->where); + + $query->andFilterWhere(['like', 'id', '']); + $this->assertEquals($condition, $query->where); + + $query->andFilterWhere(['or like', 'id', '']); + $this->assertEquals($condition, $query->where); + + $query->andFilterWhere(['not like', 'id', ' ']); + $this->assertEquals($condition, $query->where); + + $query->andFilterWhere(['or not like', 'id', null]); + $this->assertEquals($condition, $query->where); + } + + public function testFilterRecursively() + { + $query = new Query(); + $query->filterWhere(['and', ['like', 'name', ''], ['like', 'title', ''], ['id' => 1], ['not', ['like', 'name', '']]]); + $this->assertEquals(['and', ['id' => 1]], $query->where); + } + + public function testJoin() + { + } + + public function testGroup() + { + $query = new Query; + $query->groupBy('team'); + $this->assertEquals(['team'], $query->groupBy); + + $query->addGroupBy('company'); + $this->assertEquals(['team', 'company'], $query->groupBy); + + $query->addGroupBy('age'); + $this->assertEquals(['team', 'company', 'age'], $query->groupBy); + } + + public function testHaving() + { + $query = new Query; + $query->having('id = :id', [':id' => 1]); + $this->assertEquals('id = :id', $query->having); + $this->assertEquals([':id' => 1], $query->params); + + $query->andHaving('name = :name', [':name' => 'something']); + $this->assertEquals(['and', 'id = :id', 'name = :name'], $query->having); + $this->assertEquals([':id' => 1, ':name' => 'something'], $query->params); + + $query->orHaving('age = :age', [':age' => '30']); + $this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->having); + $this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params); + } + + public function testOrder() + { + $query = new Query; + $query->orderBy('team'); + $this->assertEquals(['team' => SORT_ASC], $query->orderBy); + + $query->addOrderBy('company'); + $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC], $query->orderBy); + + $query->addOrderBy('age'); + $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_ASC], $query->orderBy); + + $query->addOrderBy(['age' => SORT_DESC]); + $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_DESC], $query->orderBy); + + $query->addOrderBy('age ASC, company DESC'); + $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_DESC, 'age' => SORT_ASC], $query->orderBy); + } + + public function testLimitOffset() + { + $query = new Query; + $query->limit(10)->offset(5); + $this->assertEquals(10, $query->limit); + $this->assertEquals(5, $query->offset); + } + + public function testUnion() + { + } + + public function testOne() + { + $db = $this->getConnection(); + + $result = (new Query)->from('customer')->where(['status' => 2])->one($db); + $this->assertEquals('user3', $result['name']); + + $result = (new Query)->from('customer')->where(['status' => 3])->one($db); + $this->assertFalse($result); + } + + public function testColumn() + { + $db = $this->getConnection(); + $result = (new Query)->select('name')->from('customer')->orderBy(['id' => SORT_DESC])->column($db); + $this->assertEquals(['user3', 'user2', 'user1'], $result); + + // https://github.com/yiisoft/yii2/issues/7515 + $result = (new Query)->from('customer') + ->select('name') + ->orderBy(['id' => SORT_DESC]) + ->indexBy('id') + ->column($db); + $this->assertEquals([3 => 'user3', 2 => 'user2', 1 => 'user1'], $result); + } + + public function testCount() + { + $db = $this->getConnection(); + + $count = (new Query)->from('customer')->count('*', $db); + $this->assertEquals(3, $count); + + $count = (new Query)->from('customer')->where(['status' => 2])->count('*', $db); + $this->assertEquals(1, $count); + + $count = (new Query)->select('status, COUNT(id)')->from('customer')->groupBy('status')->count('*', $db); + $this->assertEquals(2, $count); + } + + /** + * @see https://github.com/yiisoft/yii2/issues/8068 + * + * @depends testCount + */ + public function testCountHavingWithoutGroupBy() + { + if (!in_array($this->driverName, ['mysql'])) { + $this->markTestSkipped("{$this->driverName} does not support having without group by."); + } + + $db = $this->getConnection(); + + $count = (new Query)->from('customer')->having(['status' => 2])->count('*', $db); + $this->assertEquals(1, $count); + } +} diff --git a/tests/framework/db/SchemaTest.php b/tests/framework/db/SchemaTest.php new file mode 100644 index 0000000..1277faa --- /dev/null +++ b/tests/framework/db/SchemaTest.php @@ -0,0 +1,336 @@ +getConnection()->schema; + + $tables = $schema->getTableNames(); + $this->assertTrue(in_array('customer', $tables)); + $this->assertTrue(in_array('category', $tables)); + $this->assertTrue(in_array('item', $tables)); + $this->assertTrue(in_array('order', $tables)); + $this->assertTrue(in_array('order_item', $tables)); + $this->assertTrue(in_array('type', $tables)); + $this->assertTrue(in_array('animal', $tables)); + $this->assertTrue(in_array('animal_view', $tables)); + } + + public function testGetTableSchemas() + { + /* @var $schema Schema */ + $schema = $this->getConnection()->schema; + + $tables = $schema->getTableSchemas(); + $this->assertEquals(count($schema->getTableNames()), count($tables)); + foreach ($tables as $table) { + $this->assertInstanceOf('yii\db\TableSchema', $table); + } + } + + public function testGetTableSchemasWithAttrCase() + { + $db = $this->getConnection(false); + $db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER); + $this->assertEquals(count($db->schema->getTableNames()), count($db->schema->getTableSchemas())); + + $db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_UPPER); + $this->assertEquals(count($db->schema->getTableNames()), count($db->schema->getTableSchemas())); + } + + public function testGetNonExistingTableSchema() + { + $this->assertNull($this->getConnection()->schema->getTableSchema('nonexisting_table')); + } + + public function testSchemaCache() + { + /* @var $schema Schema */ + $schema = $this->getConnection()->schema; + + $schema->db->enableSchemaCache = true; + $schema->db->schemaCache = new FileCache(); + $noCacheTable = $schema->getTableSchema('type', true); + $cachedTable = $schema->getTableSchema('type', false); + $this->assertEquals($noCacheTable, $cachedTable); + } + + public function testCompositeFk() + { + /* @var $schema Schema */ + $schema = $this->getConnection()->schema; + + $table = $schema->getTableSchema('composite_fk'); + + $this->assertCount(1, $table->foreignKeys); + $this->assertTrue(isset($table->foreignKeys[0])); + $this->assertEquals('order_item', $table->foreignKeys[0][0]); + $this->assertEquals('order_id', $table->foreignKeys[0]['order_id']); + $this->assertEquals('item_id', $table->foreignKeys[0]['item_id']); + } + + public function testGetPDOType() + { + $values = [ + [null, \PDO::PARAM_NULL], + ['', \PDO::PARAM_STR], + ['hello', \PDO::PARAM_STR], + [0, \PDO::PARAM_INT], + [1, \PDO::PARAM_INT], + [1337, \PDO::PARAM_INT], + [true, \PDO::PARAM_BOOL], + [false, \PDO::PARAM_BOOL], + [$fp = fopen(__FILE__, 'rb'), \PDO::PARAM_LOB], + ]; + + /* @var $schema Schema */ + $schema = $this->getConnection()->schema; + + foreach ($values as $value) { + $this->assertEquals($value[1], $schema->getPdoType($value[0]), 'type for value ' . print_r($value[0], true) . ' does not match.'); + } + fclose($fp); + } + + public function getExpectedColumns() + { + return [ + 'int_col' => [ + 'type' => 'integer', + 'dbType' => 'int(11)', + 'phpType' => 'integer', + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => 11, + 'precision' => 11, + 'scale' => null, + 'defaultValue' => null, + ], + 'int_col2' => [ + 'type' => 'integer', + 'dbType' => 'int(11)', + 'phpType' => 'integer', + 'allowNull' => true, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => 11, + 'precision' => 11, + 'scale' => null, + 'defaultValue' => 1, + ], + 'smallint_col' => [ + 'type' => 'smallint', + 'dbType' => 'smallint(1)', + 'phpType' => 'integer', + 'allowNull' => true, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => 1, + 'precision' => 1, + 'scale' => null, + 'defaultValue' => 1, + ], + 'char_col' => [ + 'type' => 'string', + 'dbType' => 'char(100)', + 'phpType' => 'string', + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => 100, + 'precision' => 100, + 'scale' => null, + 'defaultValue' => null, + ], + 'char_col2' => [ + 'type' => 'string', + 'dbType' => 'varchar(100)', + 'phpType' => 'string', + 'allowNull' => true, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => 100, + 'precision' => 100, + 'scale' => null, + 'defaultValue' => 'something', + ], + 'char_col3' => [ + 'type' => 'text', + 'dbType' => 'text', + 'phpType' => 'string', + 'allowNull' => true, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => null, + 'precision' => null, + 'scale' => null, + 'defaultValue' => null, + ], + 'enum_col' => [ + 'type' => 'string', + 'dbType' => "enum('a','B')", + 'phpType' => 'string', + 'allowNull' => true, + 'autoIncrement' => false, + 'enumValues' => ['a', 'B'], + 'size' => null, + 'precision' => null, + 'scale' => null, + 'defaultValue' => null, + ], + 'float_col' => [ + 'type' => 'double', + 'dbType' => 'double(4,3)', + 'phpType' => 'double', + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => 4, + 'precision' => 4, + 'scale' => 3, + 'defaultValue' => null, + ], + 'float_col2' => [ + 'type' => 'double', + 'dbType' => 'double', + 'phpType' => 'double', + 'allowNull' => true, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => null, + 'precision' => null, + 'scale' => null, + 'defaultValue' => 1.23, + ], + 'blob_col' => [ + 'type' => 'binary', + 'dbType' => 'blob', + 'phpType' => 'resource', + 'allowNull' => true, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => null, + 'precision' => null, + 'scale' => null, + 'defaultValue' => null, + ], + 'numeric_col' => [ + 'type' => 'decimal', + 'dbType' => 'decimal(5,2)', + 'phpType' => 'string', + 'allowNull' => true, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => 5, + 'precision' => 5, + 'scale' => 2, + 'defaultValue' => '33.22', + ], + 'time' => [ + 'type' => 'timestamp', + 'dbType' => 'timestamp', + 'phpType' => 'string', + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => null, + 'precision' => null, + 'scale' => null, + 'defaultValue' => '2002-01-01 00:00:00', + ], + 'bool_col' => [ + 'type' => 'smallint', + 'dbType' => 'tinyint(1)', + 'phpType' => 'integer', + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => 1, + 'precision' => 1, + 'scale' => null, + 'defaultValue' => null, + ], + 'bool_col2' => [ + 'type' => 'smallint', + 'dbType' => 'tinyint(1)', + 'phpType' => 'integer', + 'allowNull' => true, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => 1, + 'precision' => 1, + 'scale' => null, + 'defaultValue' => 1, + ], + 'ts_default' => [ + 'type' => 'timestamp', + 'dbType' => 'timestamp', + 'phpType' => 'string', + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => null, + 'precision' => null, + 'scale' => null, + 'defaultValue' => new Expression('CURRENT_TIMESTAMP'), + ], + 'bit_col' => [ + 'type' => 'integer', + 'dbType' => 'bit(8)', + 'phpType' => 'integer', + 'allowNull' => false, + 'autoIncrement' => false, + 'enumValues' => null, + 'size' => 8, + 'precision' => 8, + 'scale' => null, + 'defaultValue' => 130, // b'10000010' + ], + ]; + } + + public function testColumnSchema() + { + $columns = $this->getExpectedColumns(); + + $table = $this->getConnection(false)->schema->getTableSchema('type', true); + + $expectedColNames = array_keys($columns); + sort($expectedColNames); + $colNames = $table->columnNames; + sort($colNames); + $this->assertEquals($expectedColNames, $colNames); + + foreach($table->columns as $name => $column) { + $expected = $columns[$name]; + $this->assertSame($expected['dbType'], $column->dbType, "dbType of colum $name does not match. type is $column->type, dbType is $column->dbType."); + $this->assertSame($expected['phpType'], $column->phpType, "phpType of colum $name does not match. type is $column->type, dbType is $column->dbType."); + $this->assertSame($expected['type'], $column->type, "type of colum $name does not match."); + $this->assertSame($expected['allowNull'], $column->allowNull, "allowNull of colum $name does not match."); + $this->assertSame($expected['autoIncrement'], $column->autoIncrement, "autoIncrement of colum $name does not match."); + $this->assertSame($expected['enumValues'], $column->enumValues, "enumValues of colum $name does not match."); + $this->assertSame($expected['size'], $column->size, "size of colum $name does not match."); + $this->assertSame($expected['precision'], $column->precision, "precision of colum $name does not match."); + $this->assertSame($expected['scale'], $column->scale, "scale of colum $name does not match."); + if (is_object($expected['defaultValue'])) { + $this->assertTrue(is_object($column->defaultValue), "defaultValue of colum $name is expected to be an object but it is not."); + $this->assertEquals((string) $expected['defaultValue'], (string) $column->defaultValue, "defaultValue of colum $name does not match."); + } else { + $this->assertSame($expected['defaultValue'], $column->defaultValue, "defaultValue of colum $name does not match."); + } + } + } +} diff --git a/tests/framework/db/cubrid/CubridActiveDataProviderTest.php b/tests/framework/db/cubrid/CubridActiveDataProviderTest.php new file mode 100644 index 0000000..f01e69f --- /dev/null +++ b/tests/framework/db/cubrid/CubridActiveDataProviderTest.php @@ -0,0 +1,14 @@ +getConnection(); + + // bindParam + $sql = 'INSERT INTO customer(email, name, address) VALUES (:email, :name, :address)'; + $command = $db->createCommand($sql); + $email = 'user4@example.com'; + $name = 'user4'; + $address = 'address4'; + $command->bindParam(':email', $email); + $command->bindParam(':name', $name); + $command->bindParam(':address', $address); + $command->execute(); + + $sql = 'SELECT name FROM customer WHERE email=:email'; + $command = $db->createCommand($sql); + $command->bindParam(':email', $email); + $this->assertEquals($name, $command->queryScalar()); + + $sql = "INSERT INTO type (int_col, char_col, char_col2, enum_col, float_col, blob_col, numeric_col, bool_col) VALUES (:int_col, '', :char_col, :enum_col, :float_col, CHAR_TO_BLOB(:blob_col), :numeric_col, :bool_col)"; + $command = $db->createCommand($sql); + $intCol = 123; + $charCol = 'abc'; + $enumCol = 'a'; + $floatCol = 1.23; + $blobCol = "\x10\x11\x12"; + $numericCol = '1.23'; + $boolCol = true; + $command->bindParam(':int_col', $intCol); + $command->bindParam(':char_col', $charCol); + $command->bindParam(':enum_col', $enumCol); + $command->bindParam(':float_col', $floatCol); + $command->bindParam(':blob_col', $blobCol); + $command->bindParam(':numeric_col', $numericCol); + $command->bindParam(':bool_col', $boolCol); + $this->assertEquals(1, $command->execute()); + + $sql = 'SELECT * FROM type'; + $row = $db->createCommand($sql)->queryOne(); + $this->assertEquals($intCol, $row['int_col']); + $this->assertEquals($enumCol, $row['enum_col']); + $this->assertEquals($charCol, $row['char_col2']); + $this->assertEquals($floatCol, $row['float_col']); + $this->assertEquals($blobCol, fread($row['blob_col'], 3)); + $this->assertEquals($numericCol, $row['numeric_col']); + $this->assertEquals($boolCol, $row['bool_col']); + + // bindValue + $sql = 'INSERT INTO customer(email, name, address) VALUES (:email, \'user5\', \'address5\')'; + $command = $db->createCommand($sql); + $command->bindValue(':email', 'user5@example.com'); + $command->execute(); + + $sql = 'SELECT email FROM customer WHERE name=:name'; + $command = $db->createCommand($sql); + $command->bindValue(':name', 'user5'); + $this->assertEquals('user5@example.com', $command->queryScalar()); + } + + public function testAutoQuoting() + { + $db = $this->getConnection(false); + + $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; + $command = $db->createCommand($sql); + $this->assertEquals('SELECT "id", "t"."name" FROM "customer" t', $command->sql); + } +} diff --git a/tests/framework/db/cubrid/CubridConnectionTest.php b/tests/framework/db/cubrid/CubridConnectionTest.php new file mode 100644 index 0000000..9b432d0 --- /dev/null +++ b/tests/framework/db/cubrid/CubridConnectionTest.php @@ -0,0 +1,44 @@ +getConnection(false); + $this->assertEquals(123, $connection->quoteValue(123)); + $this->assertEquals("'string'", $connection->quoteValue('string')); + $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); + } + + public function testQuoteTableName() + { + $connection = $this->getConnection(false); + $this->assertEquals('"table"', $connection->quoteTableName('table')); + $this->assertEquals('"table"', $connection->quoteTableName('"table"')); + $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema.table')); + $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema."table"')); + $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); + $this->assertEquals('(table)', $connection->quoteTableName('(table)')); + } + + public function testQuoteColumnName() + { + $connection = $this->getConnection(false); + $this->assertEquals('"column"', $connection->quoteColumnName('column')); + $this->assertEquals('"column"', $connection->quoteColumnName('"column"')); + $this->assertEquals('"table"."column"', $connection->quoteColumnName('table.column')); + $this->assertEquals('"table"."column"', $connection->quoteColumnName('table."column"')); + $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); + $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); + $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); + } +} diff --git a/tests/framework/db/cubrid/CubridQueryBuilderTest.php b/tests/framework/db/cubrid/CubridQueryBuilderTest.php new file mode 100644 index 0000000..12d4c0b --- /dev/null +++ b/tests/framework/db/cubrid/CubridQueryBuilderTest.php @@ -0,0 +1,82 @@ + 5)', 'int NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], + [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'int NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], + [Schema::TYPE_STRING, 'varchar(255)'], + [Schema::TYPE_STRING . '(32)', 'varchar(32)'], + [Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'], + [Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'], + [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], + [Schema::TYPE_TEXT, 'varchar'], + [Schema::TYPE_TEXT . '(255)', 'varchar'], + [Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'varchar CHECK (value LIKE "test%")'], + [Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'varchar CHECK (value LIKE "test%")'], + [Schema::TYPE_TEXT . ' NOT NULL', 'varchar NOT NULL'], + [Schema::TYPE_TEXT . '(255) NOT NULL', 'varchar NOT NULL'], + [Schema::TYPE_SMALLINT, 'smallint'], + [Schema::TYPE_SMALLINT . '(8)', 'smallint'], + [Schema::TYPE_INTEGER, 'int'], + [Schema::TYPE_INTEGER . '(8)', 'int'], + [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'int CHECK (value > 5)'], + [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'int CHECK (value > 5)'], + [Schema::TYPE_INTEGER . ' NOT NULL', 'int NOT NULL'], + [Schema::TYPE_BIGINT, 'bigint'], + [Schema::TYPE_BIGINT . '(8)', 'bigint'], + [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'], + [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'], + [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'], + [Schema::TYPE_FLOAT, 'float(7)'], + [Schema::TYPE_FLOAT . '(16)', 'float(16)'], + [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float(7) CHECK (value > 5.6)'], + [Schema::TYPE_FLOAT . '(16) CHECK (value > 5.6)', 'float(16) CHECK (value > 5.6)'], + [Schema::TYPE_FLOAT . ' NOT NULL', 'float(7) NOT NULL'], + [Schema::TYPE_DECIMAL, 'decimal(10,0)'], + [Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'], + [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'], + [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'], + [Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'], + [Schema::TYPE_DATETIME, 'datetime'], + [Schema::TYPE_DATETIME . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'], + [Schema::TYPE_TIMESTAMP, 'timestamp'], + [Schema::TYPE_TIMESTAMP . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'], + [Schema::TYPE_TIME, 'time'], + [Schema::TYPE_TIME . " CHECK (value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK (value BETWEEN '12:00:00' AND '13:01:01')"], + [Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'], + [Schema::TYPE_DATE, 'date'], + [Schema::TYPE_DATE . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], + [Schema::TYPE_BINARY, 'blob'], + [Schema::TYPE_BOOLEAN, 'smallint'], + [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'smallint NOT NULL DEFAULT 1'], + [Schema::TYPE_MONEY, 'decimal(19,4)'], + [Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'], + [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'], + [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'], + [Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'], + ]; + } +} diff --git a/tests/framework/db/cubrid/CubridQueryTest.php b/tests/framework/db/cubrid/CubridQueryTest.php new file mode 100644 index 0000000..50fe0d8 --- /dev/null +++ b/tests/framework/db/cubrid/CubridQueryTest.php @@ -0,0 +1,13 @@ +getConnection()->schema; + + foreach ($values as $value) { + $this->assertEquals($value[1], $schema->getPdoType($value[0])); + } + fclose($fp); + } + + + public function getExpectedColumns() + { + $columns = parent::getExpectedColumns(); + $columns['int_col']['dbType'] = 'integer'; + $columns['int_col']['size'] = null; + $columns['int_col']['precision'] = null; + $columns['int_col2']['dbType'] = 'integer'; + $columns['int_col2']['size'] = null; + $columns['int_col2']['precision'] = null; + $columns['smallint_col']['dbType'] = 'short'; + $columns['smallint_col']['size'] = null; + $columns['smallint_col']['precision'] = null; + $columns['char_col3']['type'] = 'string'; + $columns['char_col3']['dbType'] = 'varchar(1073741823)'; + $columns['char_col3']['size'] = 1073741823; + $columns['char_col3']['precision'] = 1073741823; + $columns['enum_col']['dbType'] = "enum('a', 'B')"; + $columns['float_col']['dbType'] = 'double'; + $columns['float_col']['size'] = null; + $columns['float_col']['precision'] = null; + $columns['float_col']['scale'] = null; + $columns['numeric_col']['dbType'] = 'numeric(5,2)'; + $columns['blob_col']['phpType'] = 'resource'; + $columns['blob_col']['type'] = 'binary'; + $columns['bool_col']['dbType'] = 'short'; + $columns['bool_col']['size'] = null; + $columns['bool_col']['precision'] = null; + $columns['bool_col2']['dbType'] = 'short'; + $columns['bool_col2']['size'] = null; + $columns['bool_col2']['precision'] = null; + $columns['time']['defaultValue'] = '12:00:00 AM 01/01/2002'; + $columns['ts_default']['defaultValue'] = new Expression('SYS_TIMESTAMP'); + return $columns; + } +} diff --git a/tests/framework/db/mssql/MssqlActiveDataProviderTest.php b/tests/framework/db/mssql/MssqlActiveDataProviderTest.php new file mode 100644 index 0000000..e9f4994 --- /dev/null +++ b/tests/framework/db/mssql/MssqlActiveDataProviderTest.php @@ -0,0 +1,14 @@ +getConnection(false); + + $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; + $command = $db->createCommand($sql); + $this->assertEquals("SELECT [id], [t].[name] FROM [customer] t", $command->sql); + } + + public function testPrepareCancel() + { + $this->markTestSkipped('MSSQL driver does not support this feature.'); + } + + public function testBindParamValue() + { + $db = $this->getConnection(); + + // bindParam + $sql = 'INSERT INTO customer(email, name, address) VALUES (:email, :name, :address)'; + $command = $db->createCommand($sql); + $email = 'user4@example.com'; + $name = 'user4'; + $address = 'address4'; + $command->bindParam(':email', $email); + $command->bindParam(':name', $name); + $command->bindParam(':address', $address); + $command->execute(); + + $sql = 'SELECT name FROM customer WHERE email=:email'; + $command = $db->createCommand($sql); + $command->bindParam(':email', $email); + $this->assertEquals($name, $command->queryScalar()); + + $sql = 'INSERT INTO type (int_col, char_col, float_col, blob_col, numeric_col, bool_col) VALUES (:int_col, :char_col, :float_col, CONVERT([varbinary], :blob_col), :numeric_col, :bool_col)'; + $command = $db->createCommand($sql); + $intCol = 123; + $charCol = 'abc'; + $floatCol = 1.23; + $blobCol = "\x10\x11\x12"; + $numericCol = '1.23'; + $boolCol = false; + $command->bindParam(':int_col', $intCol); + $command->bindParam(':char_col', $charCol); + $command->bindParam(':float_col', $floatCol); + $command->bindParam(':blob_col', $blobCol); + $command->bindParam(':numeric_col', $numericCol); + $command->bindParam(':bool_col', $boolCol); + $this->assertEquals(1, $command->execute()); + + $sql = 'SELECT int_col, char_col, float_col, CONVERT([nvarchar], blob_col) AS blob_col, numeric_col FROM type'; + $row = $db->createCommand($sql)->queryOne(); + $this->assertEquals($intCol, $row['int_col']); + $this->assertEquals($charCol, trim($row['char_col'])); + $this->assertEquals($floatCol, $row['float_col']); + $this->assertEquals($blobCol, $row['blob_col']); + $this->assertEquals($numericCol, $row['numeric_col']); + + // bindValue + $sql = 'INSERT INTO customer(email, name, address) VALUES (:email, \'user5\', \'address5\')'; + $command = $db->createCommand($sql); + $command->bindValue(':email', 'user5@example.com'); + $command->execute(); + + $sql = 'SELECT email FROM customer WHERE name=:name'; + $command = $db->createCommand($sql); + $command->bindValue(':name', 'user5'); + $this->assertEquals('user5@example.com', $command->queryScalar()); + } +} diff --git a/tests/framework/db/mssql/MssqlConnectionTest.php b/tests/framework/db/mssql/MssqlConnectionTest.php new file mode 100644 index 0000000..02f7bfd --- /dev/null +++ b/tests/framework/db/mssql/MssqlConnectionTest.php @@ -0,0 +1,45 @@ +getConnection(false); + $this->assertEquals(123, $connection->quoteValue(123)); + $this->assertEquals("'string'", $connection->quoteValue('string')); + $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); + } + + public function testQuoteTableName() + { + $connection = $this->getConnection(false); + $this->assertEquals('[table]', $connection->quoteTableName('table')); + $this->assertEquals('[table]', $connection->quoteTableName('[table]')); + $this->assertEquals('[schema].[table]', $connection->quoteTableName('schema.table')); + $this->assertEquals('[schema].[table]', $connection->quoteTableName('schema.[table]')); + $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); + $this->assertEquals('(table)', $connection->quoteTableName('(table)')); + } + + public function testQuoteColumnName() + { + $connection = $this->getConnection(false); + $this->assertEquals('[column]', $connection->quoteColumnName('column')); + $this->assertEquals('[column]', $connection->quoteColumnName('[column]')); + $this->assertEquals('[table].[column]', $connection->quoteColumnName('table.column')); + $this->assertEquals('[table].[column]', $connection->quoteColumnName('table.[column]')); + $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); + $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); + $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); + } +} diff --git a/tests/framework/db/mssql/MssqlQueryBuilderTest.php b/tests/framework/db/mssql/MssqlQueryBuilderTest.php new file mode 100644 index 0000000..987d6a4 --- /dev/null +++ b/tests/framework/db/mssql/MssqlQueryBuilderTest.php @@ -0,0 +1,57 @@ +select('id')->from('example')->limit(10)->offset(5); + + list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query); + + $this->assertEquals($expectedQuerySql, $actualQuerySql); + $this->assertEquals($expectedQueryParams, $actualQueryParams); + } + + public function testLimit() + { + $expectedQuerySql = 'SELECT `id` FROM `exapmle` OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; + $expectedQueryParams = null; + + $query = new Query(); + $query->select('id')->from('example')->limit(10); + + list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query); + + $this->assertEquals($expectedQuerySql, $actualQuerySql); + $this->assertEquals($expectedQueryParams, $actualQueryParams); + } + + public function testOffset() + { + $expectedQuerySql = 'SELECT `id` FROM `exapmle` OFFSET 10 ROWS'; + $expectedQueryParams = null; + + $query = new Query(); + $query->select('id')->from('example')->offset(10); + + list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query); + + $this->assertEquals($expectedQuerySql, $actualQuerySql); + $this->assertEquals($expectedQueryParams, $actualQueryParams); + } +} diff --git a/tests/framework/db/mssql/MssqlQueryTest.php b/tests/framework/db/mssql/MssqlQueryTest.php new file mode 100644 index 0000000..89830d0 --- /dev/null +++ b/tests/framework/db/mssql/MssqlQueryTest.php @@ -0,0 +1,14 @@ +int_col = 123; + $model->int_col2 = 456; + $model->smallint_col = 42; + $model->char_col = '1337'; + $model->char_col2 = 'test'; + $model->char_col3 = 'test123'; + $model->float_col = 3.742; + $model->float_col2 = 42.1337; + $model->bool_col = 1; + $model->bool_col2 = 0; + $model->save(false); + + /* @var $model Type */ + $model = Type::find()->one(); + $this->assertSame(123, $model->int_col); + $this->assertSame(456, $model->int_col2); + $this->assertSame(42, $model->smallint_col); + $this->assertSame('1337', trim($model->char_col)); + $this->assertSame('test', $model->char_col2); + $this->assertSame('test123', $model->char_col3); +// $this->assertSame(1337.42, $model->float_col); +// $this->assertSame(42.1337, $model->float_col2); +// $this->assertSame(true, $model->bool_col); +// $this->assertSame(false, $model->bool_col2); + } + + public function testDefaultValues() + { + $model = new Type(); + $model->loadDefaultValues(); + $this->assertEquals(1, $model->int_col2); + $this->assertEquals('something', $model->char_col2); + $this->assertEquals(1.23, $model->float_col2); + $this->assertEquals(33.22, $model->numeric_col); + $this->assertEquals(true, $model->bool_col2); + + // not testing $model->time, because oci\Schema can't read default value + + $model = new Type(); + $model->char_col2 = 'not something'; + + $model->loadDefaultValues(); + $this->assertEquals('not something', $model->char_col2); + + $model = new Type(); + $model->char_col2 = 'not something'; + + $model->loadDefaultValues(false); + $this->assertEquals('something', $model->char_col2); + } + + public function testFindAsArray() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + // asArray + $customer = $customerClass::find()->where(['id' => 2])->asArray()->one(); + $this->assertEquals([ + 'id' => 2, + 'email' => 'user2@example.com', + 'name' => 'user2', + 'address' => 'address2', + 'status' => 1, + 'profile_id' => null, + 'bool_status' => true, + ], $customer); + + // find all asArray + $customers = $customerClass::find()->asArray()->all(); + $this->assertEquals(3, count($customers)); + $this->assertArrayHasKey('id', $customers[0]); + $this->assertArrayHasKey('name', $customers[0]); + $this->assertArrayHasKey('email', $customers[0]); + $this->assertArrayHasKey('address', $customers[0]); + $this->assertArrayHasKey('status', $customers[0]); + $this->assertArrayHasKey('bool_status', $customers[0]); + $this->assertArrayHasKey('id', $customers[1]); + $this->assertArrayHasKey('name', $customers[1]); + $this->assertArrayHasKey('email', $customers[1]); + $this->assertArrayHasKey('address', $customers[1]); + $this->assertArrayHasKey('status', $customers[1]); + $this->assertArrayHasKey('bool_status', $customers[1]); + $this->assertArrayHasKey('id', $customers[2]); + $this->assertArrayHasKey('name', $customers[2]); + $this->assertArrayHasKey('email', $customers[2]); + $this->assertArrayHasKey('address', $customers[2]); + $this->assertArrayHasKey('status', $customers[2]); + $this->assertArrayHasKey('bool_status', $customers[2]); + } +} diff --git a/tests/framework/db/oci/OracleCommandTest.php b/tests/framework/db/oci/OracleCommandTest.php new file mode 100644 index 0000000..aed38a3 --- /dev/null +++ b/tests/framework/db/oci/OracleCommandTest.php @@ -0,0 +1,22 @@ +getConnection(false); + + $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; + $command = $db->createCommand($sql); + $this->assertEquals('SELECT "id", "t"."name" FROM "customer" t', $command->sql); + } +} diff --git a/tests/framework/db/oci/OracleQueryTest.php b/tests/framework/db/oci/OracleQueryTest.php new file mode 100644 index 0000000..4c0e50f --- /dev/null +++ b/tests/framework/db/oci/OracleQueryTest.php @@ -0,0 +1,25 @@ +getConnection(); + + $result = (new Query)->from('customer')->where(['[[status]]' => 2])->one($db); + $this->assertEquals('user3', $result['name']); + + $result = (new Query)->from('customer')->where(['[[status]]' => 3])->one($db); + $this->assertFalse($result); + } +} diff --git a/tests/framework/db/oci/OracleSchemaTest.php b/tests/framework/db/oci/OracleSchemaTest.php new file mode 100644 index 0000000..747d06e --- /dev/null +++ b/tests/framework/db/oci/OracleSchemaTest.php @@ -0,0 +1,97 @@ +getConnection(false)->schema->getTableSchema('order', true); + $this->assertSame(false, $table->columns['id']->autoIncrement); + } +} diff --git a/tests/framework/db/pgsql/PostgreSQLActiveDataProviderTest.php b/tests/framework/db/pgsql/PostgreSQLActiveDataProviderTest.php new file mode 100644 index 0000000..081f680 --- /dev/null +++ b/tests/framework/db/pgsql/PostgreSQLActiveDataProviderTest.php @@ -0,0 +1,14 @@ +getCustomerClass(); + /* @var $this TestCase|ActiveRecordTestTrait */ + $customer = new $customerClass(); + $customer->name = 'boolean customer'; + $customer->email = 'mail@example.com'; + $customer->bool_status = false; + $customer->save(false); + + $customer->refresh(); + $this->assertSame(false, $customer->bool_status); + + $customer->bool_status = true; + $customer->save(false); + + $customer->refresh(); + $this->assertSame(true, $customer->bool_status); + + $customers = $customerClass::find()->where(['bool_status' => true])->all(); + $this->assertEquals(3, count($customers)); + + $customers = $customerClass::find()->where(['bool_status' => false])->all(); + $this->assertEquals(1, count($customers)); + } + + public function testFindAsArray() + { + /* @var $customerClass \yii\db\ActiveRecordInterface */ + $customerClass = $this->getCustomerClass(); + + // asArray + $customer = $customerClass::find()->where(['id' => 2])->asArray()->one(); + $this->assertEquals([ + 'id' => 2, + 'email' => 'user2@example.com', + 'name' => 'user2', + 'address' => 'address2', + 'status' => 1, + 'profile_id' => null, + 'bool_status' => true, + ], $customer); + + // find all asArray + $customers = $customerClass::find()->asArray()->all(); + $this->assertEquals(3, count($customers)); + $this->assertArrayHasKey('id', $customers[0]); + $this->assertArrayHasKey('name', $customers[0]); + $this->assertArrayHasKey('email', $customers[0]); + $this->assertArrayHasKey('address', $customers[0]); + $this->assertArrayHasKey('status', $customers[0]); + $this->assertArrayHasKey('bool_status', $customers[0]); + $this->assertArrayHasKey('id', $customers[1]); + $this->assertArrayHasKey('name', $customers[1]); + $this->assertArrayHasKey('email', $customers[1]); + $this->assertArrayHasKey('address', $customers[1]); + $this->assertArrayHasKey('status', $customers[1]); + $this->assertArrayHasKey('bool_status', $customers[1]); + $this->assertArrayHasKey('id', $customers[2]); + $this->assertArrayHasKey('name', $customers[2]); + $this->assertArrayHasKey('email', $customers[2]); + $this->assertArrayHasKey('address', $customers[2]); + $this->assertArrayHasKey('status', $customers[2]); + $this->assertArrayHasKey('bool_status', $customers[2]); + } + + public function testBooleanValues() + { + $db = $this->getConnection(); + $command = $db->createCommand(); + $command->batchInsert('bool_values', + ['bool_col'], [ + [true], + [false], + ] + )->execute(); + + $this->assertEquals(1, BoolAR::find()->where('bool_col = TRUE')->count('*', $db)); + $this->assertEquals(1, BoolAR::find()->where('bool_col = FALSE')->count('*', $db)); + $this->assertEquals(2, BoolAR::find()->where('bool_col IN (TRUE, FALSE)')->count('*', $db)); + + $this->assertEquals(1, BoolAR::find()->where(['bool_col' => true])->count('*', $db)); + $this->assertEquals(1, BoolAR::find()->where(['bool_col' => false])->count('*', $db)); + $this->assertEquals(2, BoolAR::find()->where(['bool_col' => [true, false]])->count('*', $db)); + + $this->assertEquals(1, BoolAR::find()->where('bool_col = :bool_col', ['bool_col' => true])->count('*', $db)); + $this->assertEquals(1, BoolAR::find()->where('bool_col = :bool_col', ['bool_col' => false])->count('*', $db)); + + $this->assertSame(true, BoolAR::find()->where(['bool_col' => true])->one($db)->bool_col); + $this->assertSame(false, BoolAR::find()->where(['bool_col' => false])->one($db)->bool_col); + } + + /** + * https://github.com/yiisoft/yii2/issues/4672 + */ + public function testBooleanValues2() + { + $db = $this->getConnection(); + $db->charset = 'utf8'; + + $db->createCommand("DROP TABLE IF EXISTS bool_user;")->execute(); + $db->createCommand()->createTable('bool_user', [ + 'id' => Schema::TYPE_PK, + 'username' => Schema::TYPE_STRING . ' NOT NULL', + 'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL', + 'password_hash' => Schema::TYPE_STRING . ' NOT NULL', + 'password_reset_token' => Schema::TYPE_STRING, + 'email' => Schema::TYPE_STRING . ' NOT NULL', + 'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10', + + 'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10', + 'created_at' => Schema::TYPE_INTEGER . ' NOT NULL', + 'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL', + ])->execute(); + $db->createCommand()->addColumn('bool_user', 'is_deleted', Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT FALSE')->execute(); + + $user = new UserAR(); + $user->username = 'test'; + $user->auth_key = 'test'; + $user->password_hash = 'test'; + $user->email = 'test@example.com'; + $user->save(false); + + $this->assertEquals(1, count(UserAR::find()->where(['is_deleted' => false])->all($db))); + $this->assertEquals(0, count(UserAR::find()->where(['is_deleted' => true])->all($db))); + $this->assertEquals(1, count(UserAR::find()->where(['is_deleted' => [true, false]])->all($db))); + } + + public function testBooleanDefaultValues() + { + $model = new BoolAR(); + $this->assertNull($model->bool_col); + $this->assertNull($model->default_true); + $this->assertNull($model->default_false); + $model->loadDefaultValues(); + $this->assertNull($model->bool_col); + $this->assertSame(true, $model->default_true); + $this->assertSame(false, $model->default_false); + + $this->assertTrue($model->save(false)); + } +} + +class BoolAR extends ActiveRecord +{ + public static function tableName() + { + return 'bool_values'; + } +} + +class UserAR extends ActiveRecord +{ + const STATUS_DELETED = 0; + const STATUS_ACTIVE = 10; + const ROLE_USER = 10; + + public static function tableName() + { + return '{{%bool_user}}'; + } + + public function behaviors() + { + return [ + TimestampBehavior::className(), + ]; + } +} + diff --git a/tests/framework/db/pgsql/PostgreSQLCommandTest.php b/tests/framework/db/pgsql/PostgreSQLCommandTest.php new file mode 100644 index 0000000..1382bd7 --- /dev/null +++ b/tests/framework/db/pgsql/PostgreSQLCommandTest.php @@ -0,0 +1,57 @@ +getConnection(false); + + $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; + $command = $db->createCommand($sql); + $this->assertEquals('SELECT "id", "t"."name" FROM "customer" t', $command->sql); + } + + public function testBooleanValuesInsert() + { + $db = $this->getConnection(); + $command = $db->createCommand(); + $command->insert('bool_values', ['bool_col' => true]); + $this->assertEquals(1, $command->execute()); + + $command = $db->createCommand(); + $command->insert('bool_values', ['bool_col' => false]); + $this->assertEquals(1, $command->execute()); + + $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = TRUE;'); + $this->assertEquals(1, $command->queryScalar()); + $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = FALSE;'); + $this->assertEquals(1, $command->queryScalar()); + } + + public function testBooleanValuesBatchInsert() + { + $db = $this->getConnection(); + $command = $db->createCommand(); + $command->batchInsert('bool_values', + ['bool_col'], [ + [true], + [false], + ] + ); + $this->assertEquals(2, $command->execute()); + + $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = TRUE;'); + $this->assertEquals(1, $command->queryScalar()); + $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = FALSE;'); + $this->assertEquals(1, $command->queryScalar()); + } +} \ No newline at end of file diff --git a/tests/framework/db/pgsql/PostgreSQLConnectionTest.php b/tests/framework/db/pgsql/PostgreSQLConnectionTest.php new file mode 100644 index 0000000..c569a44 --- /dev/null +++ b/tests/framework/db/pgsql/PostgreSQLConnectionTest.php @@ -0,0 +1,77 @@ +getConnection(true); + } + + public function testQuoteValue() + { + $connection = $this->getConnection(false); + $this->assertEquals(123, $connection->quoteValue(123)); + $this->assertEquals("'string'", $connection->quoteValue('string')); + $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); + } + + public function testQuoteTableName() + { + $connection = $this->getConnection(false); + $this->assertEquals('"table"', $connection->quoteTableName('table')); + $this->assertEquals('"table"', $connection->quoteTableName('"table"')); + $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema.table')); + $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema."table"')); + $this->assertEquals('"schema"."table"', $connection->quoteTableName('"schema"."table"')); + $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); + $this->assertEquals('(table)', $connection->quoteTableName('(table)')); + } + + public function testQuoteColumnName() + { + $connection = $this->getConnection(false); + $this->assertEquals('"column"', $connection->quoteColumnName('column')); + $this->assertEquals('"column"', $connection->quoteColumnName('"column"')); + $this->assertEquals('"table"."column"', $connection->quoteColumnName('table.column')); + $this->assertEquals('"table"."column"', $connection->quoteColumnName('table."column"')); + $this->assertEquals('"table"."column"', $connection->quoteColumnName('"table"."column"')); + $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); + $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); + $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); + } + + public function testTransactionIsolation() + { + $connection = $this->getConnection(true); + + $transaction = $connection->beginTransaction(); + $transaction->setIsolationLevel(Transaction::READ_UNCOMMITTED); + $transaction->commit(); + + $transaction = $connection->beginTransaction(); + $transaction->setIsolationLevel(Transaction::READ_COMMITTED); + $transaction->commit(); + + $transaction = $connection->beginTransaction(); + $transaction->setIsolationLevel(Transaction::REPEATABLE_READ); + $transaction->commit(); + + $transaction = $connection->beginTransaction(); + $transaction->setIsolationLevel(Transaction::SERIALIZABLE); + $transaction->commit(); + + $transaction = $connection->beginTransaction(); + $transaction->setIsolationLevel(Transaction::SERIALIZABLE . ' READ ONLY DEFERRABLE'); + $transaction->commit(); + } +} diff --git a/tests/framework/db/pgsql/PostgreSQLQueryBuilderTest.php b/tests/framework/db/pgsql/PostgreSQLQueryBuilderTest.php new file mode 100644 index 0000000..9dbc47b --- /dev/null +++ b/tests/framework/db/pgsql/PostgreSQLQueryBuilderTest.php @@ -0,0 +1,125 @@ + 5)', 'serial NOT NULL PRIMARY KEY CHECK (value > 5)'], + [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'serial NOT NULL PRIMARY KEY CHECK (value > 5)'], + [Schema::TYPE_STRING, 'varchar(255)'], + [Schema::TYPE_STRING . '(32)', 'varchar(32)'], + [Schema::TYPE_STRING . ' CHECK (value LIKE \'test%\')', 'varchar(255) CHECK (value LIKE \'test%\')'], + [Schema::TYPE_STRING . '(32) CHECK (value LIKE \'test%\')', 'varchar(32) CHECK (value LIKE \'test%\')'], + [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], + [Schema::TYPE_TEXT, 'text'], + [Schema::TYPE_TEXT . '(255)', 'text'], + [Schema::TYPE_TEXT . ' CHECK (value LIKE \'test%\')', 'text CHECK (value LIKE \'test%\')'], + [Schema::TYPE_TEXT . '(255) CHECK (value LIKE \'test%\')', 'text CHECK (value LIKE \'test%\')'], + [Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'], + [Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'], + [Schema::TYPE_SMALLINT, 'smallint'], + [Schema::TYPE_SMALLINT . '(8)', 'smallint'], + [Schema::TYPE_INTEGER, 'integer'], + [Schema::TYPE_INTEGER . '(8)', 'integer'], + [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'integer CHECK (value > 5)'], + [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'integer CHECK (value > 5)'], + [Schema::TYPE_INTEGER . ' NOT NULL', 'integer NOT NULL'], + [Schema::TYPE_BIGINT, 'bigint'], + [Schema::TYPE_BIGINT . '(8)', 'bigint'], + [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'], + [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'], + [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'], + [Schema::TYPE_FLOAT, 'double precision'], + [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'double precision CHECK (value > 5.6)'], + [Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'double precision CHECK (value > 5.6)'], + [Schema::TYPE_FLOAT . ' NOT NULL', 'double precision NOT NULL'], + [Schema::TYPE_DECIMAL, 'numeric(10,0)'], + [Schema::TYPE_DECIMAL . '(12,4)', 'numeric(12,4)'], + [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'numeric(10,0) CHECK (value > 5.6)'], + [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'numeric(12,4) CHECK (value > 5.6)'], + [Schema::TYPE_DECIMAL . ' NOT NULL', 'numeric(10,0) NOT NULL'], + [Schema::TYPE_DATETIME, 'timestamp(0)'], + [Schema::TYPE_DATETIME . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp(0) CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_DATETIME . ' NOT NULL', 'timestamp(0) NOT NULL'], + [Schema::TYPE_TIMESTAMP, 'timestamp(0)'], + [Schema::TYPE_TIMESTAMP . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp(0) CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp(0) NOT NULL'], + [Schema::TYPE_TIMESTAMP.'(4)', 'timestamp(4)'], + [Schema::TYPE_TIME, 'time(0)'], + [Schema::TYPE_TIME . " CHECK (value BETWEEN '12:00:00' AND '13:01:01')", "time(0) CHECK (value BETWEEN '12:00:00' AND '13:01:01')"], + [Schema::TYPE_TIME . ' NOT NULL', 'time(0) NOT NULL'], + [Schema::TYPE_DATE, 'date'], + [Schema::TYPE_DATE . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], + [Schema::TYPE_BINARY, 'bytea'], + [Schema::TYPE_BOOLEAN, 'boolean'], + [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT TRUE', 'boolean NOT NULL DEFAULT TRUE'], + [Schema::TYPE_MONEY, 'numeric(19,4)'], + [Schema::TYPE_MONEY . '(16,2)', 'numeric(16,2)'], + [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'numeric(19,4) CHECK (value > 0.0)'], + [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'numeric(16,2) CHECK (value > 0.0)'], + [Schema::TYPE_MONEY . ' NOT NULL', 'numeric(19,4) NOT NULL'], + ]; + } + + public function conditionProvider() + { + return array_merge(parent::conditionProvider(), [ + // adding conditions for ILIKE i.e. case insensitive LIKE + // http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE + + // empty values + [ ['ilike', 'name', []], '0=1', [] ], + [ ['not ilike', 'name', []], '', [] ], + [ ['or ilike', 'name', []], '0=1', [] ], + [ ['or not ilike', 'name', []], '', [] ], + + // simple ilike + [ ['ilike', 'name', 'heyho'], '"name" ILIKE :qp0', [':qp0' => '%heyho%'] ], + [ ['not ilike', 'name', 'heyho'], '"name" NOT ILIKE :qp0', [':qp0' => '%heyho%'] ], + [ ['or ilike', 'name', 'heyho'], '"name" ILIKE :qp0', [':qp0' => '%heyho%'] ], + [ ['or not ilike', 'name', 'heyho'], '"name" NOT ILIKE :qp0', [':qp0' => '%heyho%'] ], + + // ilike for many values + [ ['ilike', 'name', ['heyho', 'abc']], '"name" ILIKE :qp0 AND "name" ILIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], + [ ['not ilike', 'name', ['heyho', 'abc']], '"name" NOT ILIKE :qp0 AND "name" NOT ILIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], + [ ['or ilike', 'name', ['heyho', 'abc']], '"name" ILIKE :qp0 OR "name" ILIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], + [ ['or not ilike', 'name', ['heyho', 'abc']], '"name" NOT ILIKE :qp0 OR "name" NOT ILIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], + ]); + } + + public function testAlterColumn() + { + $qb = $this->getQueryBuilder(); + + $expected = 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255)'; + $sql = $qb->alterColumn('foo1', 'bar', 'varchar(255)'); + $this->assertEquals($expected, $sql); + + $expected = 'ALTER TABLE "foo1" ALTER COLUMN "bar" SET NOT null'; + $sql = $qb->alterColumn('foo1', 'bar', 'SET NOT null'); + $this->assertEquals($expected, $sql); + + $expected = 'ALTER TABLE "foo1" ALTER COLUMN "bar" drop default'; + $sql = $qb->alterColumn('foo1', 'bar', 'drop default'); + $this->assertEquals($expected, $sql); + + $expected = 'ALTER TABLE "foo1" ALTER COLUMN "bar" reset xyz'; + $sql = $qb->alterColumn('foo1', 'bar', 'reset xyz'); + $this->assertEquals($expected, $sql); + } +} diff --git a/tests/framework/db/pgsql/PostgreSQLQueryTest.php b/tests/framework/db/pgsql/PostgreSQLQueryTest.php new file mode 100644 index 0000000..af2c383 --- /dev/null +++ b/tests/framework/db/pgsql/PostgreSQLQueryTest.php @@ -0,0 +1,40 @@ +getConnection(); + $command = $db->createCommand(); + $command->batchInsert('bool_values', + ['bool_col'], [ + [true], + [false], + ] + )->execute(); + + $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = TRUE')->count('*', $db)); + $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = FALSE')->count('*', $db)); + $this->assertEquals(2, (new Query())->from('bool_values')->where('bool_col IN (TRUE, FALSE)')->count('*', $db)); + + $this->assertEquals(1, (new Query())->from('bool_values')->where(['bool_col' => true])->count('*', $db)); + $this->assertEquals(1, (new Query())->from('bool_values')->where(['bool_col' => false])->count('*', $db)); + $this->assertEquals(2, (new Query())->from('bool_values')->where(['bool_col' => [true, false]])->count('*', $db)); + + $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = :bool_col', ['bool_col' => true])->count('*', $db)); + $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = :bool_col', ['bool_col' => false])->count('*', $db)); + } +} diff --git a/tests/framework/db/pgsql/PostgreSQLSchemaTest.php b/tests/framework/db/pgsql/PostgreSQLSchemaTest.php new file mode 100644 index 0000000..7b8e9bb --- /dev/null +++ b/tests/framework/db/pgsql/PostgreSQLSchemaTest.php @@ -0,0 +1,109 @@ +getConnection()->schema; + + foreach ($values as $value) { + $this->assertEquals($value[1], $schema->getPdoType($value[0])); + } + fclose($fp); + } + + public function testBooleanDefaultValues() + { + /* @var $schema Schema */ + $schema = $this->getConnection()->schema; + + $table = $schema->getTableSchema('bool_values'); + $this->assertSame(true, $table->getColumn('default_true')->defaultValue); + $this->assertSame(false, $table->getColumn('default_false')->defaultValue); + } + + public function testFindSchemaNames() + { + $schema = $this->getConnection()->schema; + + $this->assertEquals(3, count($schema->getSchemaNames())); + } +} diff --git a/tests/framework/db/sqlite/SqliteActiveDataProviderTest.php b/tests/framework/db/sqlite/SqliteActiveDataProviderTest.php new file mode 100644 index 0000000..245bc88 --- /dev/null +++ b/tests/framework/db/sqlite/SqliteActiveDataProviderTest.php @@ -0,0 +1,14 @@ +getConnection(false); + + $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; + $command = $db->createCommand($sql); + $this->assertEquals("SELECT `id`, `t`.`name` FROM `customer` t", $command->sql); + } +} diff --git a/tests/framework/db/sqlite/SqliteConnectionTest.php b/tests/framework/db/sqlite/SqliteConnectionTest.php new file mode 100644 index 0000000..c36e5e6 --- /dev/null +++ b/tests/framework/db/sqlite/SqliteConnectionTest.php @@ -0,0 +1,145 @@ +getConnection(false); + $params = $this->database; + + $this->assertEquals($params['dsn'], $connection->dsn); + } + + public function testQuoteValue() + { + $connection = $this->getConnection(false); + $this->assertEquals(123, $connection->quoteValue(123)); + $this->assertEquals("'string'", $connection->quoteValue('string')); + $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); + } + + public function testQuoteTableName() + { + $connection = $this->getConnection(false); + $this->assertEquals("`table`", $connection->quoteTableName('table')); + $this->assertEquals("`schema`.`table`", $connection->quoteTableName('schema.table')); + $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); + $this->assertEquals('(table)', $connection->quoteTableName('(table)')); + } + + public function testQuoteColumnName() + { + $connection = $this->getConnection(false); + $this->assertEquals('`column`', $connection->quoteColumnName('column')); + $this->assertEquals("`table`.`column`", $connection->quoteColumnName('table.column')); + $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); + $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); + $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); + } + + public function testTransactionIsolation() + { + $connection = $this->getConnection(true); + + $transaction = $connection->beginTransaction(Transaction::READ_UNCOMMITTED); + $transaction->rollBack(); + + $transaction = $connection->beginTransaction(Transaction::SERIALIZABLE); + $transaction->rollBack(); + } + + public function testMasterSlave() + { + $counts = [[0, 2], [1, 2], [2, 2]]; + + foreach ($counts as $count) { + list($masterCount, $slaveCount) = $count; + + $db = $this->prepareMasterSlave($masterCount, $slaveCount); + + $this->assertTrue($db->getSlave() instanceof Connection); + $this->assertTrue($db->getSlave()->isActive); + $this->assertFalse($db->isActive); + + // test SELECT uses slave + $this->assertEquals(2, $db->createCommand('SELECT COUNT(*) FROM profile')->queryScalar()); + $this->assertFalse($db->isActive); + + // test UPDATE uses master + $db->createCommand("UPDATE profile SET description='test' WHERE id=1")->execute(); + $this->assertTrue($db->isActive); + $this->assertNotEquals('test', $db->createCommand("SELECT description FROM profile WHERE id=1")->queryScalar()); + $result = $db->useMaster(function (Connection $db) { + return $db->createCommand("SELECT description FROM profile WHERE id=1")->queryScalar(); + }); + $this->assertEquals('test', $result); + + // test ActiveRecord read/write split + ActiveRecord::$db = $db = $this->prepareMasterSlave($masterCount, $slaveCount); + $this->assertFalse($db->isActive); + + $customer = Customer::findOne(1); + $this->assertTrue($customer instanceof Customer); + $this->assertEquals('user1', $customer->name); + $this->assertFalse($db->isActive); + + $customer->name = 'test'; + $customer->save(); + $this->assertTrue($db->isActive); + $customer = Customer::findOne(1); + $this->assertTrue($customer instanceof Customer); + $this->assertEquals('user1', $customer->name); + $result = $db->useMaster(function () { + return Customer::findOne(1)->name; + }); + $this->assertEquals('test', $result); + } + } + + /** + * @param integer $masterCount + * @param integer $slaveCount + * @return Connection + */ + protected function prepareMasterSlave($masterCount, $slaveCount) + { + $databases = self::getParam('databases'); + $fixture = $databases[$this->driverName]['fixture']; + $basePath = \Yii::getAlias('@yiiunit/runtime'); + + $config = [ + 'class' => 'yii\db\Connection', + 'dsn' => "sqlite:$basePath/yii2test.sq3", + ]; + $this->prepareDatabase($config, $fixture)->close(); + + for ($i = 0; $i < $masterCount; ++$i) { + $master = ['dsn' => "sqlite:$basePath/yii2test_master{$i}.sq3"]; + $db = $this->prepareDatabase($master, $fixture); + $db->close(); + $config['masters'][] = $master; + } + + for ($i = 0; $i < $slaveCount; ++$i) { + $slave = ['dsn' => "sqlite:$basePath/yii2test_slave{$i}.sq3"]; + $db = $this->prepareDatabase($slave, $fixture); + $db->close(); + $config['slaves'][] = $slave; + } + + return \Yii::createObject($config); + } +} diff --git a/tests/framework/db/sqlite/SqliteQueryBuilderTest.php b/tests/framework/db/sqlite/SqliteQueryBuilderTest.php new file mode 100644 index 0000000..34ab18a --- /dev/null +++ b/tests/framework/db/sqlite/SqliteQueryBuilderTest.php @@ -0,0 +1,94 @@ + 5)', 'integer PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (value > 5)'], + [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'integer PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (value > 5)'], + [Schema::TYPE_STRING, 'varchar(255)'], + [Schema::TYPE_STRING . '(32)', 'varchar(32)'], + [Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'], + [Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'], + [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], + [Schema::TYPE_TEXT, 'text'], + [Schema::TYPE_TEXT . '(255)', 'text'], + [Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], + [Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], + [Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'], + [Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'], + [Schema::TYPE_SMALLINT, 'smallint'], + [Schema::TYPE_SMALLINT . '(8)', 'smallint'], + [Schema::TYPE_INTEGER, 'integer'], + [Schema::TYPE_INTEGER . '(8)', 'integer'], + [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'integer CHECK (value > 5)'], + [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'integer CHECK (value > 5)'], + [Schema::TYPE_INTEGER . ' NOT NULL', 'integer NOT NULL'], + [Schema::TYPE_BIGINT, 'bigint'], + [Schema::TYPE_BIGINT . '(8)', 'bigint'], + [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'], + [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'], + [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'], + [Schema::TYPE_FLOAT, 'float'], + [Schema::TYPE_FLOAT . '(16,5)', 'float'], + [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], + [Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], + [Schema::TYPE_FLOAT . ' NOT NULL', 'float NOT NULL'], + [Schema::TYPE_DECIMAL, 'decimal(10,0)'], + [Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'], + [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'], + [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'], + [Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'], + [Schema::TYPE_DATETIME, 'datetime'], + [Schema::TYPE_DATETIME . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'], + [Schema::TYPE_TIMESTAMP, 'timestamp'], + [Schema::TYPE_TIMESTAMP . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'], + [Schema::TYPE_TIME, 'time'], + [Schema::TYPE_TIME . " CHECK (value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK (value BETWEEN '12:00:00' AND '13:01:01')"], + [Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'], + [Schema::TYPE_DATE, 'date'], + [Schema::TYPE_DATE . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], + [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], + [Schema::TYPE_BINARY, 'blob'], + [Schema::TYPE_BOOLEAN, 'boolean'], + [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'boolean NOT NULL DEFAULT 1'], + [Schema::TYPE_MONEY, 'decimal(19,4)'], + [Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'], + [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'], + [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'], + [Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'], + ]; + } + + public function testAddDropPrimaryKey() + { + $this->setExpectedException('yii\base\NotSupportedException'); + parent::testAddDropPrimaryKey(); + } + + public function testBatchInsert() + { + $db = $this->getConnection(); + if (version_compare($db->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '3.7.11', '>=')) { + $this->markTestSkipped('This test is only relevant for SQLite < 3.7.11'); + } + $sql = $this->getQueryBuilder()->batchInsert('{{customer}} t', ['t.id', 't.name'], [[1, 'a'], [2, 'b']]); + $this->assertEquals("INSERT INTO {{customer}} t (`t`.`id`, `t`.`name`) SELECT 1, 'a' UNION SELECT 2, 'b'", $sql); + } +} diff --git a/tests/framework/db/sqlite/SqliteQueryTest.php b/tests/framework/db/sqlite/SqliteQueryTest.php new file mode 100644 index 0000000..5c85077 --- /dev/null +++ b/tests/framework/db/sqlite/SqliteQueryTest.php @@ -0,0 +1,13 @@ + + * @since 2.0 + */ +class ContainerTest extends TestCase +{ + public function testDefault() + { + $namespace = __NAMESPACE__ . '\stubs'; + $QuxInterface = "$namespace\\QuxInterface"; + $Foo = Foo::className(); + $Bar = Bar::className(); + $Qux = Qux::className(); + + // automatic wiring + $container = new Container; + $container->set($QuxInterface, $Qux); + $foo = $container->get($Foo); + $this->assertTrue($foo instanceof $Foo); + $this->assertTrue($foo->bar instanceof $Bar); + $this->assertTrue($foo->bar->qux instanceof $Qux); + $foo2 = $container->get($Foo); + $this->assertFalse($foo === $foo2); + + // full wiring + $container = new Container; + $container->set($QuxInterface, $Qux); + $container->set($Bar); + $container->set($Qux); + $container->set($Foo); + $foo = $container->get($Foo); + $this->assertTrue($foo instanceof $Foo); + $this->assertTrue($foo->bar instanceof $Bar); + $this->assertTrue($foo->bar->qux instanceof $Qux); + + // wiring by closure + $container = new Container; + $container->set('foo', function () { + $qux = new Qux; + $bar = new Bar($qux); + return new Foo($bar); + }); + $foo = $container->get('foo'); + $this->assertTrue($foo instanceof $Foo); + $this->assertTrue($foo->bar instanceof $Bar); + $this->assertTrue($foo->bar->qux instanceof $Qux); + + // wiring by closure which uses container + $container = new Container; + $container->set($QuxInterface, $Qux); + $container->set('foo', function (Container $c, $params, $config) { + return $c->get(Foo::className()); + }); + $foo = $container->get('foo'); + $this->assertTrue($foo instanceof $Foo); + $this->assertTrue($foo->bar instanceof $Bar); + $this->assertTrue($foo->bar->qux instanceof $Qux); + + // predefined constructor parameters + $container = new Container; + $container->set('foo', $Foo, [Instance::of('bar')]); + $container->set('bar', $Bar, [Instance::of('qux')]); + $container->set('qux', $Qux); + $foo = $container->get('foo'); + $this->assertTrue($foo instanceof $Foo); + $this->assertTrue($foo->bar instanceof $Bar); + $this->assertTrue($foo->bar->qux instanceof $Qux); + + // wiring by closure + $container = new Container; + $container->set('qux', new Qux); + $qux1 = $container->get('qux'); + $qux2 = $container->get('qux'); + $this->assertTrue($qux1 === $qux2); + + // config + $container = new Container; + $container->set('qux', $Qux); + $qux = $container->get('qux', [], ['a' => 2]); + $this->assertEquals(2, $qux->a); + $qux = $container->get('qux', [3]); + $this->assertEquals(3, $qux->a); + $qux = $container->get('qux', [3, ['a' => 4]]); + $this->assertEquals(4, $qux->a); + } +} diff --git a/tests/framework/di/InstanceTest.php b/tests/framework/di/InstanceTest.php new file mode 100644 index 0000000..70f7970 --- /dev/null +++ b/tests/framework/di/InstanceTest.php @@ -0,0 +1,49 @@ + + * @since 2.0 + */ +class InstanceTest extends TestCase +{ + public function testOf() + { + $container = new Container; + $className = Component::className(); + $instance = Instance::of($className); + + $this->assertTrue($instance instanceof Instance); + $this->assertTrue($instance->get($container) instanceof Component); + $this->assertTrue(Instance::ensure($instance, $className, $container) instanceof Component); + $this->assertTrue($instance->get($container) !== Instance::ensure($instance, $className, $container)); + } + + public function testEnsure() + { + $container = new Container; + $container->set('db', [ + 'class' => 'yii\db\Connection', + 'dsn' => 'test', + ]); + + $this->assertTrue(Instance::ensure('db', 'yii\db\Connection', $container) instanceof Connection); + $this->assertTrue(Instance::ensure(new Connection, 'yii\db\Connection', $container) instanceof Connection); + $this->assertTrue(Instance::ensure([ + 'class' => 'yii\db\Connection', + 'dsn' => 'test', + ], 'yii\db\Connection', $container) instanceof Connection); + } +} diff --git a/tests/framework/di/ServiceLocatorTest.php b/tests/framework/di/ServiceLocatorTest.php new file mode 100644 index 0000000..66139bd --- /dev/null +++ b/tests/framework/di/ServiceLocatorTest.php @@ -0,0 +1,88 @@ + + * @since 2.0 + */ +class ServiceLocatorTest extends TestCase +{ + public function testCallable() + { + // anonymous function + $container = new ServiceLocator; + $className = TestClass::className(); + $container->set($className, function () { + return new TestClass([ + 'prop1' => 100, + 'prop2' => 200, + ]); + }); + $object = $container->get($className); + $this->assertTrue($object instanceof $className); + $this->assertEquals(100, $object->prop1); + $this->assertEquals(200, $object->prop2); + + // static method + $container = new ServiceLocator; + $className = TestClass::className(); + $container->set($className, [__NAMESPACE__ . "\\Creator", 'create']); + $object = $container->get($className); + $this->assertTrue($object instanceof $className); + $this->assertEquals(1, $object->prop1); + $this->assertNull($object->prop2); + } + + public function testObject() + { + $object = new TestClass; + $className = TestClass::className(); + $container = new ServiceLocator; + $container->set($className, $object); + $this->assertTrue($container->get($className) === $object); + } + + public function testShared() + { + // with configuration: shared + $container = new ServiceLocator; + $className = TestClass::className(); + $container->set($className, [ + 'class' => $className, + 'prop1' => 10, + 'prop2' => 20, + ]); + $object = $container->get($className); + $this->assertEquals(10, $object->prop1); + $this->assertEquals(20, $object->prop2); + $this->assertTrue($object instanceof $className); + // check shared + $object2 = $container->get($className); + $this->assertTrue($object2 instanceof $className); + $this->assertTrue($object === $object2); + } +} diff --git a/tests/framework/di/stubs/Bar.php b/tests/framework/di/stubs/Bar.php new file mode 100644 index 0000000..d0bc788 --- /dev/null +++ b/tests/framework/di/stubs/Bar.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +class Bar extends Object +{ + public $qux; + + public function __construct(QuxInterface $qux, $config = []) + { + $this->qux = $qux; + parent::__construct($config); + } +} diff --git a/tests/framework/di/stubs/Foo.php b/tests/framework/di/stubs/Foo.php new file mode 100644 index 0000000..75a5612 --- /dev/null +++ b/tests/framework/di/stubs/Foo.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +class Foo extends Object +{ + public $bar; + + public function __construct(Bar $bar, $config = []) + { + $this->bar = $bar; + parent::__construct($config); + } +} diff --git a/tests/framework/di/stubs/Qux.php b/tests/framework/di/stubs/Qux.php new file mode 100644 index 0000000..4b44866 --- /dev/null +++ b/tests/framework/di/stubs/Qux.php @@ -0,0 +1,29 @@ + + * @since 2.0 + */ +class Qux extends Object implements QuxInterface +{ + public $a; + + public function __construct($a = 1, $config = []) + { + $this->a = $a; + parent::__construct($config); + } + + public function quxMethod() + { + } +} diff --git a/tests/framework/di/stubs/QuxInterface.php b/tests/framework/di/stubs/QuxInterface.php new file mode 100644 index 0000000..8a98471 --- /dev/null +++ b/tests/framework/di/stubs/QuxInterface.php @@ -0,0 +1,17 @@ + + * @since 2.0 + */ +interface QuxInterface +{ + function quxMethod(); +} diff --git a/tests/framework/filters/CompositeAuthTest.php b/tests/framework/filters/CompositeAuthTest.php new file mode 100644 index 0000000..0092d2c --- /dev/null +++ b/tests/framework/filters/CompositeAuthTest.php @@ -0,0 +1,121 @@ + + */ +class TestAuth extends AuthMethod +{ + public function authenticate($user, $request, $response) + { + return $user; + } +} + +class TestController extends Controller +{ + public function actionA() + { + return 'success'; + } + + public function actionB() + { + /** + * this call will execute the actionA in a same instance of TestController + */ + return $this->runAction('a'); + } + + public function actionC() + { + /** + * this call will execute the actionA in a same instance of TestController + */ + return $this->run('a'); + } + + public function actionD() + { + /** + * this call will execute the actionA in a new instance of TestController + */ + return $this->run('test/a'); + } + + public function behaviors() + { + /** + * the CompositeAuth::authenticate() assumes that it is only executed once per the controller's instance + * i believe this is okay as long as we specify in the documentation that if we want to use the authenticate + * method again(this might even be also true to other behaviors that attaches to the beforeAction event), + * that we will have to forward/run into the other action in a way that it will create a new controller instance + */ + return [ + 'authenticator' => [ + 'class' => CompositeAuth::className(), + 'authMethods' => [ + TestAuth::className() + ] + ], + ]; + } +} + +/** + * @group filters + */ +class CompositeAuthTest extends \yiiunit\TestCase +{ + protected function setUp() + { + parent::setUp(); + + $_SERVER['SCRIPT_FILENAME'] = "/index.php"; + $_SERVER['SCRIPT_NAME'] = "/index.php"; + + $appConfig = [ + 'components' => [ + 'user' => [ + 'identityClass' => UserIdentity::className() + ], + ], + 'controllerMap' => [ + 'test' => TestController::className() + ] + ]; + + $this->mockWebApplication($appConfig); + } + + public function testCallingRunWithCompleteRoute() + { + /** @var TestController $controller */ + $controller = Yii::$app->createController('test')[0]; + $this->assertEquals('success', $controller->run('test/d')); + } + + /** + * reproducing the issue specified in https://github.com/yiisoft/yii2/issues/7409 + */ + public function testRunAction() + { + /** @var TestController $controller */ + $controller = Yii::$app->createController('test')[0]; + $this->assertEquals('success', $controller->run('b')); + } + + public function testRunButWithActionIdOnly() + { + /** @var TestController $controller */ + $controller = Yii::$app->createController('test')[0]; + $this->assertEquals('success', $controller->run('c')); + } +} diff --git a/tests/framework/filters/HttpCacheTest.php b/tests/framework/filters/HttpCacheTest.php new file mode 100644 index 0000000..ca5d932 --- /dev/null +++ b/tests/framework/filters/HttpCacheTest.php @@ -0,0 +1,79 @@ +mockWebApplication(); + } + + public function testDisabled() + { + $httpCache = new HttpCache; + $this->assertTrue($httpCache->beforeAction(null)); + $httpCache->enabled=false; + $this->assertTrue($httpCache->beforeAction(null)); + } + + /** + * @covers yii\filters\HttpCache::validateCache + */ + public function testValidateCache() + { + $httpCache = new HttpCache; + $method = new \ReflectionMethod($httpCache, 'validateCache'); + $method->setAccessible(true); + + unset($_SERVER['HTTP_IF_MODIFIED_SINCE'], $_SERVER['HTTP_IF_NONE_MATCH']); + $this->assertTrue($method->invoke($httpCache, null, null)); + $this->assertFalse($method->invoke($httpCache, 0, null)); + $this->assertFalse($method->invoke($httpCache, 0, '"foo"')); + + $_SERVER['HTTP_IF_MODIFIED_SINCE'] = 'Thu, 01 Jan 1970 00:00:00 GMT'; + $this->assertTrue($method->invoke($httpCache, 0, null)); + $this->assertFalse($method->invoke($httpCache, 1, null)); + + $_SERVER['HTTP_IF_NONE_MATCH'] = '"foo"'; + $this->assertTrue($method->invoke($httpCache, 0, '"foo"')); + $this->assertFalse($method->invoke($httpCache, 0, '"foos"')); + $this->assertTrue($method->invoke($httpCache, 1, '"foo"')); + $this->assertFalse($method->invoke($httpCache, 1, '"foos"')); + $this->assertFalse($method->invoke($httpCache, null, null)); + + $_SERVER['HTTP_IF_NONE_MATCH'] = '*'; + $this->assertFalse($method->invoke($httpCache, 0, '"foo"')); + $this->assertFalse($method->invoke($httpCache, 0, null)); + } + + /** + * @covers yii\filters\HttpCache::generateEtag + */ + public function testGenerateEtag() + { + $httpCache = new HttpCache; + $httpCache->etagSeed = function($action, $params) { + return ''; + }; + $httpCache->beforeAction(null); + $response = Yii::$app->getResponse(); + + $this->assertTrue($response->getHeaders()->offsetExists('ETag')); + + $etag = $response->getHeaders()->get('ETag'); + $this->assertStringStartsWith('"', $etag); + $this->assertStringEndsWith('"', $etag); + } +} diff --git a/tests/framework/helpers/ArrayHelperTest.php b/tests/framework/helpers/ArrayHelperTest.php new file mode 100644 index 0000000..97592aa --- /dev/null +++ b/tests/framework/helpers/ArrayHelperTest.php @@ -0,0 +1,467 @@ +secret; + } +} + +class Post3 extends Object +{ + public $id = 33; + public $subObject; + + public function init() + { + $this->subObject = new Post2(); + } +} + +/** + * @group helpers + */ +class ArrayHelperTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + + public function testToArray() + { + $object = new Post1; + $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object)); + $object = new Post2; + $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object)); + + $object1 = new Post1; + $object2 = new Post2; + $this->assertEquals([ + get_object_vars($object1), + get_object_vars($object2), + ], ArrayHelper::toArray([ + $object1, + $object2, + ])); + + $object = new Post2; + $this->assertEquals([ + 'id' => 123, + 'secret' => 's', + '_content' => 'test', + 'length' => 4, + ], ArrayHelper::toArray($object, [ + $object->className() => [ + 'id', 'secret', + '_content' => 'content', + 'length' => function ($post) { + return strlen($post->content); + } + ] + ])); + + $object = new Post3(); + $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object, [], false)); + $this->assertEquals([ + 'id' => 33, + 'subObject' => [ + 'id' => 123, + 'content' => 'test', + ], + ], ArrayHelper::toArray($object)); + } + + public function testRemove() + { + $array = ['name' => 'b', 'age' => 3]; + $name = ArrayHelper::remove($array, 'name'); + + $this->assertEquals($name, 'b'); + $this->assertEquals($array, ['age' => 3]); + + $default = ArrayHelper::remove($array, 'nonExisting', 'defaultValue'); + $this->assertEquals('defaultValue', $default); + } + + public function testMultisort() + { + // single key + $array = [ + ['name' => 'b', 'age' => 3], + ['name' => 'a', 'age' => 1], + ['name' => 'c', 'age' => 2], + ]; + ArrayHelper::multisort($array, 'name'); + $this->assertEquals(['name' => 'a', 'age' => 1], $array[0]); + $this->assertEquals(['name' => 'b', 'age' => 3], $array[1]); + $this->assertEquals(['name' => 'c', 'age' => 2], $array[2]); + + // multiple keys + $array = [ + ['name' => 'b', 'age' => 3], + ['name' => 'a', 'age' => 2], + ['name' => 'a', 'age' => 1], + ]; + ArrayHelper::multisort($array, ['name', 'age']); + $this->assertEquals(['name' => 'a', 'age' => 1], $array[0]); + $this->assertEquals(['name' => 'a', 'age' => 2], $array[1]); + $this->assertEquals(['name' => 'b', 'age' => 3], $array[2]); + + // case-insensitive + $array = [ + ['name' => 'a', 'age' => 3], + ['name' => 'b', 'age' => 2], + ['name' => 'B', 'age' => 4], + ['name' => 'A', 'age' => 1], + ]; + + ArrayHelper::multisort($array, ['name', 'age'], SORT_ASC, [SORT_STRING, SORT_REGULAR]); + $this->assertEquals(['name' => 'A', 'age' => 1], $array[0]); + $this->assertEquals(['name' => 'B', 'age' => 4], $array[1]); + $this->assertEquals(['name' => 'a', 'age' => 3], $array[2]); + $this->assertEquals(['name' => 'b', 'age' => 2], $array[3]); + + ArrayHelper::multisort($array, ['name', 'age'], SORT_ASC, [SORT_STRING | SORT_FLAG_CASE, SORT_REGULAR]); + $this->assertEquals(['name' => 'A', 'age' => 1], $array[0]); + $this->assertEquals(['name' => 'a', 'age' => 3], $array[1]); + $this->assertEquals(['name' => 'b', 'age' => 2], $array[2]); + $this->assertEquals(['name' => 'B', 'age' => 4], $array[3]); + } + + public function testMultisortUseSort() + { + // single key + $sort = new Sort([ + 'attributes' => ['name', 'age'], + 'defaultOrder' => ['name' => SORT_ASC], + ]); + $orders = $sort->getOrders(); + + $array = [ + ['name' => 'b', 'age' => 3], + ['name' => 'a', 'age' => 1], + ['name' => 'c', 'age' => 2], + ]; + ArrayHelper::multisort($array, array_keys($orders), array_values($orders)); + $this->assertEquals(['name' => 'a', 'age' => 1], $array[0]); + $this->assertEquals(['name' => 'b', 'age' => 3], $array[1]); + $this->assertEquals(['name' => 'c', 'age' => 2], $array[2]); + + // multiple keys + $sort = new Sort([ + 'attributes' => ['name', 'age'], + 'defaultOrder' => ['name' => SORT_ASC, 'age' => SORT_DESC], + ]); + $orders = $sort->getOrders(); + + $array = [ + ['name' => 'b', 'age' => 3], + ['name' => 'a', 'age' => 2], + ['name' => 'a', 'age' => 1], + ]; + ArrayHelper::multisort($array, array_keys($orders), array_values($orders)); + $this->assertEquals(['name' => 'a', 'age' => 2], $array[0]); + $this->assertEquals(['name' => 'a', 'age' => 1], $array[1]); + $this->assertEquals(['name' => 'b', 'age' => 3], $array[2]); + } + + public function testMerge() + { + $a = [ + 'name' => 'Yii', + 'version' => '1.0', + 'options' => [ + 'namespace' => false, + 'unittest' => false, + ], + 'features' => [ + 'mvc', + ], + ]; + $b = [ + 'version' => '1.1', + 'options' => [ + 'unittest' => true, + ], + 'features' => [ + 'gii', + ], + ]; + $c = [ + 'version' => '2.0', + 'options' => [ + 'namespace' => true, + ], + 'features' => [ + 'debug', + ], + ]; + + $result = ArrayHelper::merge($a, $b, $c); + $expected = [ + 'name' => 'Yii', + 'version' => '2.0', + 'options' => [ + 'namespace' => true, + 'unittest' => true, + ], + 'features' => [ + 'mvc', + 'gii', + 'debug', + ], + ]; + + $this->assertEquals($expected, $result); + } + + public function testIndex() + { + $array = [ + ['id' => '123', 'data' => 'abc'], + ['id' => '345', 'data' => 'def'], + ]; + $result = ArrayHelper::index($array, 'id'); + $this->assertEquals([ + '123' => ['id' => '123', 'data' => 'abc'], + '345' => ['id' => '345', 'data' => 'def'], + ], $result); + + $result = ArrayHelper::index($array, function ($element) { + return $element['data']; + }); + $this->assertEquals([ + 'abc' => ['id' => '123', 'data' => 'abc'], + 'def' => ['id' => '345', 'data' => 'def'], + ], $result); + } + + public function testGetColumn() + { + $array = [ + 'a' => ['id' => '123', 'data' => 'abc'], + 'b' => ['id' => '345', 'data' => 'def'], + ]; + $result = ArrayHelper::getColumn($array, 'id'); + $this->assertEquals(['a' => '123', 'b' => '345'], $result); + $result = ArrayHelper::getColumn($array, 'id', false); + $this->assertEquals(['123', '345'], $result); + + $result = ArrayHelper::getColumn($array, function ($element) { + return $element['data']; + }); + $this->assertEquals(['a' => 'abc', 'b' => 'def'], $result); + $result = ArrayHelper::getColumn($array, function ($element) { + return $element['data']; + }, false); + $this->assertEquals(['abc', 'def'], $result); + } + + public function testMap() + { + $array = [ + ['id' => '123', 'name' => 'aaa', 'class' => 'x'], + ['id' => '124', 'name' => 'bbb', 'class' => 'x'], + ['id' => '345', 'name' => 'ccc', 'class' => 'y'], + ]; + + $result = ArrayHelper::map($array, 'id', 'name'); + $this->assertEquals([ + '123' => 'aaa', + '124' => 'bbb', + '345' => 'ccc', + ], $result); + + $result = ArrayHelper::map($array, 'id', 'name', 'class'); + $this->assertEquals([ + 'x' => [ + '123' => 'aaa', + '124' => 'bbb', + ], + 'y' => [ + '345' => 'ccc', + ], + ], $result); + } + + public function testKeyExists() + { + $array = [ + 'a' => 1, + 'B' => 2, + ]; + $this->assertTrue(ArrayHelper::keyExists('a', $array)); + $this->assertFalse(ArrayHelper::keyExists('b', $array)); + $this->assertTrue(ArrayHelper::keyExists('B', $array)); + $this->assertFalse(ArrayHelper::keyExists('c', $array)); + + $this->assertTrue(ArrayHelper::keyExists('a', $array, false)); + $this->assertTrue(ArrayHelper::keyExists('b', $array, false)); + $this->assertTrue(ArrayHelper::keyExists('B', $array, false)); + $this->assertFalse(ArrayHelper::keyExists('c', $array, false)); + } + + public function valueProvider() + { + return [ + ['name', 'test'], + ['noname', null], + ['noname', 'test', 'test'], + ['post.id', 5], + ['post.id', 5, 'test'], + ['nopost.id', null], + ['nopost.id', 'test', 'test'], + ['post.author.name', 'cebe'], + ['post.author.noname', null], + ['post.author.noname', 'test', 'test'], + ['post.author.profile.title', '1337'], + ['admin.firstname', 'Qiang'], + ['admin.firstname', 'Qiang', 'test'], + ['admin.lastname', 'Xue'], + [ + function ($array, $defaultValue) { + return $array['date'] . $defaultValue; + }, + '31-12-2113test', + 'test' + ], + ]; + } + + /** + * @dataProvider valueProvider + * + * @param $key + * @param $expected + * @param null $default + */ + public function testGetValue($key, $expected, $default = null) + { + $array = [ + 'name' => 'test', + 'date' => '31-12-2113', + 'post' => [ + 'id' => 5, + 'author' => [ + 'name' => 'cebe', + 'profile' => [ + 'title' => '1337', + ], + ], + ], + 'admin.firstname' => 'Qiang', + 'admin.lastname' => 'Xue', + 'admin' => [ + 'lastname' => 'cebe', + ], + ]; + + $this->assertEquals($expected, ArrayHelper::getValue($array, $key, $default)); + } + + public function testIsAssociative() + { + $this->assertFalse(ArrayHelper::isAssociative('test')); + $this->assertFalse(ArrayHelper::isAssociative([])); + $this->assertFalse(ArrayHelper::isAssociative([1, 2, 3])); + $this->assertTrue(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test'])); + $this->assertFalse(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test', 3])); + $this->assertTrue(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test', 3], false)); + } + + public function testIsIndexed() + { + $this->assertFalse(ArrayHelper::isIndexed('test')); + $this->assertTrue(ArrayHelper::isIndexed([])); + $this->assertTrue(ArrayHelper::isIndexed([1, 2, 3])); + $this->assertTrue(ArrayHelper::isIndexed([2 => 'a', 3 => 'b'])); + $this->assertFalse(ArrayHelper::isIndexed([2 => 'a', 3 => 'b'], true)); + } + + public function testHtmlEncode() + { + $array = [ + 'abc' => '123', + '<' => '>', + 'cde' => false, + 3 => 'blank', + [ + '<>' => 'a<>b', + '23' => true, + ] + ]; + $this->assertEquals([ + 'abc' => '123', + '<' => '>', + 'cde' => false, + 3 => 'blank', + [ + '<>' => 'a<>b', + '23' => true, + ] + ], ArrayHelper::htmlEncode($array)); + $this->assertEquals([ + 'abc' => '123', + '<' => '>', + 'cde' => false, + 3 => 'blank', + [ + '<>' => 'a<>b', + '23' => true, + ] + ], ArrayHelper::htmlEncode($array, false)); + } + + public function testHtmlDecode() + { + $array = [ + 'abc' => '123', + '<' => '>', + 'cde' => false, + 3 => 'blank', + [ + '<>' => 'a<>b', + '23' => true, + ] + ]; + $this->assertEquals([ + 'abc' => '123', + '<' => '>', + 'cde' => false, + 3 => 'blank', + [ + '<>' => 'a<>b', + '23' => true, + ] + ], ArrayHelper::htmlDecode($array)); + $this->assertEquals([ + 'abc' => '123', + '<' => '>', + 'cde' => false, + 3 => 'blank', + [ + '<>' => 'a<>b', + '23' => true, + ] + ], ArrayHelper::htmlDecode($array, false)); + } +} diff --git a/tests/framework/helpers/ConsoleTest.php b/tests/framework/helpers/ConsoleTest.php new file mode 100644 index 0000000..70344df --- /dev/null +++ b/tests/framework/helpers/ConsoleTest.php @@ -0,0 +1,132 @@ +assertEquals(str_repeat('a', 25), $output); + } + +/* public function testScreenSize() + { + for ($i = 1; $i < 20; $i++) { + echo implode(', ', Console::getScreenSize(true)) . "\n"; + ob_flush(); + sleep(1); + } + }*/ + + public function ansiFormats() + { + return [ + ['test', 'test'], + [Console::ansiFormat('test', [Console::FG_RED]), 'test'], + ['abc' . Console::ansiFormat('def', [Console::FG_RED]) . 'ghj', 'abcdefghj'], + ['abc' . Console::ansiFormat('def', [Console::FG_RED, Console::BG_GREEN]) . 'ghj', 'abcdefghj'], + ['abc' . Console::ansiFormat('def', [Console::FG_GREEN, Console::FG_RED, Console::BG_GREEN]) . 'ghj', 'abcdefghj'], + ['abc' . Console::ansiFormat('def', [Console::BOLD, Console::BG_GREEN]) . 'ghj', 'abcdefghj'], + + [ + Console::ansiFormat('test', [Console::UNDERLINE, Console::OVERLINED, Console::CROSSED_OUT, Console::FG_GREEN]), + 'test' + ], + + [Console::ansiFormatCode([Console::RESET]) . Console::ansiFormatCode([Console::RESET]), ''], + [Console::ansiFormatCode([Console::RESET]) . Console::ansiFormatCode([Console::RESET]) . 'test', 'test'], + [Console::ansiFormatCode([Console::RESET]) . 'test' . Console::ansiFormatCode([Console::RESET]), 'test'], + + [ + Console::ansiFormatCode([Console::BOLD]) . 'abc' . Console::ansiFormatCode([Console::RESET, Console::FG_GREEN]) . 'ghj' . Console::ansiFormatCode([Console::RESET]), + 'abcghj' + ], + [ + Console::ansiFormatCode([Console::FG_GREEN]) . ' a ' . Console::ansiFormatCode([Console::BOLD]) . 'abc' . Console::ansiFormatCode([Console::RESET]) . 'ghj', + ' a abcghj' + ], + [ + Console::ansiFormat('test', [Console::FG_GREEN, Console::BG_BLUE, Console::NEGATIVE]), + 'test' + ], + [ + Console::ansiFormat('test', [Console::NEGATIVE]), + 'test' + ], + [ + Console::ansiFormat('test', [Console::CONCEALED]), + 'test' + ], + ]; + } + + /** + * @dataProvider ansiFormats + */ + public function testAnsi2Html($ansi, $html) + { + $this->assertEquals($html, Console::ansiToHtml($ansi)); + } +} diff --git a/tests/framework/helpers/FallbackInflector.php b/tests/framework/helpers/FallbackInflector.php new file mode 100644 index 0000000..0eff0e9 --- /dev/null +++ b/tests/framework/helpers/FallbackInflector.php @@ -0,0 +1,21 @@ +testFilePath = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . get_class($this); + $this->createDir($this->testFilePath); + if (!file_exists($this->testFilePath)) { + $this->markTestIncomplete('Unit tests runtime directory should have writable permissions!'); + } + } + + public function tearDown() + { + $this->removeDir($this->testFilePath); + } + + /** + * Creates directory. + * @param string $dirName directory full name. + */ + protected function createDir($dirName) + { + if (!file_exists($dirName)) { + mkdir($dirName, 0777, true); + } + } + + /** + * Removes directory. + * @param string $dirName directory full name. + */ + protected function removeDir($dirName) + { + if (!empty($dirName) && is_dir($dirName)) { + if ($handle = opendir($dirName)) { + while (false !== ($entry = readdir($handle))) { + if ($entry != '.' && $entry != '..') { + if (is_dir($dirName . DIRECTORY_SEPARATOR . $entry) === true) { + $this->removeDir($dirName . DIRECTORY_SEPARATOR . $entry); + } else { + unlink($dirName . DIRECTORY_SEPARATOR . $entry); + } + } + } + closedir($handle); + rmdir($dirName); + } + } + } + + /** + * Get file permission mode. + * @param string $file file name. + * @return string permission mode. + */ + protected function getMode($file) + { + return substr(sprintf('%o', fileperms($file)), -4); + } + + /** + * Creates test files structure, + * @param array $items file system objects to be created in format: objectName => objectContent + * Arrays specifies directories, other values - files. + * @param string $basePath structure base file path. + */ + protected function createFileStructure(array $items, $basePath = '') + { + if (empty($basePath)) { + $basePath = $this->testFilePath; + } + foreach ($items as $name => $content) { + $itemName = $basePath . DIRECTORY_SEPARATOR . $name; + if (is_array($content)) { + if (isset($content[0], $content[1]) && $content[0] == 'symlink') { + symlink($content[1], $itemName); + } else { + mkdir($itemName, 0777, true); + $this->createFileStructure($content, $itemName); + } + } else { + file_put_contents($itemName, $content); + } + } + } + + /** + * Asserts that file has specific permission mode. + * @param integer $expectedMode expected file permission mode. + * @param string $fileName file name. + * @param string $message error message + */ + protected function assertFileMode($expectedMode, $fileName, $message = '') + { + $expectedMode = sprintf('%o', $expectedMode); + $this->assertEquals($expectedMode, $this->getMode($fileName), $message); + } + + // Tests : + + public function testCopyDirectory() + { + $srcDirName = 'test_src_dir'; + $files = [ + 'file1.txt' => 'file 1 content', + 'file2.txt' => 'file 2 content', + ]; + $this->createFileStructure([ + $srcDirName => $files + ]); + + $basePath = $this->testFilePath; + $srcDirName = $basePath . DIRECTORY_SEPARATOR . $srcDirName; + $dstDirName = $basePath . DIRECTORY_SEPARATOR . 'test_dst_dir'; + + FileHelper::copyDirectory($srcDirName, $dstDirName); + + $this->assertFileExists($dstDirName, 'Destination directory does not exist!'); + foreach ($files as $name => $content) { + $fileName = $dstDirName . DIRECTORY_SEPARATOR . $name; + $this->assertFileExists($fileName); + $this->assertEquals($content, file_get_contents($fileName), 'Incorrect file content!'); + } + } + + /** + * @depends testCopyDirectory + */ + public function testCopyDirectoryPermissions() + { + if (DIRECTORY_SEPARATOR === '\\') { + $this->markTestSkipped("Can't reliably test it on Windows because fileperms() always return 0777."); + } + + $srcDirName = 'test_src_dir'; + $subDirName = 'test_sub_dir'; + $fileName = 'test_file.txt'; + $this->createFileStructure([ + $srcDirName => [ + $subDirName => [], + $fileName => 'test file content', + ], + ]); + + $basePath = $this->testFilePath; + $srcDirName = $basePath . DIRECTORY_SEPARATOR . $srcDirName; + $dstDirName = $basePath . DIRECTORY_SEPARATOR . 'test_dst_dir'; + + $dirMode = 0755; + $fileMode = 0755; + $options = [ + 'dirMode' => $dirMode, + 'fileMode' => $fileMode, + ]; + FileHelper::copyDirectory($srcDirName, $dstDirName, $options); + + $this->assertFileMode($dirMode, $dstDirName, 'Destination directory has wrong mode!'); + $this->assertFileMode($dirMode, $dstDirName . DIRECTORY_SEPARATOR . $subDirName, 'Copied sub directory has wrong mode!'); + $this->assertFileMode($fileMode, $dstDirName . DIRECTORY_SEPARATOR . $fileName, 'Copied file has wrong mode!'); + } + + public function testRemoveDirectory() + { + $dirName = 'test_dir_for_remove'; + $this->createFileStructure([ + $dirName => [ + 'file1.txt' => 'file 1 content', + 'file2.txt' => 'file 2 content', + 'test_sub_dir' => [ + 'sub_dir_file_1.txt' => 'sub dir file 1 content', + 'sub_dir_file_2.txt' => 'sub dir file 2 content', + ], + ], + ]); + + $basePath = $this->testFilePath; + $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; + + FileHelper::removeDirectory($dirName); + + $this->assertFileNotExists($dirName, 'Unable to remove directory!'); + + // should be silent about non-existing directories + FileHelper::removeDirectory($basePath . DIRECTORY_SEPARATOR . 'nonExisting'); + } + + public function testRemoveDirectorySymlinks1() + { + if (strtolower(substr(PHP_OS, 0, 3)) == 'win') { + $this->markTestSkipped('Cannot test this on MS Windows since symlinks are uncommon for it.'); + } + + $dirName = 'remove-directory-symlinks-1'; + $this->createFileStructure([ + $dirName => [ + 'file' => 'Symlinked file.', + 'directory' => [ + 'standard-file-1' => 'Standard file 1.' + ], + 'symlinks' => [ + 'standard-file-2' => 'Standard file 2.', + 'symlinked-file' => ['symlink', '..' . DIRECTORY_SEPARATOR . 'file'], + 'symlinked-directory' => ['symlink', '..' . DIRECTORY_SEPARATOR . 'directory'], + ], + ], + ]); + + $basePath = $this->testFilePath . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR; + $this->assertFileExists($basePath . 'file'); + $this->assertTrue(is_dir($basePath . 'directory')); + $this->assertFileExists($basePath . 'directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); + $this->assertTrue(is_dir($basePath . 'symlinks')); + $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'standard-file-2'); + $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-file'); + $this->assertTrue(is_dir($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory')); + $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); + + FileHelper::removeDirectory($basePath . 'symlinks'); + + $this->assertFileExists($basePath . 'file'); + $this->assertTrue(is_dir($basePath . 'directory')); + $this->assertFileExists($basePath . 'directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); // symlinked directory still have it's file + $this->assertFalse(is_dir($basePath . 'symlinks')); + $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'standard-file-2'); + $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-file'); + $this->assertFalse(is_dir($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory')); + $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); + } + + public function testRemoveDirectorySymlinks2() + { + if (strtolower(substr(PHP_OS, 0, 3)) == 'win') { + $this->markTestSkipped('Cannot test this on MS Windows since symlinks are uncommon for it.'); + } + + $dirName = 'remove-directory-symlinks-2'; + $this->createFileStructure([ + $dirName => [ + 'file' => 'Symlinked file.', + 'directory' => [ + 'standard-file-1' => 'Standard file 1.' + ], + 'symlinks' => [ + 'standard-file-2' => 'Standard file 2.', + 'symlinked-file' => ['symlink', '..' . DIRECTORY_SEPARATOR . 'file'], + 'symlinked-directory' => ['symlink', '..' . DIRECTORY_SEPARATOR . 'directory'], + ], + ], + ]); + + $basePath = $this->testFilePath . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR; + $this->assertFileExists($basePath . 'file'); + $this->assertTrue(is_dir($basePath . 'directory')); + $this->assertFileExists($basePath . 'directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); + $this->assertTrue(is_dir($basePath . 'symlinks')); + $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'standard-file-2'); + $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-file'); + $this->assertTrue(is_dir($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory')); + $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); + + FileHelper::removeDirectory($basePath . 'symlinks', ['traverseSymlinks' => true]); + + $this->assertFileExists($basePath . 'file'); + $this->assertTrue(is_dir($basePath . 'directory')); + $this->assertFileNotExists($basePath . 'directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); // symlinked directory doesn't have it's file now + $this->assertFalse(is_dir($basePath . 'symlinks')); + $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'standard-file-2'); + $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-file'); + $this->assertFalse(is_dir($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory')); + $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); + } + + public function testFindFiles() + { + $dirName = 'test_dir'; + $this->createFileStructure([ + $dirName => [ + 'file_1.txt' => 'file 1 content', + 'file_2.txt' => 'file 2 content', + 'test_sub_dir' => [ + 'file_1_1.txt' => 'sub dir file 1 content', + 'file_1_2.txt' => 'sub dir file 2 content', + ], + ], + ]); + $basePath = $this->testFilePath; + $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; + $expectedFiles = [ + $dirName . DIRECTORY_SEPARATOR . 'file_1.txt', + $dirName . DIRECTORY_SEPARATOR . 'file_2.txt', + $dirName . DIRECTORY_SEPARATOR . 'test_sub_dir' . DIRECTORY_SEPARATOR . 'file_1_1.txt', + $dirName . DIRECTORY_SEPARATOR . 'test_sub_dir' . DIRECTORY_SEPARATOR . 'file_1_2.txt', + ]; + + $foundFiles = FileHelper::findFiles($dirName); + sort($expectedFiles); + sort($foundFiles); + $this->assertEquals($expectedFiles, $foundFiles); + } + + /** + * @depends testFindFiles + */ + public function testFindFileFilter() + { + $dirName = 'test_dir'; + $passedFileName = 'passed.txt'; + $this->createFileStructure([ + $dirName => [ + $passedFileName => 'passed file content', + 'declined.txt' => 'declined file content', + ], + ]); + $basePath = $this->testFilePath; + $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; + + $options = [ + 'filter' => function ($path) use ($passedFileName) { + return $passedFileName == basename($path); + } + ]; + $foundFiles = FileHelper::findFiles($dirName, $options); + $this->assertEquals([$dirName . DIRECTORY_SEPARATOR . $passedFileName], $foundFiles); + } + + /** + * @depends testFindFiles + */ + public function testFindFilesExclude() + { + $basePath = $this->testFilePath . DIRECTORY_SEPARATOR; + $dirs = ['', 'one', 'one' . DIRECTORY_SEPARATOR . 'two', 'three']; + $files = array_fill_keys(array_map(function ($n) { + return "a.$n"; + }, range(1, 8)), 'file contents'); + + $tree = $files; + $root = $files; + $flat = []; + foreach ($dirs as $dir) { + foreach ($files as $fileName => $contents) { + $flat[] = rtrim($basePath . $dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $fileName; + } + if ($dir === '') { + continue; + } + $parts = explode(DIRECTORY_SEPARATOR, $dir); + $last = array_pop($parts); + $parent = array_pop($parts); + $tree[$last] = $files; + if ($parent !== null) { + $tree[$parent][$last] = &$tree[$last]; + } else { + $root[$last] = &$tree[$last]; + } + } + $this->createFileStructure($root); + + // range + $foundFiles = FileHelper::findFiles($basePath, ['except' => ['a.[2-8]']]); + sort($foundFiles); + $expect = array_values(array_filter($flat, function ($p) { + return substr($p, -3)==='a.1'; + })); + $this->assertEquals($expect, $foundFiles); + + // suffix + $foundFiles = FileHelper::findFiles($basePath, ['except' => ['*.1']]); + sort($foundFiles); + $expect = array_values(array_filter($flat, function ($p) { + return substr($p, -3)!=='a.1'; + })); + $this->assertEquals($expect, $foundFiles); + + // dir + $foundFiles = FileHelper::findFiles($basePath, ['except' => ['/one']]); + sort($foundFiles); + $expect = array_values(array_filter($flat, function ($p) { + return strpos($p, DIRECTORY_SEPARATOR.'one')===false; + })); + $this->assertEquals($expect, $foundFiles); + + // dir contents + $foundFiles = FileHelper::findFiles($basePath, ['except' => ['?*/a.1']]); + sort($foundFiles); + $expect = array_values(array_filter($flat, function ($p) { + return substr($p, -11, 10)==='one'.DIRECTORY_SEPARATOR.'two'.DIRECTORY_SEPARATOR.'a.' || ( + substr($p, -8)!==DIRECTORY_SEPARATOR.'one'.DIRECTORY_SEPARATOR.'a.1' && + substr($p, -10)!==DIRECTORY_SEPARATOR.'three'.DIRECTORY_SEPARATOR.'a.1' + ); + })); + $this->assertEquals($expect, $foundFiles); + } + + /** + * @depends testFindFilesExclude + */ + public function testFindFilesCaseSensitive() + { + $dirName = 'test_dir'; + $this->createFileStructure([ + $dirName => [ + 'lower.txt' => 'lower case filename', + 'upper.TXT' => 'upper case filename', + ], + ]); + $basePath = $this->testFilePath; + $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; + + $options = [ + 'except' => ['*.txt'], + 'caseSensitive' => false + ]; + $foundFiles = FileHelper::findFiles($dirName, $options); + $this->assertCount(0, $foundFiles); + + $options = [ + 'only' => ['*.txt'], + 'caseSensitive' => false + ]; + $foundFiles = FileHelper::findFiles($dirName, $options); + $this->assertCount(2, $foundFiles); + } + + public function testCreateDirectory() + { + $basePath = $this->testFilePath; + $dirName = $basePath . DIRECTORY_SEPARATOR . 'test_dir_level_1' . DIRECTORY_SEPARATOR . 'test_dir_level_2'; + $this->assertTrue(FileHelper::createDirectory($dirName), 'FileHelper::createDirectory should return true if directory was created!'); + $this->assertFileExists($dirName, 'Unable to create directory recursively!'); + $this->assertTrue(FileHelper::createDirectory($dirName), 'FileHelper::createDirectory should return true for already existing directories!'); + } + + public function testGetMimeTypeByExtension() + { + $magicFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'mime_type.php'; + $mimeTypeMap = [ + 'txa' => 'application/json', + 'txb' => 'another/mime', + ]; + $magicFileContent = ' $mimeType) { + $fileName = 'test.' . $extension; + $this->assertNull(FileHelper::getMimeTypeByExtension($fileName)); + $this->assertEquals($mimeType, FileHelper::getMimeTypeByExtension($fileName, $magicFile)); + } + } + + public function testGetMimeType() + { + $file = $this->testFilePath . DIRECTORY_SEPARATOR . 'mime_type_test.txt'; + file_put_contents($file, 'some text'); + $this->assertEquals('text/plain', FileHelper::getMimeType($file)); + + // see http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type + // JSON/JSONP should not use text/plain - see http://jibbering.com/blog/?p=514 + // with "fileinfo" extension enabled, returned MIME is not quite correctly "text/plain" + // without "fileinfo" it falls back to getMimeTypeByExtension() and returns application/json + $file = $this->testFilePath . DIRECTORY_SEPARATOR . 'mime_type_test.json'; + file_put_contents($file, '{"a": "b"}'); + $this->assertTrue(in_array(FileHelper::getMimeType($file), ['application/json', 'text/plain'])); + } + + public function testNormalizePath() + { + $ds = DIRECTORY_SEPARATOR; + $this->assertEquals("{$ds}a{$ds}b", FileHelper::normalizePath('//a\b/')); + $this->assertEquals("{$ds}b{$ds}c", FileHelper::normalizePath('/a/../b/c')); + $this->assertEquals("{$ds}c", FileHelper::normalizePath('/a\\b/../..///c')); + $this->assertEquals("{$ds}c", FileHelper::normalizePath('/a/.\\b//../../c')); + $this->assertEquals("c", FileHelper::normalizePath('/a/.\\b/../..//../c')); + $this->assertEquals("..{$ds}c", FileHelper::normalizePath('//a/.\\b//..//..//../../c')); + + // relative paths + $this->assertEquals(".", FileHelper::normalizePath('.')); + $this->assertEquals(".", FileHelper::normalizePath('./')); + $this->assertEquals("a", FileHelper::normalizePath('.\\a')); + $this->assertEquals("a{$ds}b", FileHelper::normalizePath('./a\\b')); + $this->assertEquals(".", FileHelper::normalizePath('./a\\../')); + $this->assertEquals("..{$ds}..{$ds}a", FileHelper::normalizePath('../..\\a')); + $this->assertEquals("..{$ds}..{$ds}a", FileHelper::normalizePath('../..\\a/../a')); + $this->assertEquals("..{$ds}..{$ds}b", FileHelper::normalizePath('../..\\a/../b')); + $this->assertEquals("..{$ds}a", FileHelper::normalizePath('./..\\a')); + $this->assertEquals("..{$ds}a", FileHelper::normalizePath('././..\\a')); + $this->assertEquals("..{$ds}a", FileHelper::normalizePath('./..\\a/../a')); + $this->assertEquals("..{$ds}b", FileHelper::normalizePath('./..\\a/../b')); + } + + public function testLocalizedDirectory() + { + $this->createFileStructure([ + 'views' => [ + 'faq.php' => 'English FAQ', + 'de-DE' => [ + 'faq.php' => 'German FAQ', + ], + ], + ]); + $viewFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'faq.php'; + $sourceLanguage = 'en-US'; + + // Source language and target language are same. The view path should be unchanged. + $currentLanguage = $sourceLanguage; + $this->assertSame($viewFile, FileHelper::localize($viewFile, $currentLanguage, $sourceLanguage)); + + // Source language and target language are different. The view path should be changed. + $currentLanguage = 'de-DE'; + $this->assertSame( + $this->testFilePath . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . $currentLanguage . DIRECTORY_SEPARATOR . 'faq.php', + FileHelper::localize($viewFile, $currentLanguage, $sourceLanguage) + ); + } + + /** + * @see https://github.com/yiisoft/yii2/issues/3393 + * + * @depends testCopyDirectory + * @depends testFindFiles + */ + public function testCopyDirectoryExclude() + { + $srcDirName = 'test_src_dir'; + $textFiles = [ + 'file1.txt' => 'text file 1 content', + 'file2.txt' => 'text file 2 content', + ]; + $dataFiles = [ + 'file1.dat' => 'data file 1 content', + 'file2.dat' => 'data file 2 content', + ]; + $this->createFileStructure([ + $srcDirName => array_merge($textFiles, $dataFiles) + ]); + + $basePath = $this->testFilePath; + $srcDirName = $basePath . DIRECTORY_SEPARATOR . $srcDirName; + $dstDirName = $basePath . DIRECTORY_SEPARATOR . 'test_dst_dir'; + + FileHelper::copyDirectory($srcDirName, $dstDirName, ['only' => ['*.dat']]); + + $this->assertFileExists($dstDirName, 'Destination directory does not exist!'); + $copiedFiles = FileHelper::findFiles($dstDirName); + $this->assertCount(2, $copiedFiles, 'wrong files count copied'); + + foreach ($dataFiles as $name => $content) { + $fileName = $dstDirName . DIRECTORY_SEPARATOR . $name; + $this->assertFileExists($fileName); + $this->assertEquals($content, file_get_contents($fileName), 'Incorrect file content!'); + } + } +} diff --git a/tests/framework/helpers/FormatConverterTest.php b/tests/framework/helpers/FormatConverterTest.php new file mode 100644 index 0000000..1bd198d --- /dev/null +++ b/tests/framework/helpers/FormatConverterTest.php @@ -0,0 +1,75 @@ +mockApplication([ + 'timeZone' => 'UTC', + 'language' => 'ru-RU', + ]); + } + + protected function tearDown() + { + parent::tearDown(); + IntlTestHelper::resetIntlStatus(); + } + + public function testIntlIcuToPhpShortForm() + { + $this->assertEquals('n/j/y', FormatConverter::convertDateIcuToPhp('short', 'date', 'en-US')); + $this->assertEquals('d.m.y', FormatConverter::convertDateIcuToPhp('short', 'date', 'de-DE')); + } + + public function testEscapedIcuToPhp() + { + $this->assertEquals('l, F j, Y \\a\\t g:i:s a T', FormatConverter::convertDateIcuToPhp('EEEE, MMMM d, y \'at\' h:mm:ss a zzzz')); + $this->assertEquals('\\o\\\'\\c\\l\\o\\c\\k', FormatConverter::convertDateIcuToPhp('\'o\'\'clock\'')); + } + + public function testEscapedIcuToJui() + { + $this->assertEquals('l, F j, Y \\a\\t g:i:s a T', FormatConverter::convertDateIcuToPhp('EEEE, MMMM d, y \'at\' h:mm:ss a zzzz')); + $this->assertEquals('\'o\'\'clock\'', FormatConverter::convertDateIcuToJui('\'o\'\'clock\'')); + } + + public function testIntlOneDigitIcu() + { + $formatter = new Formatter(['locale' => 'en-US']); + $this->assertEquals('24.8.2014', $formatter->asDate('2014-8-24', 'php:d.n.Y')); + $this->assertEquals('24.8.2014', $formatter->asDate('2014-8-24', 'd.M.yyyy')); + } + + public function testOneDigitIcu() + { + $formatter = new Formatter(['locale' => 'en-US']); + $this->assertEquals('24.8.2014', $formatter->asDate('2014-8-24', 'php:d.n.Y')); + $this->assertEquals('24.8.2014', $formatter->asDate('2014-8-24', 'd.M.yyyy')); + } + + public function testIntlUtf8Ru() + { + $this->assertEquals('d M Y \г.', FormatConverter::convertDateIcuToPhp('dd MMM y \'г\'.', 'date', 'ru-RU')); + $this->assertEquals('dd M yy \'г\'.', FormatConverter::convertDateIcuToJui('dd MMM y \'г\'.', 'date', 'ru-RU')); + + $formatter = new Formatter(['locale' => 'ru-RU']); + $this->assertEquals('24 авг 2014 г.', $formatter->asDate('2014-8-24', 'dd MMM y \'г\'.')); + } +} diff --git a/tests/framework/helpers/HtmlTest.php b/tests/framework/helpers/HtmlTest.php new file mode 100644 index 0000000..f8ee237 --- /dev/null +++ b/tests/framework/helpers/HtmlTest.php @@ -0,0 +1,658 @@ +mockApplication([ + 'components' => [ + 'request' => [ + 'class' => 'yii\web\Request', + 'url' => '/test', + 'enableCsrfValidation' => false, + ], + 'response' => [ + 'class' => 'yii\web\Response', + ], + ], + ]); + } + + public function testEncode() + { + $this->assertEquals("a<>&"'�", Html::encode("a<>&\"'\x80")); + $this->assertEquals('Sam & Dark', Html::encode('Sam & Dark')); + } + + public function testDecode() + { + $this->assertEquals("a<>&\"'", Html::decode("a<>&"'")); + } + + public function testTag() + { + $this->assertEquals('
', Html::tag('br')); + $this->assertEquals('', Html::tag('span')); + $this->assertEquals('
content
', Html::tag('div', 'content')); + $this->assertEquals('', Html::tag('input', '', ['type' => 'text', 'name' => 'test', 'value' => '<>'])); + $this->assertEquals('', Html::tag('span', '', ['disabled' => true])); + } + + public function testBeginTag() + { + $this->assertEquals('
', Html::beginTag('br')); + $this->assertEquals('', Html::beginTag('span', ['id' => 'test', 'class' => 'title'])); + } + + public function testEndTag() + { + $this->assertEquals('
', Html::endTag('br')); + $this->assertEquals('
', Html::endTag('span')); + } + + public function testStyle() + { + $content = 'a <>'; + $this->assertEquals("", Html::style($content)); + $this->assertEquals("", Html::style($content, ['type' => 'text/less'])); + } + + public function testScript() + { + $content = 'a <>'; + $this->assertEquals("", Html::script($content)); + $this->assertEquals("", Html::script($content, ['type' => 'text/js'])); + } + + public function testCssFile() + { + $this->assertEquals('', Html::cssFile('http://example.com')); + $this->assertEquals('', Html::cssFile('')); + $this->assertEquals("", Html::cssFile('http://example.com', ['condition' => 'IE 9'])); + } + + public function testJsFile() + { + $this->assertEquals('', Html::jsFile('http://example.com')); + $this->assertEquals('', Html::jsFile('')); + $this->assertEquals("", Html::jsFile('http://example.com', ['condition' => 'IE 9'])); + } + + public function testBeginForm() + { + $this->assertEquals('
', Html::beginForm()); + $this->assertEquals('', Html::beginForm('/example', 'get')); + $hiddens = [ + '', + '', + ]; + $this->assertEquals('' . "\n" . implode("\n", $hiddens), Html::beginForm('/example?id=1&title=%3C', 'get')); + } + + public function testEndForm() + { + $this->assertEquals('
', Html::endForm()); + } + + public function testA() + { + $this->assertEquals('something<>', Html::a('something<>')); + $this->assertEquals('something', Html::a('something', '/example')); + $this->assertEquals('something', Html::a('something', '')); + $this->assertEquals('http://www.быстроном.рф', Html::a('http://www.быстроном.рф', 'http://www.быстроном.рф')); + } + + public function testMailto() + { + $this->assertEquals('test<>', Html::mailto('test<>')); + $this->assertEquals('test<>', Html::mailto('test<>', 'test>')); + } + + public function testImg() + { + $this->assertEquals('', Html::img('/example')); + $this->assertEquals('', Html::img('')); + $this->assertEquals('something', Html::img('/example', ['alt' => 'something', 'width' => 10])); + } + + public function testLabel() + { + $this->assertEquals('', Html::label('something<>')); + $this->assertEquals('', Html::label('something<>', 'a')); + $this->assertEquals('', Html::label('something<>', 'a', ['class' => 'test'])); + } + + public function testButton() + { + $this->assertEquals('', Html::button()); + $this->assertEquals('', Html::button('content<>', ['name' => 'test', 'value' => 'value'])); + $this->assertEquals('', Html::button('content<>', ['type' => 'submit', 'name' => 'test', 'value' => 'value', 'class' => "t"])); + } + + public function testSubmitButton() + { + $this->assertEquals('', Html::submitButton()); + $this->assertEquals('', Html::submitButton('content<>', ['name' => 'test', 'value' => 'value', 'class' => 't'])); + } + + public function testResetButton() + { + $this->assertEquals('', Html::resetButton()); + $this->assertEquals('', Html::resetButton('content<>', ['name' => 'test', 'value' => 'value', 'class' => 't'])); + } + + public function testInput() + { + $this->assertEquals('', Html::input('text')); + $this->assertEquals('', Html::input('text', 'test', 'value', ['class' => 't'])); + } + + public function testButtonInput() + { + $this->assertEquals('', Html::buttonInput()); + $this->assertEquals('', Html::buttonInput('text', ['name' => 'test', 'class' => 'a'])); + } + + public function testSubmitInput() + { + $this->assertEquals('', Html::submitInput()); + $this->assertEquals('', Html::submitInput('text', ['name' => 'test', 'class' => 'a'])); + } + + public function testResetInput() + { + $this->assertEquals('', Html::resetInput()); + $this->assertEquals('', Html::resetInput('text', ['name' => 'test', 'class' => 'a'])); + } + + public function testTextInput() + { + $this->assertEquals('', Html::textInput('test')); + $this->assertEquals('', Html::textInput('test', 'value', ['class' => 't'])); + } + + public function testHiddenInput() + { + $this->assertEquals('', Html::hiddenInput('test')); + $this->assertEquals('', Html::hiddenInput('test', 'value', ['class' => 't'])); + } + + public function testPasswordInput() + { + $this->assertEquals('', Html::passwordInput('test')); + $this->assertEquals('', Html::passwordInput('test', 'value', ['class' => 't'])); + } + + public function testFileInput() + { + $this->assertEquals('', Html::fileInput('test')); + $this->assertEquals('', Html::fileInput('test', 'value', ['class' => 't'])); + } + + public function testTextarea() + { + $this->assertEquals('', Html::textarea('test')); + $this->assertEquals('', Html::textarea('test', 'value<>', ['class' => 't'])); + } + + public function testRadio() + { + $this->assertEquals('', Html::radio('test')); + $this->assertEquals('', Html::radio('test', true, ['class' => 'a', 'value' => null])); + $this->assertEquals('', Html::radio('test', true, ['class' => 'a', 'uncheck' => '0', 'value' => 2])); + + $this->assertEquals('', Html::radio('test', true, [ + 'class' => 'a', + 'value' => null, + 'label' => 'ccc', + 'labelOptions' => ['class' =>'bbb'], + ])); + $this->assertEquals('', Html::radio('test', true, [ + 'class' => 'a', + 'uncheck' => '0', + 'label' => 'ccc', + 'value' => 2, + ])); + } + + public function testCheckbox() + { + $this->assertEquals('', Html::checkbox('test')); + $this->assertEquals('', Html::checkbox('test', true, ['class' => 'a', 'value' => null])); + $this->assertEquals('', Html::checkbox('test', true, ['class' => 'a', 'uncheck' => '0', 'value' => 2])); + + $this->assertEquals('', Html::checkbox('test', true, [ + 'class' => 'a', + 'value' => null, + 'label' => 'ccc', + 'labelOptions' => ['class' =>'bbb'], + ])); + $this->assertEquals('', Html::checkbox('test', true, [ + 'class' => 'a', + 'uncheck' => '0', + 'label' => 'ccc', + 'value' => 2, + ])); + } + + public function testDropDownList() + { + $expected = << + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::dropDownList('test')); + $expected = << + + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', null, $this->getDataItems())); + $expected = << + + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', 'value2', $this->getDataItems())); + } + + public function testListBox() + { + $expected = << + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test')); + $expected = << + + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems(), ['size' => 5])); + $expected = << + + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems2())); + $expected = << + + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems2(), ['encodeSpaces' => true])); + $expected = << + + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems2(), ['encode' => false])); + $expected = << + + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems2(), ['encodeSpaces' => true, 'encode' => false])); + $expected = << + + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', 'value2', $this->getDataItems())); + $expected = << + + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', ['value1', 'value2'], $this->getDataItems())); + + $expected = << + + +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, [], ['multiple' => true])); + $expected = << +EOD; + $this->assertEqualsWithoutLE($expected, Html::listBox('test', '', [], ['unselect' => '0'])); + } + + public function testCheckboxList() + { + $this->assertEquals('
', Html::checkboxList('test')); + + $expected = << + +EOD; + $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems())); + + $expected = << + +EOD; + $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems2())); + + $expected = <<

+
+EOD; + $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems(), [ + 'separator' => "
\n", + 'unselect' => '0', + ])); + + $expected = <<0 +1 +EOD; + $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems(), [ + 'item' => function ($index, $label, $name, $checked, $value) { + return $index . Html::label($label . ' ' . Html::checkbox($name, $checked, ['value' => $value])); + } + ])); + } + + public function testRadioList() + { + $this->assertEquals('
', Html::radioList('test')); + + $expected = << + +EOD; + $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems())); + + $expected = << + +EOD; + $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems2())); + + $expected = <<

+
+EOD; + $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems(), [ + 'separator' => "
\n", + 'unselect' => '0', + ])); + + $expected = <<0 +1 +EOD; + $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems(), [ + 'item' => function ($index, $label, $name, $checked, $value) { + return $index . Html::label($label . ' ' . Html::radio($name, $checked, ['value' => $value])); + } + ])); + } + + public function testUl() + { + $data = [ + 1, 'abc', '<>', + ]; + $expected = << +
  • 1
  • +
  • abc
  • +
  • <>
  • + +EOD; + $this->assertEqualsWithoutLE($expected, Html::ul($data)); + $expected = << +
  • 1
  • +
  • abc
  • +
  • <>
  • + +EOD; + $this->assertEqualsWithoutLE($expected, Html::ul($data, [ + 'class' => 'test', + 'item' => function ($item, $index) { + return "
  • $item
  • "; + } + ])); + + $this->assertEquals('
      ', Html::ul([], ['class' => 'test'])); + } + + public function testOl() + { + $data = [ + 1, 'abc', '<>', + ]; + $expected = << +
    • 1
    • +
    • abc
    • +
    • <>
    • + +EOD; + $this->assertEqualsWithoutLE($expected, Html::ol($data, [ + 'itemOptions' => ['class' => 'ti'], + ])); + $expected = << +
    • 1
    • +
    • abc
    • +
    • <>
    • + +EOD; + $this->assertEqualsWithoutLE($expected, Html::ol($data, [ + 'class' => 'test', + 'item' => function ($item, $index) { + return "
    • $item
    • "; + } + ])); + + $this->assertEquals('
        ', Html::ol([], ['class' => 'test'])); + } + + public function testRenderOptions() + { + $data = [ + 'value1' => 'label1', + 'group1' => [ + 'value11' => 'label11', + 'group11' => [ + 'value111' => 'label111', + ], + 'group12' => [], + ], + 'value2' => 'label2', + 'group2' => [], + ]; + $expected = <<please select<> + + + + + + + + + + + + + + +EOD; + $attributes = [ + 'prompt' => 'please select<>', + 'options' => [ + 'value111' => ['class' => 'option'], + ], + 'groups' => [ + 'group12' => ['class' => 'group'], + ], + 'encodeSpaces' => true, + ]; + $this->assertEqualsWithoutLE($expected, Html::renderSelectOptions(['value111', 'value1'], $data, $attributes)); + + $attributes = [ + 'prompt' => 'please select<>', + 'options' => [ + 'value111' => ['class' => 'option'], + ], + 'groups' => [ + 'group12' => ['class' => 'group'], + ], + ]; + $this->assertEqualsWithoutLE(str_replace(' ', ' ', $expected), Html::renderSelectOptions(['value111', 'value1'], $data, $attributes)); + } + + public function testRenderAttributes() + { + $this->assertEquals('', Html::renderTagAttributes([])); + $this->assertEquals(' name="test" value="1<>"', Html::renderTagAttributes(['name' => 'test', 'empty' => null, 'value' => '1<>'])); + $this->assertEquals(' checked disabled', Html::renderTagAttributes(['checked' => true, 'disabled' => true, 'hidden' => false])); + } + + public function testAddCssClass() + { + $options = []; + Html::addCssClass($options, 'test'); + $this->assertEquals(['class' => 'test'], $options); + Html::addCssClass($options, 'test'); + $this->assertEquals(['class' => 'test'], $options); + Html::addCssClass($options, 'test2'); + $this->assertEquals(['class' => 'test test2'], $options); + Html::addCssClass($options, 'test'); + $this->assertEquals(['class' => 'test test2'], $options); + Html::addCssClass($options, 'test2'); + $this->assertEquals(['class' => 'test test2'], $options); + Html::addCssClass($options, 'test3'); + $this->assertEquals(['class' => 'test test2 test3'], $options); + Html::addCssClass($options, 'test2'); + $this->assertEquals(['class' => 'test test2 test3'], $options); + } + + public function testRemoveCssClass() + { + $options = ['class' => 'test test2 test3']; + Html::removeCssClass($options, 'test2'); + $this->assertEquals(['class' => 'test test3'], $options); + Html::removeCssClass($options, 'test2'); + $this->assertEquals(['class' => 'test test3'], $options); + Html::removeCssClass($options, 'test'); + $this->assertEquals(['class' => 'test3'], $options); + Html::removeCssClass($options, 'test3'); + $this->assertEquals([], $options); + } + + public function testCssStyleFromArray() + { + $this->assertEquals('width: 100px; height: 200px;', Html::cssStyleFromArray([ + 'width' => '100px', + 'height' => '200px', + ])); + $this->assertNull(Html::cssStyleFromArray([])); + } + + public function testCssStyleToArray() + { + $this->assertEquals([ + 'width' => '100px', + 'height' => '200px', + ], Html::cssStyleToArray('width: 100px; height: 200px;')); + $this->assertEquals([], Html::cssStyleToArray(' ')); + } + + public function testAddCssStyle() + { + $options = ['style' => 'width: 100px; height: 200px;']; + Html::addCssStyle($options, 'width: 110px; color: red;'); + $this->assertEquals('width: 110px; height: 200px; color: red;', $options['style']); + + $options = ['style' => 'width: 100px; height: 200px;']; + Html::addCssStyle($options, ['width' => '110px', 'color' => 'red']); + $this->assertEquals('width: 110px; height: 200px; color: red;', $options['style']); + + $options = ['style' => 'width: 100px; height: 200px;']; + Html::addCssStyle($options, 'width: 110px; color: red;', false); + $this->assertEquals('width: 100px; height: 200px; color: red;', $options['style']); + + $options = []; + Html::addCssStyle($options, 'width: 110px; color: red;'); + $this->assertEquals('width: 110px; color: red;', $options['style']); + + $options = []; + Html::addCssStyle($options, 'width: 110px; color: red;', false); + $this->assertEquals('width: 110px; color: red;', $options['style']); + } + + public function testRemoveCssStyle() + { + $options = ['style' => 'width: 110px; height: 200px; color: red;']; + Html::removeCssStyle($options, 'width'); + $this->assertEquals('height: 200px; color: red;', $options['style']); + Html::removeCssStyle($options, ['height']); + $this->assertEquals('color: red;', $options['style']); + Html::removeCssStyle($options, ['color', 'background']); + $this->assertNull($options['style']); + + $options = []; + Html::removeCssStyle($options, ['color', 'background']); + $this->assertTrue(!array_key_exists('style', $options)); + } + + public function testBooleanAttributes() + { + $this->assertEquals('', Html::input('email', 'mail', null, ['required' => false])); + $this->assertEquals('', Html::input('email', 'mail', null, ['required' => true])); + $this->assertEquals('', Html::input('email', 'mail', null, ['required' => 'hi'])); + } + + public function testDataAttributes() + { + $this->assertEquals('', Html::tag('link', '', ['src' => 'xyz', 'data' => ['a' => 1, 'b' => 'c']])); + $this->assertEquals('', Html::tag('link', '', ['src' => 'xyz', 'ng' => ['a' => 1, 'b' => 'c']])); + $this->assertEquals('', Html::tag('link', '', ['src' => 'xyz', 'data-ng' => ['a' => 1, 'b' => 'c']])); + $this->assertEquals('', Html::tag('link', '', ['src' => ['a' => 1, 'b' => "It's"]])); + } + + protected function getDataItems() + { + return [ + 'value1' => 'text1', + 'value2' => 'text2', + ]; + } + + protected function getDataItems2() + { + return [ + 'value1<>' => 'text1<>', + 'value 2' => 'text 2', + ]; + } +} diff --git a/tests/framework/helpers/InflectorTest.php b/tests/framework/helpers/InflectorTest.php new file mode 100644 index 0000000..658eef6 --- /dev/null +++ b/tests/framework/helpers/InflectorTest.php @@ -0,0 +1,248 @@ + 'moves', + 'foot' => 'feet', + 'child' => 'children', + 'human' => 'humans', + 'man' => 'men', + 'staff' => 'staff', + 'tooth' => 'teeth', + 'person' => 'people', + 'mouse' => 'mice', + 'touch' => 'touches', + 'hash' => 'hashes', + 'shelf' => 'shelves', + 'potato' => 'potatoes', + 'bus' => 'buses', + 'test' => 'tests', + 'car' => 'cars', + ]; + + foreach ($testData as $testIn => $testOut) { + $this->assertEquals($testOut, Inflector::pluralize($testIn)); + $this->assertEquals(ucfirst($testOut), ucfirst(Inflector::pluralize($testIn))); + } + } + + public function testSingularize() + { + $testData = [ + 'moves' => 'move', + 'feet' => 'foot', + 'children' => 'child', + 'humans' => 'human', + 'men' => 'man', + 'staff' => 'staff', + 'teeth' => 'tooth', + 'people' => 'person', + 'mice' => 'mouse', + 'touches' => 'touch', + 'hashes' => 'hash', + 'shelves' => 'shelf', + 'potatoes' => 'potato', + 'buses' => 'bus', + 'tests' => 'test', + 'cars' => 'car', + ]; + foreach ($testData as $testIn => $testOut) { + $this->assertEquals($testOut, Inflector::singularize($testIn)); + $this->assertEquals(ucfirst($testOut), ucfirst(Inflector::singularize($testIn))); + } + } + + public function testTitleize() + { + $this->assertEquals("Me my self and i", Inflector::titleize('MeMySelfAndI')); + $this->assertEquals("Me My Self And I", Inflector::titleize('MeMySelfAndI', true)); + } + + public function testCamelize() + { + $this->assertEquals("MeMySelfAndI", Inflector::camelize('me my_self-andI')); + $this->assertEquals("QweQweEwq", Inflector::camelize('qwe qwe^ewq')); + } + + public function testUnderscore() + { + $this->assertEquals("me_my_self_and_i", Inflector::underscore('MeMySelfAndI')); + } + + public function testCamel2words() + { + $this->assertEquals('Camel Case', Inflector::camel2words('camelCase')); + $this->assertEquals('Lower Case', Inflector::camel2words('lower_case')); + $this->assertEquals('Tricky Stuff It Is Testing', Inflector::camel2words(' tricky_stuff.it-is testing... ')); + } + + public function testCamel2id() + { + $this->assertEquals('post-tag', Inflector::camel2id('PostTag')); + $this->assertEquals('post_tag', Inflector::camel2id('PostTag', '_')); + + $this->assertEquals('post-tag', Inflector::camel2id('postTag')); + $this->assertEquals('post_tag', Inflector::camel2id('postTag', '_')); + + $this->assertEquals('foo-ybar', Inflector::camel2id('FooYBar', '-', false)); + $this->assertEquals('foo_ybar', Inflector::camel2id('fooYBar', '_', false)); + + $this->assertEquals('foo-y-bar', Inflector::camel2id('FooYBar', '-', true)); + $this->assertEquals('foo_y_bar', Inflector::camel2id('fooYBar', '_', true)); + } + + public function testId2camel() + { + $this->assertEquals('PostTag', Inflector::id2camel('post-tag')); + $this->assertEquals('PostTag', Inflector::id2camel('post_tag', '_')); + + $this->assertEquals('PostTag', Inflector::id2camel('post-tag')); + $this->assertEquals('PostTag', Inflector::id2camel('post_tag', '_')); + + $this->assertEquals('FooYBar', Inflector::id2camel('foo-y-bar')); + $this->assertEquals('FooYBar', Inflector::id2camel('foo_y_bar', '_')); + } + + public function testHumanize() + { + $this->assertEquals("Me my self and i", Inflector::humanize('me_my_self_and_i')); + $this->assertEquals("Me My Self And I", Inflector::humanize('me_my_self_and_i', true)); + } + + public function testVariablize() + { + $this->assertEquals("customerTable", Inflector::variablize('customer_table')); + } + + public function testTableize() + { + $this->assertEquals("customer_tables", Inflector::tableize('customerTable')); + } + + public function testSlugCommons() + { + $data = [ + '' => '', + 'hello world 123' => 'hello-world-123', + 'remove.!?[]{}…symbols' => 'removesymbols', + 'minus-sign' => 'minus-sign', + 'mdash—sign' => 'mdash-sign', + 'ndash–sign' => 'ndash-sign', + 'áàâéèêíìîóòôúùûã' => 'aaaeeeiiiooouuua', + 'älä lyö ääliö ööliä läikkyy' => 'ala-lyo-aalio-oolia-laikkyy', + ]; + + foreach ($data as $source => $expected) { + if (extension_loaded('intl')) { + $this->assertEquals($expected, FallbackInflector::slug($source)); + } + $this->assertEquals($expected, Inflector::slug($source)); + } + } + + public function testSlugIntl() + { + if (!extension_loaded('intl')) { + $this->markTestSkipped('intl extension is required.'); + } + + // Some test strings are from https://github.com/bergie/midgardmvc_helper_urlize. Thank you, Henri Bergius! + $data = [ + // Korean + '해동검도' => 'haedong-geomdo', + + // Hiragana + 'ひらがな' => 'hiragana', + + // Georgian + 'საქართველო' => 'sakartvelo', + + // Arabic + 'العربي' => 'alrby', + 'عرب' => 'rb', + + // Hebrew + 'עִבְרִית' => 'iberiyt', + + // Turkish + 'Sanırım hepimiz aynı şeyi düşünüyoruz.' => 'sanrm-hepimiz-ayn-seyi-dusunuyoruz', + + // Russian + 'недвижимость' => 'nedvizimost', + 'Контакты' => 'kontakty', + ]; + + foreach ($data as $source => $expected) { + $this->assertEquals($expected, Inflector::slug($source)); + } + } + + public function testSlugPhp() + { + $data = [ + 'we have недвижимость' => 'we-have', + ]; + + foreach ($data as $source => $expected) { + $this->assertEquals($expected, FallbackInflector::slug($source)); + } + } + + public function testClassify() + { + $this->assertEquals("CustomerTable", Inflector::classify('customer_tables')); + } + + public function testOrdinalize() + { + $this->assertEquals('21st', Inflector::ordinalize('21')); + $this->assertEquals('22nd', Inflector::ordinalize('22')); + $this->assertEquals('23rd', Inflector::ordinalize('23')); + $this->assertEquals('24th', Inflector::ordinalize('24')); + $this->assertEquals('25th', Inflector::ordinalize('25')); + $this->assertEquals('111th', Inflector::ordinalize('111')); + $this->assertEquals('113th', Inflector::ordinalize('113')); + } + + public function testSentence() + { + $array = []; + $this->assertEquals('', Inflector::sentence($array)); + + $array = ['Spain']; + $this->assertEquals('Spain', Inflector::sentence($array)); + + $array = ['Spain', 'France']; + $this->assertEquals('Spain and France', Inflector::sentence($array)); + + $array = ['Spain', 'France', 'Italy']; + $this->assertEquals('Spain, France and Italy', Inflector::sentence($array)); + + $array = ['Spain', 'France', 'Italy', 'Germany']; + $this->assertEquals('Spain, France, Italy and Germany', Inflector::sentence($array)); + + $array = ['Spain', 'France']; + $this->assertEquals('Spain or France', Inflector::sentence($array, ' or ')); + + $array = ['Spain', 'France', 'Italy']; + $this->assertEquals('Spain, France or Italy', Inflector::sentence($array, ' or ')); + + $array = ['Spain', 'France']; + $this->assertEquals('Spain and France', Inflector::sentence($array, ' and ', ' or ', ' - ')); + + $array = ['Spain', 'France', 'Italy']; + $this->assertEquals('Spain - France or Italy', Inflector::sentence($array, ' and ', ' or ', ' - ')); + } +} diff --git a/tests/framework/helpers/JsonTest.php b/tests/framework/helpers/JsonTest.php new file mode 100644 index 0000000..147ccdb --- /dev/null +++ b/tests/framework/helpers/JsonTest.php @@ -0,0 +1,81 @@ +assertSame('"1"', Json::encode($data)); + + // simple array encoding + $data = [1, 2]; + $this->assertSame('[1,2]', Json::encode($data)); + $data = ['a' => 1, 'b' => 2]; + $this->assertSame('{"a":1,"b":2}', Json::encode($data)); + + // simple object encoding + $data = new \stdClass(); + $data->a = 1; + $data->b = 2; + $this->assertSame('{"a":1,"b":2}', Json::encode($data)); + + // expression encoding + $expression = 'function () {}'; + $data = new JsExpression($expression); + $this->assertSame($expression, Json::encode($data)); + + // complex data + $expression1 = 'function (a) {}'; + $expression2 = 'function (b) {}'; + $data = [ + 'a' => [ + 1, new JsExpression($expression1) + ], + 'b' => new JsExpression($expression2), + ]; + $this->assertSame("{\"a\":[1,$expression1],\"b\":$expression2}", Json::encode($data)); + + // https://github.com/yiisoft/yii2/issues/957 + $data = (object) null; + $this->assertSame('{}', Json::encode($data)); + + // JsonSerializable + $data = new JsonModel(); + $this->assertSame('{"json":"serializable"}', Json::encode($data)); + } + + public function testDecode() + { + // basic data decoding + $json = '"1"'; + $this->assertSame('1', Json::decode($json)); + + // array decoding + $json = '{"a":1,"b":2}'; + $this->assertSame(['a' => 1, 'b' => 2], Json::decode($json)); + + // exception + $json = '{"a":1,"b":2'; + $this->setExpectedException('yii\base\InvalidParamException'); + Json::decode($json); + } +} + +class JsonModel extends Model implements \JsonSerializable +{ + function jsonSerialize() + { + return ['json' => 'serializable']; + } +} \ No newline at end of file diff --git a/tests/framework/helpers/StringHelperTest.php b/tests/framework/helpers/StringHelperTest.php new file mode 100644 index 0000000..b305aaf --- /dev/null +++ b/tests/framework/helpers/StringHelperTest.php @@ -0,0 +1,239 @@ +mockApplication(); + } + + public function testStrlen() + { + $this->assertEquals(4, StringHelper::byteLength('this')); + $this->assertEquals(6, StringHelper::byteLength('это')); + } + + public function testSubstr() + { + $this->assertEquals('th', StringHelper::byteSubstr('this', 0, 2)); + $this->assertEquals('э', StringHelper::byteSubstr('это', 0, 2)); + + $this->assertEquals('abcdef', StringHelper::byteSubstr('abcdef', 0)); + $this->assertEquals('abcdef', StringHelper::byteSubstr('abcdef', 0, null)); + + $this->assertEquals('de', StringHelper::byteSubstr('abcdef', 3, 2)); + $this->assertEquals('def', StringHelper::byteSubstr('abcdef', 3)); + $this->assertEquals('def', StringHelper::byteSubstr('abcdef', 3, null)); + + $this->assertEquals('cd', StringHelper::byteSubstr('abcdef', -4, 2)); + $this->assertEquals('cdef', StringHelper::byteSubstr('abcdef', -4)); + $this->assertEquals('cdef', StringHelper::byteSubstr('abcdef', -4, null)); + + $this->assertEquals('', StringHelper::byteSubstr('abcdef', 4, 0)); + $this->assertEquals('', StringHelper::byteSubstr('abcdef', -4, 0)); + + $this->assertEquals('это', StringHelper::byteSubstr('это', 0)); + $this->assertEquals('это', StringHelper::byteSubstr('это', 0, null)); + + $this->assertEquals('т', StringHelper::byteSubstr('это', 2, 2)); + $this->assertEquals('то', StringHelper::byteSubstr('это', 2)); + $this->assertEquals('то', StringHelper::byteSubstr('это', 2, null)); + + $this->assertEquals('т', StringHelper::byteSubstr('это', -4, 2)); + $this->assertEquals('то', StringHelper::byteSubstr('это', -4)); + $this->assertEquals('то', StringHelper::byteSubstr('это', -4, null)); + + $this->assertEquals('', StringHelper::byteSubstr('это', 4, 0)); + $this->assertEquals('', StringHelper::byteSubstr('это', -4, 0)); + } + + public function testBasename() + { + $this->assertEquals('', StringHelper::basename('')); + + $this->assertEquals('file', StringHelper::basename('file')); + $this->assertEquals('file.test', StringHelper::basename('file.test', '.test2')); + $this->assertEquals('file', StringHelper::basename('file.test', '.test')); + + $this->assertEquals('file', StringHelper::basename('/file')); + $this->assertEquals('file.test', StringHelper::basename('/file.test', '.test2')); + $this->assertEquals('file', StringHelper::basename('/file.test', '.test')); + + $this->assertEquals('file', StringHelper::basename('/path/to/file')); + $this->assertEquals('file.test', StringHelper::basename('/path/to/file.test', '.test2')); + $this->assertEquals('file', StringHelper::basename('/path/to/file.test', '.test')); + + $this->assertEquals('file', StringHelper::basename('\file')); + $this->assertEquals('file.test', StringHelper::basename('\file.test', '.test2')); + $this->assertEquals('file', StringHelper::basename('\file.test', '.test')); + + $this->assertEquals('file', StringHelper::basename('C:\file')); + $this->assertEquals('file.test', StringHelper::basename('C:\file.test', '.test2')); + $this->assertEquals('file', StringHelper::basename('C:\file.test', '.test')); + + $this->assertEquals('file', StringHelper::basename('C:\path\to\file')); + $this->assertEquals('file.test', StringHelper::basename('C:\path\to\file.test', '.test2')); + $this->assertEquals('file', StringHelper::basename('C:\path\to\file.test', '.test')); + + // mixed paths + $this->assertEquals('file.test', StringHelper::basename('/path\to/file.test')); + $this->assertEquals('file.test', StringHelper::basename('/path/to\file.test')); + $this->assertEquals('file.test', StringHelper::basename('\path/to\file.test')); + + // \ and / in suffix + $this->assertEquals('file', StringHelper::basename('/path/to/filete/st', 'te/st')); + $this->assertEquals('st', StringHelper::basename('/path/to/filete/st', 'te\st')); + $this->assertEquals('file', StringHelper::basename('/path/to/filete\st', 'te\st')); + $this->assertEquals('st', StringHelper::basename('/path/to/filete\st', 'te/st')); + + // http://www.php.net/manual/en/function.basename.php#72254 + $this->assertEquals('foo', StringHelper::basename('/bar/foo/')); + $this->assertEquals('foo', StringHelper::basename('\\bar\\foo\\')); + } + + public function testTruncate() + { + $this->assertEquals('привет, я multibyte...', StringHelper::truncate('привет, я multibyte строка!', 20)); + $this->assertEquals('Не трогаем строку', StringHelper::truncate('Не трогаем строку', 20)); + $this->assertEquals('исполь!!!', StringHelper::truncate('используем восклицательные знаки', 6, '!!!')); + + // With Html + $this->assertEquals('This is a test ...', StringHelper::truncate('This is a test sentance', 14, '...', null, true)); + $this->assertEquals('This is a test ...', StringHelper::truncate('This is a test sentance', 14, '...', null, true)); + } + + public function testTruncateWords() + { + $this->assertEquals('это тестовая multibyte строка', StringHelper::truncateWords('это тестовая multibyte строка', 5)); + $this->assertEquals('это тестовая multibyte...', StringHelper::truncateWords('это тестовая multibyte строка', 3)); + $this->assertEquals('это тестовая multibyte!!!', StringHelper::truncateWords('это тестовая multibyte строка', 3, '!!!')); + $this->assertEquals('это строка с неожиданными...', StringHelper::truncateWords('это строка с неожиданными пробелами', 4)); + + // With Html + $this->assertEquals('This is a test...', StringHelper::truncateWords('This is a test sentance', 4, '...', true)); + $this->assertEquals('This is a test...', StringHelper::truncateWords('This is a test sentance', 4, '...', true)); + } + + /** + * @dataProvider providerStartsWith + */ + public function testStartsWith($result, $string, $with) + { + // case sensitive version check + $this->assertSame($result, StringHelper::startsWith($string, $with)); + // case insensitive version check + $this->assertSame($result, StringHelper::startsWith($string, $with, false)); + } + + /** + * Rules that should work the same for case-sensitive and case-insensitive `startsWith()` + */ + public function providerStartsWith() + { + return [ + // positive check + [true, '', ''], + [true, '', null], + [true, 'string', ''], + [true, ' string', ' '], + [true, 'abc', 'abc'], + [true, 'Bürger', 'Bürger'], + [true, '我Я multibyte', '我Я'], + [true, 'Qנטשופ צרכנות', 'Qנ'], + [true, 'ไทย.idn.icann.org', 'ไ'], + [true, '!?+', "\x21\x3F"], + [true, "\x21?+", '!?'], + // false-positive check + [false, '', ' '], + [false, ' ', ' '], + [false, 'Abc', 'Abcde'], + [false, 'abc', 'abe'], + [false, 'abc', 'b'], + [false, 'abc', 'c'], + ]; + } + + public function testStartsWithCaseSensitive() + { + $this->assertFalse(StringHelper::startsWith('Abc', 'a')); + $this->assertFalse(StringHelper::startsWith('üЯ multibyte', 'Üя multibyte')); + } + + public function testStartsWithCaseInsensitive() + { + $this->assertTrue(StringHelper::startsWith('sTrInG', 'StRiNg', false)); + $this->assertTrue(StringHelper::startsWith('CaSe', 'cAs', false)); + $this->assertTrue(StringHelper::startsWith('HTTP://BÜrger.DE/', 'http://bürger.de', false)); + $this->assertTrue(StringHelper::startsWith('üЯйΨB', 'ÜяЙΨ', false)); + } + + /** + * @dataProvider providerEndsWith + */ + public function testEndsWith($result, $string, $with) + { + // case sensitive version check + $this->assertSame($result, StringHelper::endsWith($string, $with)); + // case insensitive version check + $this->assertSame($result, StringHelper::endsWith($string, $with, false)); + } + + /** + * Rules that should work the same for case-sensitive and case-insensitive `endsWith()` + */ + public function providerEndsWith() + { + return [ + // positive check + [true, '', ''], + [true, '', null], + [true, 'string', ''], + [true, 'string ', ' '], + [true, 'string', 'g'], + [true, 'abc', 'abc'], + [true, 'Bürger', 'Bürger'], + [true, 'Я multibyte строка我!', ' строка我!'], + [true, '+!?', "\x21\x3F"], + [true, "+\x21?", "!\x3F"], + [true, 'נטשופ צרכנות', 'ת'], + // false-positive check + [false, '', ' '], + [false, ' ', ' '], + [false, 'aaa', 'aaaa'], + [false, 'abc', 'abe'], + [false, 'abc', 'a'], + [false, 'abc', 'b'], + ]; + } + + public function testEndsWithCaseSensitive() + { + $this->assertFalse(StringHelper::endsWith('string', 'G')); + $this->assertFalse(StringHelper::endsWith('multibyte строка', 'А')); + } + + public function testEndsWithCaseInsensitive() + { + $this->assertTrue(StringHelper::endsWith('sTrInG', 'StRiNg', false)); + $this->assertTrue(StringHelper::endsWith('string', 'nG', false)); + $this->assertTrue(StringHelper::endsWith('BüЯйΨ', 'ÜяЙΨ', false)); + } + + public function testExplode() + { + $this->assertEquals(['It', 'is', 'a first', 'test'], StringHelper::explode("It, is, a first, test")); + $this->assertEquals(['It', 'is', 'a second', 'test'], StringHelper::explode("It+ is+ a second+ test", '+')); + $this->assertEquals(['Save', '', '', 'empty trimmed string'], StringHelper::explode("Save, ,, empty trimmed string", ',')); + $this->assertEquals(['Здесь', 'multibyte', 'строка'], StringHelper::explode("Здесь我 multibyte我 строка", '我')); + $this->assertEquals(['Disable', ' trim ', 'here but ignore empty'], StringHelper::explode("Disable, trim ,,,here but ignore empty", ',', false, true)); + } +} diff --git a/tests/framework/helpers/UrlTest.php b/tests/framework/helpers/UrlTest.php new file mode 100644 index 0000000..4630362 --- /dev/null +++ b/tests/framework/helpers/UrlTest.php @@ -0,0 +1,208 @@ +mockApplication([ + 'components' => [ + 'request' => [ + 'class' => 'yii\web\Request', + 'scriptUrl' => '/base/index.php', + 'hostInfo' => 'http://example.com/', + 'url' => '/base/index.php&r=site%2Fcurrent&id=42' + ], + 'urlManager' => [ + 'class' => 'yii\web\UrlManager', + 'baseUrl' => '/base', + 'scriptUrl' => '/base/index.php', + 'hostInfo' => 'http://example.com/', + ] + ], + ], '\yii\web\Application'); + } + + /** + * Mocks controller action with parameters + * + * @param string $controllerId + * @param string $actionID + * @param string $moduleID + * @param array $params + */ + protected function mockAction($controllerId, $actionID, $moduleID = null, $params = []) + { + \Yii::$app->controller = $controller = new Controller($controllerId, \Yii::$app); + $controller->actionParams = $params; + $controller->action = new Action($actionID, $controller); + + if ($moduleID !== null) { + $controller->module = new Module($moduleID); + } + } + + protected function removeMockedAction() + { + \Yii::$app->controller = null; + } + + public function testToRoute() + { + $this->mockAction('page', 'view', null, ['id' => 10]); + + // If the route is an empty string, the current route will be used; + $this->assertEquals('/base/index.php?r=page%2Fview', Url::toRoute('')); + $this->assertEquals('http://example.com/base/index.php?r=page%2Fview', Url::toRoute('', true)); + $this->assertEquals('https://example.com/base/index.php?r=page%2Fview', Url::toRoute('', 'https')); + + // If the route contains no slashes at all, it is considered to be an action ID of the current controller and + // will be prepended with uniqueId; + $this->assertEquals('/base/index.php?r=page%2Fedit', Url::toRoute('edit')); + $this->assertEquals('/base/index.php?r=page%2Fedit&id=20', Url::toRoute(['edit', 'id' => 20])); + $this->assertEquals('http://example.com/base/index.php?r=page%2Fedit&id=20', Url::toRoute(['edit', 'id' => 20], true)); + $this->assertEquals('https://example.com/base/index.php?r=page%2Fedit&id=20', Url::toRoute(['edit', 'id' => 20], 'https')); + + // If the route has no leading slash, it is considered to be a route relative + // to the current module and will be prepended with the module's uniqueId. + $this->mockAction('default', 'index', 'stats'); + $this->assertEquals('/base/index.php?r=stats%2Fuser%2Fview', Url::toRoute('user/view')); + $this->assertEquals('/base/index.php?r=stats%2Fuser%2Fview&id=42', Url::toRoute(['user/view', 'id' => 42])); + $this->assertEquals('http://example.com/base/index.php?r=stats%2Fuser%2Fview&id=42', Url::toRoute(['user/view', 'id' => 42], true)); + $this->assertEquals('https://example.com/base/index.php?r=stats%2Fuser%2Fview&id=42', Url::toRoute(['user/view', 'id' => 42], 'https')); + + // alias support + \Yii::setAlias('@userView', 'user/view'); + $this->assertEquals('/base/index.php?r=stats%2Fuser%2Fview', Url::toRoute('@userView')); + \Yii::setAlias('@userView', null); + + // In case there is no controller, an exception should be thrown for relative route + $this->removeMockedAction(); + + $this->setExpectedException('yii\base\InvalidParamException'); + Url::toRoute('site/view'); + } + + public function testCurrent() + { + $this->mockAction('page', 'view', null, []); + \Yii::$app->request->setQueryParams(['id' => 10, 'name' => 'test']); + + $this->assertEquals('/base/index.php?r=page%2Fview&id=10&name=test', Url::current()); + + $this->assertEquals('/base/index.php?r=page%2Fview&id=20&name=test', Url::current(['id' => 20])); + + $this->assertEquals('/base/index.php?r=page%2Fview&name=test', Url::current(['id' => null])); + } + + public function testTo() + { + // is an array: the first array element is considered a route, while the rest of the name-value + // pairs are treated as the parameters to be used for URL creation using Url::toRoute. + $this->mockAction('page', 'view', null, ['id' => 10]); + $this->assertEquals('/base/index.php?r=page%2Fedit&id=20', Url::to(['edit', 'id' => 20])); + $this->assertEquals('/base/index.php?r=page%2Fedit', Url::to(['edit'])); + $this->assertEquals('/base/index.php?r=page%2Fview', Url::to([''])); + + // alias support + \Yii::setAlias('@pageEdit', 'edit'); + $this->assertEquals('/base/index.php?r=page%2Fedit&id=20', Url::to(['@pageEdit', 'id' => 20])); + \Yii::setAlias('@pageEdit', null); + + $this->assertEquals('http://example.com/base/index.php?r=page%2Fedit&id=20', Url::to(['edit', 'id' => 20], true)); + $this->assertEquals('http://example.com/base/index.php?r=page%2Fedit', Url::to(['edit'], true)); + $this->assertEquals('http://example.com/base/index.php?r=page%2Fview', Url::to([''], true)); + + $this->assertEquals('https://example.com/base/index.php?r=page%2Fedit&id=20', Url::to(['edit', 'id' => 20], 'https')); + $this->assertEquals('https://example.com/base/index.php?r=page%2Fedit', Url::to(['edit'], 'https')); + $this->assertEquals('https://example.com/base/index.php?r=page%2Fview', Url::to([''], 'https')); + + // is an empty string: the currently requested URL will be returned; + $this->mockAction('page', 'view', null, ['id' => 10]); + $this->assertEquals('/base/index.php&r=site%2Fcurrent&id=42', Url::to('')); + $this->assertEquals('http://example.com/base/index.php&r=site%2Fcurrent&id=42', Url::to('', true)); + $this->assertEquals('https://example.com/base/index.php&r=site%2Fcurrent&id=42', Url::to('', 'https')); + + // is a non-empty string: it will first be processed by [[Yii::getAlias()]]. If the result + // is an absolute URL, it will be returned either without any change or, if schema was specified, with schema + // replaced; Otherwise, the result will be prefixed with [[\yii\web\Request::baseUrl]] and returned. + \Yii::setAlias('@web1', 'http://test.example.com/test/me1'); + \Yii::setAlias('@web2', 'test/me2'); + \Yii::setAlias('@web3', ''); + \Yii::setAlias('@web4', '/test'); + \Yii::setAlias('@web5', '#test'); + + $this->assertEquals('test/me1', Url::to('test/me1')); + $this->assertEquals('javascript:test/me1', Url::to('javascript:test/me1')); + $this->assertEquals('java/script:test/me1', Url::to('java/script:test/me1')); + $this->assertEquals('#test/me1', Url::to('#test/me1')); + $this->assertEquals('.test/me1', Url::to('.test/me1')); + $this->assertEquals('http://example.com/test/me1', Url::to('test/me1', true)); + $this->assertEquals('https://example.com/test/me1', Url::to('test/me1', 'https')); + $this->assertEquals('https://example.com/test/test/me1', Url::to('@web4/test/me1', 'https')); + + $this->assertEquals('/test/me1', Url::to('/test/me1')); + $this->assertEquals('http://example.com/test/me1', Url::to('/test/me1', true)); + $this->assertEquals('https://example.com/test/me1', Url::to('/test/me1', 'https')); + $this->assertEquals('./test/me1', Url::to('./test/me1')); + + $this->assertEquals('http://test.example.com/test/me1', Url::to('@web1')); + $this->assertEquals('http://test.example.com/test/me1', Url::to('@web1', true)); + $this->assertEquals('https://test.example.com/test/me1', Url::to('@web1', 'https')); + + $this->assertEquals('test/me2', Url::to('@web2')); + $this->assertEquals('http://example.com/test/me2', Url::to('@web2', true)); + $this->assertEquals('https://example.com/test/me2', Url::to('@web2', 'https')); + + $this->assertEquals('/base/index.php&r=site%2Fcurrent&id=42', Url::to('@web3')); + $this->assertEquals('http://example.com/base/index.php&r=site%2Fcurrent&id=42', Url::to('@web3', true)); + $this->assertEquals('https://example.com/base/index.php&r=site%2Fcurrent&id=42', Url::to('@web3', 'https')); + + $this->assertEquals('/test', Url::to('@web4')); + $this->assertEquals('http://example.com/test', Url::to('@web4', true)); + $this->assertEquals('https://example.com/test', Url::to('@web4', 'https')); + + $this->assertEquals('#test', Url::to('@web5')); + $this->assertEquals('http://example.com/#test', Url::to('@web5', true)); + $this->assertEquals('https://example.com/#test', Url::to('@web5', 'https')); + + //In case there is no controller, throw an exception + $this->removeMockedAction(); + + $this->setExpectedException('yii\base\InvalidParamException'); + Url::to(['site/view']); + } + + public function testBase() + { + $this->mockAction('page', 'view', null, ['id' => 10]); + $this->assertEquals('/base', Url::base()); + $this->assertEquals('http://example.com/base', Url::base(true)); + $this->assertEquals('https://example.com/base', Url::base('https')); + } + + public function testHome() + { + $this->assertEquals('/base/index.php', Url::home()); + $this->assertEquals('http://example.com/base/index.php', Url::home(true)); + $this->assertEquals('https://example.com/base/index.php', Url::home('https')); + } + + public function testCanonical() + { + $this->mockAction('page', 'view', null, ['id' => 10]); + $this->assertEquals('http://example.com/base/index.php?r=page%2Fview&id=10', Url::canonical()); + $this->removeMockedAction(); + } +} diff --git a/tests/framework/helpers/VarDumperTest.php b/tests/framework/helpers/VarDumperTest.php new file mode 100644 index 0000000..6faff10 --- /dev/null +++ b/tests/framework/helpers/VarDumperTest.php @@ -0,0 +1,108 @@ +assertEquals("stdClass#1\n(\n)", ob_get_contents()); + ob_end_clean(); + } + + /** + * Data provider for [[testExport()]] + * @return array test data + */ + public function dataProviderExport() + { + // Regular : + + $data = [ + [ + 'test string', + var_export('test string', true) + ], + [ + 75, + var_export(75, true) + ], + [ + 7.5, + var_export(7.5, true) + ], + [ + null, + 'null' + ], + [ + true, + 'true' + ], + [ + false, + 'false' + ], + [ + [], + '[]' + ], + ]; + + // Arrays : + + $var = [ + 'key1' => 'value1', + 'key2' => 'value2', + ]; + $expectedResult = << 'value1', + 'key2' => 'value2', +] +RESULT; + $data[] = [$var, $expectedResult]; + + $var = [ + 'value1', + 'value2', + ]; + $expectedResult = <<testField = 'Test Value'; + $expectedResult = "unserialize('" . serialize($var) . "')"; + $data[] = [$var, $expectedResult]; + + return $data; + } + + /** + * @dataProvider dataProviderExport + * + * @param mixed $var + * @param string $expectedResult + */ + public function testExport($var, $expectedResult) + { + $exportResult = VarDumper::export($var); + $this->assertEqualsWithoutLE($expectedResult, $exportResult); + $this->assertEquals($var, eval('return ' . $exportResult . ';')); + } +} diff --git a/tests/framework/i18n/FallbackMessageFormatterTest.php b/tests/framework/i18n/FallbackMessageFormatterTest.php new file mode 100644 index 0000000..5e9780c --- /dev/null +++ b/tests/framework/i18n/FallbackMessageFormatterTest.php @@ -0,0 +1,179 @@ + + * @since 2.0 + * @group i18n + */ +class FallbackMessageFormatterTest extends TestCase +{ + const N = 'n'; + const N_VALUE = 42; + const SUBJECT = 'сабж'; + const SUBJECT_VALUE = 'Answer to the Ultimate Question of Life, the Universe, and Everything'; + + public function patterns() + { + return [ + [ + '{'.self::SUBJECT.'} is {'.self::N.'}', // pattern + self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected + [ // params + self::N => self::N_VALUE, + self::SUBJECT => self::SUBJECT_VALUE, + ] + ], + + [ + '{'.self::SUBJECT.'} is {'.self::N.', number}', // pattern + self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected + [ // params + self::N => self::N_VALUE, + self::SUBJECT => self::SUBJECT_VALUE, + ] + ], + + [ + '{'.self::SUBJECT.'} is {'.self::N.', number, integer}', // pattern + self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected + [ // params + self::N => self::N_VALUE, + self::SUBJECT => self::SUBJECT_VALUE, + ] + ], + + // This one was provided by Aura.Intl. Thanks! + [<<<_MSG_ +{gender_of_host, select, + female {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to her party.} + =2 {{host} invites {guest} and one other person to her party.} + other {{host} invites {guest} and # other people to her party.}}} + male {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to his party.} + =2 {{host} invites {guest} and one other person to his party.} + other {{host} invites {guest} and # other people to his party.}}} + other {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to their party.} + =2 {{host} invites {guest} and one other person to their party.} + other {{host} invites {guest} and # other people to their party.}}}} +_MSG_ + , + 'ralph invites beep and 3 other people to his party.', + [ + 'gender_of_host' => 'male', + 'num_guests' => 4, + 'host' => 'ralph', + 'guest' => 'beep' + ] + ], + + [ + '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', + 'Alexander is male and he loves Yii!', + [ + 'name' => 'Alexander', + 'gender' => 'male', + ], + ], + + // verify pattern in select does not get replaced + [ + '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', + 'Alexander is male and he loves Yii!', + [ + 'name' => 'Alexander', + 'gender' => 'male', + // following should not be replaced + 'he' => 'wtf', + 'she' => 'wtf', + 'it' => 'wtf', + ] + ], + + // verify pattern in select message gets replaced + [ + '{name} is {gender} and {gender, select, female{she} male{{he}} other{it}} loves Yii!', + 'Alexander is male and wtf loves Yii!', + [ + 'name' => 'Alexander', + 'gender' => 'male', + 'he' => 'wtf', + 'she' => 'wtf', + ], + ], + + // some parser specific verifications + [ + '{gender} and {gender, select, female{she} male{{he}} other{it}} loves {nr} is {gender}!', + 'male and wtf loves 42 is male!', + [ + 'nr' => 42, + 'gender' => 'male', + 'he' => 'wtf', + 'she' => 'wtf', + ], + ], + ]; + } + + /** + * @dataProvider patterns + */ + public function testNamedArguments($pattern, $expected, $args) + { + $formatter = new FallbackMessageFormatter(); + $result = $formatter->fallbackFormat($pattern, $args, 'en-US'); + $this->assertEquals($expected, $result, $formatter->getErrorMessage()); + } + + public function testInsufficientArguments() + { + $expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; + + $formatter = new FallbackMessageFormatter(); + $result = $formatter->fallbackFormat('{'.self::SUBJECT.'} is {'.self::N.'}', [ + self::N => self::N_VALUE, + ], 'en-US'); + + $this->assertEquals($expected, $result); + } + + public function testNoParams() + { + $pattern = '{'.self::SUBJECT.'} is '.self::N; + + $formatter = new FallbackMessageFormatter(); + $result = $formatter->fallbackFormat($pattern, [], 'en-US'); + $this->assertEquals($pattern, $result, $formatter->getErrorMessage()); + } + + public function testGridViewMessage() + { + $pattern = 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.'; + $formatter = new FallbackMessageFormatter(); + $result = $formatter->fallbackFormat($pattern, ['begin' => 1, 'end' => 5, 'totalCount' => 10], 'en-US'); + $this->assertEquals('Showing 1-5 of 10 items.', $result); + } +} + +class FallbackMessageFormatter extends MessageFormatter +{ + public function fallbackFormat($pattern, $args, $locale) + { + return parent::fallbackFormat($pattern, $args, $locale); + } +} diff --git a/tests/framework/i18n/FormatterDateTest.php b/tests/framework/i18n/FormatterDateTest.php new file mode 100644 index 0000000..410ee3d --- /dev/null +++ b/tests/framework/i18n/FormatterDateTest.php @@ -0,0 +1,575 @@ +mockApplication([ + 'timeZone' => 'UTC', + 'language' => 'ru-RU', + ]); + $this->formatter = new Formatter(['locale' => 'en-US']); + } + + protected function tearDown() + { + parent::tearDown(); + IntlTestHelper::resetIntlStatus(); + $this->formatter = null; + } + + + public function testFormat() + { + $value = time(); + $this->assertSame(date('M j, Y', $value), $this->formatter->format($value, 'date')); + $this->assertSame(date('M j, Y', $value), $this->formatter->format($value, 'DATE')); + $this->assertSame(date('Y/m/d', $value), $this->formatter->format($value, ['date', 'php:Y/m/d'])); + $this->setExpectedException('\yii\base\InvalidParamException'); + $this->assertSame(date('Y-m-d', $value), $this->formatter->format($value, 'data')); + } + + public function testIntlAsDate() + { + $this->testAsDate(); + } + + public function testAsDate() + { + $value = time(); + $this->assertSame(date('M j, Y', $value), $this->formatter->asDate($value)); + $this->assertSame(date('Y/m/d', $value), $this->formatter->asDate($value, 'php:Y/m/d')); + $this->assertSame(date('m/d/Y', $value), $this->formatter->asDate($value, 'MM/dd/yyyy')); + $this->assertSame(date('n/j/y', $value), $this->formatter->asDate($value, 'short')); + $this->assertSame(date('F j, Y', $value), $this->formatter->asDate($value, 'long')); + + $value = new DateTime(); + $this->assertSame(date('M j, Y', $value->getTimestamp()), $this->formatter->asDate($value)); + $this->assertSame(date('Y/m/d', $value->getTimestamp()), $this->formatter->asDate($value, 'php:Y/m/d')); + $this->assertSame(date('m/d/Y', $value->getTimestamp()), $this->formatter->asDate($value, 'MM/dd/yyyy')); + $this->assertSame(date('n/j/y', $value->getTimestamp()), $this->formatter->asDate($value, 'short')); + $this->assertSame(date('F j, Y', $value->getTimestamp()), $this->formatter->asDate($value, 'long')); + + if (version_compare(PHP_VERSION, '5.5.0', '>=')) { + $value = new \DateTimeImmutable(); + $this->assertSame(date('M j, Y', $value->getTimestamp()), $this->formatter->asDate($value)); + $this->assertSame(date('Y/m/d', $value->getTimestamp()), $this->formatter->asDate($value, 'php:Y/m/d')); + $this->assertSame(date('m/d/Y', $value->getTimestamp()), $this->formatter->asDate($value, 'MM/dd/yyyy')); + $this->assertSame(date('n/j/y', $value->getTimestamp()), $this->formatter->asDate($value, 'short')); + $this->assertSame(date('F j, Y', $value->getTimestamp()), $this->formatter->asDate($value, 'long')); + } + + // empty input + $this->assertSame('Jan 1, 1970', $this->formatter->asDate('')); + $this->assertSame('Jan 1, 1970', $this->formatter->asDate(0)); + $this->assertSame('Jan 1, 1970', $this->formatter->asDate(false)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDate(null)); + } + + public function testIntlAsTime() + { + $this->testAsTime(); + + // empty input + $this->formatter->locale = 'de-DE'; + $this->assertSame('00:00:00', $this->formatter->asTime('')); + $this->assertSame('00:00:00', $this->formatter->asTime(0)); + $this->assertSame('00:00:00', $this->formatter->asTime(false)); + } + + public function testAsTime() + { + $value = time(); + $this->assertSame(date('g:i:s A', $value), $this->formatter->asTime($value)); + $this->assertSame(date('h:i:s A', $value), $this->formatter->asTime($value, 'php:h:i:s A')); + + $value = new DateTime(); + $this->assertSame(date('g:i:s A', $value->getTimestamp()), $this->formatter->asTime($value)); + $this->assertSame(date('h:i:s A', $value->getTimestamp()), $this->formatter->asTime($value, 'php:h:i:s A')); + + if (version_compare(PHP_VERSION, '5.5.0', '>=')) { + $value = new \DateTimeImmutable(); + $this->assertSame(date('g:i:s A', $value->getTimestamp()), $this->formatter->asTime($value)); + $this->assertSame(date('h:i:s A', $value->getTimestamp()), $this->formatter->asTime($value, 'php:h:i:s A')); + } + + // empty input + $this->assertSame('12:00:00 AM', $this->formatter->asTime('')); + $this->assertSame('12:00:00 AM', $this->formatter->asTime(0)); + $this->assertSame('12:00:00 AM', $this->formatter->asTime(false)); + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asTime(null)); + } + + public function testIntlAsDatetime() + { + $this->testAsDatetime(); + + // empty input + $this->formatter->locale = 'de-DE'; + $this->assertSame('01.01.1970 00:00:00', $this->formatter->asDatetime('')); + $this->assertSame('01.01.1970 00:00:00', $this->formatter->asDatetime(0)); + $this->assertSame('01.01.1970 00:00:00', $this->formatter->asDatetime(false)); + } + + public function testAsDatetime() + { + $value = time(); + $this->assertSame(date('M j, Y g:i:s A', $value), $this->formatter->asDatetime($value)); + $this->assertSame(date('Y/m/d h:i:s A', $value), $this->formatter->asDatetime($value, 'php:Y/m/d h:i:s A')); + + $value = new DateTime(); + $this->assertSame(date('M j, Y g:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value)); + $this->assertSame(date('Y/m/d h:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value, 'php:Y/m/d h:i:s A')); + + if (version_compare(PHP_VERSION, '5.5.0', '>=')) { + $value = new \DateTimeImmutable(); + $this->assertSame(date('M j, Y g:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value)); + $this->assertSame(date('Y/m/d h:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value, 'php:Y/m/d h:i:s A')); + } + + // empty input + $this->assertSame('Jan 1, 1970 12:00:00 AM', $this->formatter->asDatetime('')); + $this->assertSame('Jan 1, 1970 12:00:00 AM', $this->formatter->asDatetime(0)); + $this->assertSame('Jan 1, 1970 12:00:00 AM', $this->formatter->asDatetime(false)); + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDatetime(null)); + } + + public function testIntlAsTimestamp() + { + $this->testAsTimestamp(); + } + + public function testAsTimestamp() + { + $value = time(); + $this->assertSame("$value", $this->formatter->asTimestamp($value)); + $this->assertSame("$value", $this->formatter->asTimestamp((string) $value)); + + $this->assertSame("$value", $this->formatter->asTimestamp(date('Y-m-d H:i:s', $value))); + + // empty input + $this->assertSame("0", $this->formatter->asTimestamp(0)); + $this->assertSame("0", $this->formatter->asTimestamp(false)); + $this->assertSame("0", $this->formatter->asTimestamp("")); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asTimestamp(null)); + } + + public function testIntlDateRangeLow() + { + // intl does not support high date ranges on 32bit systems, the implementation uses a fallback to PHP formatter + $this->testDateRangeLow(); + } + + /** + * Test for dates before 1970 + * https://github.com/yiisoft/yii2/issues/3126 + */ + public function testDateRangeLow() + { + // http://en.wikipedia.org/wiki/Year_2038_problem + $this->assertSame('13-12-1901', $this->formatter->asDate('1901-12-13', 'dd-MM-yyyy')); + $this->assertSame('12-12-1901', $this->formatter->asDate('1901-12-12', 'dd-MM-yyyy')); + + $this->assertSame('12-08-1922', $this->formatter->asDate('1922-08-12', 'dd-MM-yyyy')); + $this->assertSame('14-01-1732', $this->formatter->asDate('1732-01-14', 'dd-MM-yyyy')); + } + + public function testIntlDateRangeHigh() + { + // intl does not support high date ranges on 32bit systems, the implementation uses a fallback to PHP formatter + $this->testDateRangeHigh(); + } + + /** + * Test for dates after 2038 + * https://github.com/yiisoft/yii2/issues/3126 + */ + public function testDateRangeHigh() + { + // http://en.wikipedia.org/wiki/Year_2038_problem + $this->assertSame('19-01-2038', $this->formatter->asDate('2038-01-19', 'dd-MM-yyyy')); + $this->assertSame('20-01-2038', $this->formatter->asDate('2038-01-20', 'dd-MM-yyyy')); + + $this->assertSame('17-12-2048', $this->formatter->asDate('2048-12-17', 'dd-MM-yyyy')); + $this->assertSame('17-12-3048', $this->formatter->asDate('3048-12-17', 'dd-MM-yyyy')); + $this->assertSame('31-12-9999', $this->formatter->asDate('9999-12-31', 'dd-MM-yyyy')); + } + + private function buildDateSubIntervals($referenceDate, $intervals) + { + $date = new DateTime($referenceDate); + foreach ($intervals as $interval) { + $date->sub($interval); + } + return $date; + } + + public function testIntlAsRelativeTime() + { + $this->testAsRelativeTime(); + } + + public function testAsRelativeTime() + { + $interval_1_second = new DateInterval("PT1S"); + $interval_244_seconds = new DateInterval("PT244S"); + $interval_1_minute = new DateInterval("PT1M"); + $interval_33_minutes = new DateInterval("PT33M"); + $interval_1_hour = new DateInterval("PT1H"); + $interval_6_hours = new DateInterval("PT6H"); + $interval_1_day = new DateInterval("P1D"); + $interval_89_days = new DateInterval("P89D"); + $interval_1_month = new DateInterval("P1M"); + $interval_5_months = new DateInterval("P5M"); + $interval_1_year = new DateInterval("P1Y"); + $interval_12_years = new DateInterval("P12Y"); + + // Pass a DateInterval + $this->assertSame('a second ago', $this->formatter->asRelativeTime($interval_1_second)); + $this->assertSame('244 seconds ago', $this->formatter->asRelativeTime($interval_244_seconds)); + $this->assertSame('a minute ago', $this->formatter->asRelativeTime($interval_1_minute)); + $this->assertSame('33 minutes ago', $this->formatter->asRelativeTime($interval_33_minutes)); + $this->assertSame('an hour ago', $this->formatter->asRelativeTime($interval_1_hour)); + $this->assertSame('6 hours ago', $this->formatter->asRelativeTime($interval_6_hours)); + $this->assertSame('a day ago', $this->formatter->asRelativeTime($interval_1_day)); + $this->assertSame('89 days ago', $this->formatter->asRelativeTime($interval_89_days)); + $this->assertSame('a month ago', $this->formatter->asRelativeTime($interval_1_month)); + $this->assertSame('5 months ago', $this->formatter->asRelativeTime($interval_5_months)); + $this->assertSame('a year ago', $this->formatter->asRelativeTime($interval_1_year)); + $this->assertSame('12 years ago', $this->formatter->asRelativeTime($interval_12_years)); + + // Pass a DateInterval string -> isn't possible + // $this->assertSame('a year ago', $this->formatter->asRelativeTime('2007-03-01T13:00:00Z/2008-05-11T15:30:00Z')); + // $this->assertSame('a year ago', $this->formatter->asRelativeTime('2007-03-01T13:00:00Z/P1Y2M10DT2H30M')); + // $this->assertSame('a year ago', $this->formatter->asRelativeTime('P1Y2M10DT2H30M/2008-05-11T15:30:00Z')); + // $this->assertSame('a year ago', $this->formatter->asRelativeTime('P1Y2M10DT2H30M')); + // $this->assertSame('94 months ago', $this->formatter->asRelativeTime('P94M')); + + // Force the reference time and pass a past DateTime + $dateNow = new DateTime('2014-03-13'); + $this->assertSame('a second ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_second]), $dateNow)); + $this->assertSame('4 minutes ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_244_seconds]), $dateNow)); + $this->assertSame('a minute ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_minute]), $dateNow)); + $this->assertSame('33 minutes ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_33_minutes]), $dateNow)); + $this->assertSame('an hour ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_hour]), $dateNow)); + $this->assertSame('6 hours ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_6_hours]), $dateNow)); + $this->assertSame('a day ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_day]), $dateNow)); + $this->assertSame('2 months ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_89_days]), $dateNow)); + $this->assertSame('a month ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_month]), $dateNow)); + $this->assertSame('5 months ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_5_months]), $dateNow)); + $this->assertSame('a year ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_year]), $dateNow)); + $this->assertSame('12 years ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_12_years]), $dateNow)); + + // Tricky 31-days month stuff + // See: http://www.gnu.org/software/tar/manual/html_section/Relative-items-in-date-strings.html + $dateNow = new DateTime('2014-03-31'); + $dateThen = new DateTime('2014-03-03'); + $this->assertSame('28 days ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-31', [$interval_1_month]), $dateNow)); + $this->assertSame('28 days ago', $this->formatter->asRelativeTime($dateThen, $dateNow)); + $dateThen = new DateTime('2014-02-28'); + $this->assertSame('a month ago', $this->formatter->asRelativeTime($dateThen, $dateNow)); + + // Invert all the DateIntervals + $interval_1_second->invert = true; + $interval_244_seconds->invert = true; + $interval_1_minute->invert = true; + $interval_33_minutes->invert = true; + $interval_1_hour->invert = true; + $interval_6_hours->invert = true; + $interval_1_day->invert = true; + $interval_89_days->invert = true; + $interval_1_month->invert = true; + $interval_5_months->invert = true; + $interval_1_year->invert = true; + $interval_12_years->invert = true; + + // Pass a inverted DateInterval + $this->assertSame('in a second', $this->formatter->asRelativeTime($interval_1_second)); + $this->assertSame('in 244 seconds', $this->formatter->asRelativeTime($interval_244_seconds)); + $this->assertSame('in a minute', $this->formatter->asRelativeTime($interval_1_minute)); + $this->assertSame('in 33 minutes', $this->formatter->asRelativeTime($interval_33_minutes)); + $this->assertSame('in an hour', $this->formatter->asRelativeTime($interval_1_hour)); + $this->assertSame('in 6 hours', $this->formatter->asRelativeTime($interval_6_hours)); + $this->assertSame('in a day', $this->formatter->asRelativeTime($interval_1_day)); + $this->assertSame('in 89 days', $this->formatter->asRelativeTime($interval_89_days)); + $this->assertSame('in a month', $this->formatter->asRelativeTime($interval_1_month)); + $this->assertSame('in 5 months', $this->formatter->asRelativeTime($interval_5_months)); + $this->assertSame('in a year', $this->formatter->asRelativeTime($interval_1_year)); + $this->assertSame('in 12 years', $this->formatter->asRelativeTime($interval_12_years)); + + // Pass a inverted DateInterval string + // $this->assertSame('in a year', $this->formatter->asRelativeTime('2008-05-11T15:30:00Z/2007-03-01T13:00:00Z')); + + // Force the reference time and pass a future DateTime + $dateNow = new DateTime('2014-03-13'); + $this->assertSame('in a second', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_second]), $dateNow)); + $this->assertSame('in 4 minutes', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_244_seconds]), $dateNow)); + $this->assertSame('in a minute', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_minute]), $dateNow)); + $this->assertSame('in 33 minutes', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_33_minutes]), $dateNow)); + $this->assertSame('in an hour', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_hour]), $dateNow)); + $this->assertSame('in 6 hours', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_6_hours]), $dateNow)); + $this->assertSame('in a day', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_day]), $dateNow)); + $this->assertSame('in 2 months', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_89_days]), $dateNow)); + $this->assertSame('in a month', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_month]), $dateNow)); + $this->assertSame('in 5 months', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_5_months]), $dateNow)); + $this->assertSame('in a year', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_year]), $dateNow)); + $this->assertSame('in 12 years', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_12_years]), $dateNow)); + + // Tricky 31-days month stuff + // See: http://www.gnu.org/software/tar/manual/html_section/Relative-items-in-date-strings.html + $dateNow = new DateTime('2014-03-03'); + $dateThen = new DateTime('2014-03-31'); + $this->assertSame('in a month', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-03', [$interval_1_month]), $dateNow)); + $this->assertSame('in 28 days', $this->formatter->asRelativeTime($dateThen, $dateNow)); + + // just now + $this->assertSame("just now", $this->formatter->asRelativeTime($t = time(), $t)); + $this->assertSame("just now", $this->formatter->asRelativeTime(0, 0)); + + // empty input + $this->assertSame("just now", $this->formatter->asRelativeTime(false, 0)); + $this->assertSame("just now", $this->formatter->asRelativeTime("", 0)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asRelativeTime(null)); + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asRelativeTime(null, time())); + } + + public function dateInputs() + { + return [ + ['2015-01-01 00:00:00', '2014-13-01 00:00:00'], + [false, 'asdfg', 'yii\base\InvalidParamException'], +// [(string)strtotime('now'), 'now'], // fails randomly + ]; + } + + /** + * @dataProvider dateInputs + */ + public function testIntlDateInput($expected, $value, $expectedException = null) + { + $this->testDateInput($expected, $value, $expectedException); + } + + /** + * @dataProvider dateInputs + */ + public function testDateInput($expected, $value, $expectedException = null) + { + if ($expectedException !== null) { + $this->setExpectedException($expectedException); + } + $this->assertSame($expected, $this->formatter->asDate($value, 'yyyy-MM-dd HH:mm:ss')); + $this->assertSame($expected, $this->formatter->asTime($value, 'yyyy-MM-dd HH:mm:ss')); + $this->assertSame($expected, $this->formatter->asDatetime($value, 'yyyy-MM-dd HH:mm:ss')); + } + + + public function provideTimezones() + { + return [ + ['UTC'], + ['Europe/Berlin'], + ['America/Jamaica'], + ]; + } + + /** + * provide default timezones times input date value + */ + public function provideTimesAndTz() + { + $utc = new \DateTimeZone('UTC'); + $berlin = new \DateTimeZone('Europe/Berlin'); + $result = []; + foreach($this->provideTimezones() as $tz) { + $result[] = [$tz[0], 1407674460, 1388580060]; + $result[] = [$tz[0], '2014-08-10 12:41:00', '2014-01-01 12:41:00']; + $result[] = [$tz[0], '2014-08-10 12:41:00 UTC', '2014-01-01 12:41:00 UTC']; + $result[] = [$tz[0], '2014-08-10 14:41:00 Europe/Berlin', '2014-01-01 13:41:00 Europe/Berlin']; + $result[] = [$tz[0], '2014-08-10 14:41:00 CEST', '2014-01-01 13:41:00 CET']; + $result[] = [$tz[0], '2014-08-10 14:41:00+0200', '2014-01-01 13:41:00+0100']; + $result[] = [$tz[0], '2014-08-10 14:41:00+02:00', '2014-01-01 13:41:00+01:00']; + $result[] = [$tz[0], '2014-08-10 14:41:00 +0200', '2014-01-01 13:41:00 +0100']; + $result[] = [$tz[0], '2014-08-10 14:41:00 +02:00', '2014-01-01 13:41:00 +01:00']; + $result[] = [$tz[0], '2014-08-10T14:41:00+02:00', '2014-01-01T13:41:00+01:00']; // ISO 8601 + $result[] = [$tz[0], new DateTime('2014-08-10 12:41:00', $utc), new DateTime('2014-01-01 12:41:00', $utc)]; + $result[] = [$tz[0], new DateTime('2014-08-10 14:41:00', $berlin), new DateTime('2014-01-01 13:41:00', $berlin)]; + if (version_compare(PHP_VERSION, '5.5.0', '>=')) { + $result[] = [$tz[0], new \DateTimeImmutable('2014-08-10 12:41:00', $utc), new \DateTimeImmutable('2014-01-01 12:41:00', $utc)]; + $result[] = [$tz[0], new \DateTimeImmutable('2014-08-10 14:41:00', $berlin), new \DateTimeImmutable('2014-01-01 13:41:00', $berlin)]; + } + } + return $result; + } + + /** + * Test timezones with input date and time in other timezones + * @dataProvider provideTimesAndTz + */ + public function testIntlTimezoneInput($defaultTz, $inputTimeDst, $inputTimeNonDst) + { + $this->testTimezoneInput($defaultTz, $inputTimeDst, $inputTimeNonDst); + } + + /** + * Test timezones with input date and time in other timezones + * @dataProvider provideTimesAndTz + */ + public function testTimezoneInput($defaultTz, $inputTimeDst, $inputTimeNonDst) + { + date_default_timezone_set($defaultTz); // formatting has to be independent of the default timezone set by PHP + $this->formatter->datetimeFormat = 'yyyy-MM-dd HH:mm:ss'; + $this->formatter->dateFormat = 'yyyy-MM-dd'; + $this->formatter->timeFormat = 'HH:mm:ss'; + + // daylight saving time + $this->formatter->timeZone = 'UTC'; + $this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime($inputTimeDst)); + $this->assertSame('2014-08-10', $this->formatter->asDate($inputTimeDst)); + $this->assertSame('12:41:00', $this->formatter->asTime($inputTimeDst)); + $this->assertSame('1407674460', $this->formatter->asTimestamp($inputTimeDst)); + $this->formatter->timeZone = 'Europe/Berlin'; + $this->assertSame('2014-08-10 14:41:00', $this->formatter->asDatetime($inputTimeDst)); + $this->assertSame('2014-08-10', $this->formatter->asDate($inputTimeDst)); + $this->assertSame('14:41:00', $this->formatter->asTime($inputTimeDst)); + $this->assertSame('1407674460', $this->formatter->asTimestamp($inputTimeDst)); + + // non daylight saving time + $this->formatter->timeZone = 'UTC'; + $this->assertSame('2014-01-01 12:41:00', $this->formatter->asDatetime($inputTimeNonDst)); + $this->assertSame('2014-01-01', $this->formatter->asDate($inputTimeNonDst)); + $this->assertSame('12:41:00', $this->formatter->asTime($inputTimeNonDst)); + $this->assertSame('1388580060', $this->formatter->asTimestamp($inputTimeNonDst)); + $this->formatter->timeZone = 'Europe/Berlin'; + $this->assertSame('2014-01-01 13:41:00', $this->formatter->asDatetime($inputTimeNonDst)); + $this->assertSame('2014-01-01', $this->formatter->asDate($inputTimeNonDst)); + $this->assertSame('13:41:00', $this->formatter->asTime($inputTimeNonDst)); + $this->assertSame('1388580060', $this->formatter->asTimestamp($inputTimeNonDst)); + + // tests for relative time + if ($inputTimeDst !== 1407674460 && !is_object($inputTimeDst)) { + $this->assertSame('3 hours ago', $this->formatter->asRelativeTime($inputTimeDst, $relativeTime = str_replace(['14:41', '12:41'], ['17:41', '15:41'], $inputTimeDst))); + $this->assertSame('in 3 hours', $this->formatter->asRelativeTime($relativeTime, $inputTimeDst)); + $this->assertSame('3 hours ago', $this->formatter->asRelativeTime($inputTimeNonDst, $relativeTime = str_replace(['13:41', '12:41'], ['16:41', '15:41'], $inputTimeNonDst))); + $this->assertSame('in 3 hours', $this->formatter->asRelativeTime($relativeTime, $inputTimeNonDst)); + } + } + + + /** + * Test timezones with input date and time in other timezones + */ + public function testTimezoneInputNonDefault() + { + $this->formatter->datetimeFormat = 'yyyy-MM-dd HH:mm:ss'; + $this->formatter->dateFormat = 'yyyy-MM-dd'; + $this->formatter->timeFormat = 'HH:mm:ss'; + + $this->formatter->timeZone = 'UTC'; + $this->formatter->defaultTimeZone = 'UTC'; + $this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00')); + $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00')); + $this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00')); + $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 12:41:00')); + + $this->assertSame('2014-08-10 10:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00 Europe/Berlin')); + $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00 Europe/Berlin')); + $this->assertSame('10:41:00', $this->formatter->asTime('2014-08-10 12:41:00 Europe/Berlin')); + $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00 Europe/Berlin')); + + $this->formatter->timeZone = 'Europe/Berlin'; + $this->formatter->defaultTimeZone = 'Europe/Berlin'; + $this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00')); + $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00')); + $this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00')); + $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00')); + + $this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00 Europe/Berlin')); + $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00 Europe/Berlin')); + $this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00 Europe/Berlin')); + $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00 Europe/Berlin')); + + $this->formatter->timeZone = 'UTC'; + $this->formatter->defaultTimeZone = 'Europe/Berlin'; + $this->assertSame('2014-08-10 10:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00')); + $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00')); + $this->assertSame('10:41:00', $this->formatter->asTime('2014-08-10 12:41:00')); + $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00')); + + $this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00 UTC')); + $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00 UTC')); + $this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00 UTC')); + $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 12:41:00 UTC')); + } + + + public function testDateOnlyValues() + { + date_default_timezone_set('Pacific/Kiritimati'); + // timzones with exactly 24h difference, ensure this test does not fail on a certain time + $this->formatter->defaultTimeZone = 'Pacific/Kiritimati'; // always UTC+14 + $this->formatter->timeZone = 'Pacific/Honolulu'; // always UTC-10 + + // when timezone conversion is made on this date, it will result in 2014-07-31 to be returned. + // ensure this does not happen on date only values + $this->assertSame('2014-08-01', $this->formatter->asDate('2014-08-01', 'yyyy-MM-dd')); + + date_default_timezone_set('Pacific/Honolulu'); + $this->formatter->defaultTimeZone = 'Pacific/Honolulu'; // always UTC-10 + $this->formatter->timeZone = 'Pacific/Kiritimati'; // always UTC+14 + $this->assertSame('2014-08-01', $this->formatter->asDate('2014-08-01', 'yyyy-MM-dd')); + } + + /** + * https://github.com/yiisoft/yii2/issues/6263 + * + * it is a PHP bug: https://bugs.php.net/bug.php?id=45543 + * Fixed in this commit: https://github.com/php/php-src/commit/22dba2f5f3211efe6c3b9bb24734c811ca64c68c#diff-7b738accc3d60f74c259da18588ddc5dL2996 + * Fixed in PHP >5.4.26 and >5.5.10. http://3v4l.org/mlZX7 + * + * @dataProvider provideTimezones + */ + public function testIssue6263($dtz) + { + $this->formatter->defaultTimeZone = $dtz; + + $this->formatter->timeZone = 'UTC'; + $this->assertEquals('24.11.2014 11:48:53', $this->formatter->format(1416829733, ['date', 'php:d.m.Y H:i:s'])); + $this->formatter->timeZone = 'Europe/Berlin'; + $this->assertEquals('24.11.2014 12:48:53', $this->formatter->format(1416829733, ['date', 'php:d.m.Y H:i:s'])); + + $this->assertFalse(DateTime::createFromFormat('Y-m-d', 1416829733)); + $this->assertFalse(DateTime::createFromFormat('Y-m-d', '2014-05-08 12:48:53')); + $this->assertFalse(DateTime::createFromFormat('Y-m-d H:i:s', 1416829733)); + $this->assertFalse(DateTime::createFromFormat('Y-m-d H:i:s', '2014-05-08')); + } + +} diff --git a/tests/framework/i18n/FormatterNumberTest.php b/tests/framework/i18n/FormatterNumberTest.php new file mode 100644 index 0000000..e07a392 --- /dev/null +++ b/tests/framework/i18n/FormatterNumberTest.php @@ -0,0 +1,509 @@ +mockApplication([ + 'timeZone' => 'UTC', + 'language' => 'ru-RU', + ]); + $this->formatter = new Formatter(['locale' => 'en-US']); + } + + protected function tearDown() + { + parent::tearDown(); + IntlTestHelper::resetIntlStatus(); + $this->formatter = null; + } + + /** + * Provides some configuration that should not affect Integer formatter + */ + public function differentConfigProvider() + { + // make this test not break when intl is not installed + if (!extension_loaded('intl')) { + return []; + } + + return [ + [[ + 'numberFormatterOptions' => [ + NumberFormatter::MIN_FRACTION_DIGITS => 2, + ], + ]], + [[ + 'numberFormatterOptions' => [ + NumberFormatter::MAX_FRACTION_DIGITS => 2, + ], + ]], + [[ + 'numberFormatterOptions' => [ + NumberFormatter::FRACTION_DIGITS => 2, + ], + ]], + [[ + 'numberFormatterOptions' => [ + NumberFormatter::MIN_FRACTION_DIGITS => 2, + NumberFormatter::MAX_FRACTION_DIGITS => 4, + ], + ]], + ]; + } + + + /** + * @dataProvider differentConfigProvider + */ + public function testIntlAsInteger($config) + { + // configure formatter with different configs that should not affect integer format + Yii::configure($this->formatter, $config); + $this->testAsInteger(); + } + + public function testAsInteger() + { + $this->assertSame("123", $this->formatter->asInteger(123)); + $this->assertSame("123", $this->formatter->asInteger(123.23)); + $this->assertSame("123", $this->formatter->asInteger(123.53)); + $this->assertSame("0", $this->formatter->asInteger(0)); + $this->assertSame("-123", $this->formatter->asInteger(-123.23)); + $this->assertSame("-123", $this->formatter->asInteger(-123.53)); + + $this->assertSame("123,456", $this->formatter->asInteger(123456)); + $this->assertSame("123,456", $this->formatter->asInteger(123456.789)); + + // empty input + $this->assertSame("0", $this->formatter->asInteger(false)); + $this->assertSame("0", $this->formatter->asInteger("")); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asInteger(null)); + } + + /** + * @expectedException \yii\base\InvalidParamException + */ + public function testAsIntegerException() + { + $this->formatter->asInteger('a'); + } + + /** + * @expectedException \yii\base\InvalidParamException + */ + public function testAsIntegerException2() + { + $this->formatter->asInteger('-123abc'); + } + + public function testIntlAsDecimal() + { + $value = 123.12; + $this->assertSame("123.12", $this->formatter->asDecimal($value, 2)); + $this->assertSame("123.1", $this->formatter->asDecimal($value, 1)); + $this->assertSame("123", $this->formatter->asDecimal($value, 0)); + + $value = 123; + $this->assertSame("123", $this->formatter->asDecimal($value)); + $this->assertSame("123.00", $this->formatter->asDecimal($value, 2)); + $this->formatter->decimalSeparator = ','; + $this->formatter->thousandSeparator = '.'; + $value = 123.12; + $this->assertSame("123,12", $this->formatter->asDecimal($value)); + $this->assertSame("123,1", $this->formatter->asDecimal($value, 1)); + $this->assertSame("123", $this->formatter->asDecimal($value, 0)); + $value = 123123.123; + $this->assertSame("123.123", $this->formatter->asDecimal($value, 0)); + $this->assertSame("123.123,12", $this->formatter->asDecimal($value, 2)); + $this->formatter->thousandSeparator = ''; + $this->assertSame("123123,1", $this->formatter->asDecimal($value, 1)); + $this->formatter->thousandSeparator = ' '; + $this->assertSame("12 31 23,1", $this->formatter->asDecimal($value, 1, [\NumberFormatter::GROUPING_SIZE => 2])); + + $value = 123123.123; + $this->formatter->decimalSeparator = ','; + $this->formatter->thousandSeparator = ' '; + $this->assertSame("123 123", $this->formatter->asDecimal($value, 0)); + $this->assertSame("123 123,12", $this->formatter->asDecimal($value, 2)); + + $this->formatter->decimalSeparator = null; + $this->formatter->thousandSeparator = null; + $value = '-123456.123'; + $this->assertSame("-123,456.123", $this->formatter->asDecimal($value)); + + // empty input + $this->assertSame("0", $this->formatter->asInteger(false)); + $this->assertSame("0", $this->formatter->asInteger("")); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDecimal(null)); + } + + public function testAsDecimal() + { + $value = 123.12; + $this->assertSame("123.12", $this->formatter->asDecimal($value)); + $this->assertSame("123.1", $this->formatter->asDecimal($value, 1)); + $this->assertSame("123", $this->formatter->asDecimal($value, 0)); + $value = 123; + $this->assertSame("123.00", $this->formatter->asDecimal($value)); + $this->formatter->decimalSeparator = ','; + $this->formatter->thousandSeparator = '.'; + $value = 123.12; + $this->assertSame("123,12", $this->formatter->asDecimal($value)); + $this->assertSame("123,1", $this->formatter->asDecimal($value, 1)); + $this->assertSame("123", $this->formatter->asDecimal($value, 0)); + $value = 123123.123; + $this->assertSame("123.123,12", $this->formatter->asDecimal($value)); + + $value = 123123.123; + $this->assertSame("123.123,12", $this->formatter->asDecimal($value)); + $this->assertSame("123.123,12", $this->formatter->asDecimal($value, 2)); + $this->formatter->decimalSeparator = ','; + $this->formatter->thousandSeparator = ' '; + $this->assertSame("123 123,12", $this->formatter->asDecimal($value)); + $this->assertSame("123 123,12", $this->formatter->asDecimal($value, 2)); + $this->formatter->thousandSeparator = ''; + $this->assertSame("123123,12", $this->formatter->asDecimal($value)); + $this->assertSame("123123,12", $this->formatter->asDecimal($value, 2)); + + $this->formatter->decimalSeparator = null; + $this->formatter->thousandSeparator = null; + $value = '-123456.123'; + $this->assertSame("-123,456.123", $this->formatter->asDecimal($value, 3)); + + // empty input + $this->assertSame("0", $this->formatter->asInteger(false)); + $this->assertSame("0", $this->formatter->asInteger("")); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDecimal(null)); + } + + public function testIntlAsPercent() + { + $this->testAsPercent(); + } + + public function testAsPercent() + { + $this->assertSame('12,300%', $this->formatter->asPercent(123)); + $this->assertSame('12,300%', $this->formatter->asPercent('123')); + $this->assertSame("12%", $this->formatter->asPercent(0.1234)); + $this->assertSame("12%", $this->formatter->asPercent('0.1234')); + $this->assertSame("-1%", $this->formatter->asPercent(-0.009343)); + $this->assertSame("-1%", $this->formatter->asPercent('-0.009343')); + + // empty input + $this->assertSame("0", $this->formatter->asInteger(false)); + $this->assertSame("0", $this->formatter->asInteger("")); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asPercent(null)); + } + + public function testIntlAsCurrency() + { + $this->formatter->locale = 'en-US'; + $this->assertSame('$123.00', $this->formatter->asCurrency('123')); + $this->assertSame('$123,456.00', $this->formatter->asCurrency('123456')); + $this->assertSame('$0.00', $this->formatter->asCurrency('0')); + + $this->formatter->locale = 'en-US'; + $this->formatter->currencyCode = 'USD'; + $this->assertSame('$123.00', $this->formatter->asCurrency('123')); + $this->assertSame('$123,456.00', $this->formatter->asCurrency('123456')); + $this->assertSame('$0.00', $this->formatter->asCurrency('0')); + // Starting from ICU 52.1, negative currency value will be formatted as -$123,456.12 + // see: http://source.icu-project.org/repos/icu/icu/tags/release-52-1/source/data/locales/en.txt +// $value = '-123456.123'; +// $this->assertSame("($123,456.12)", $this->formatter->asCurrency($value)); + + $this->formatter->locale = 'de-DE'; + $this->formatter->currencyCode = null; + $this->assertSame('123,00 €', $this->formatter->asCurrency('123')); + $this->formatter->currencyCode = 'USD'; + $this->assertSame('123,00 $', $this->formatter->asCurrency('123')); + $this->formatter->currencyCode = 'EUR'; + $this->assertSame('123,00 €', $this->formatter->asCurrency('123')); + + // empty input + $this->assertSame("0", $this->formatter->asInteger(false)); + $this->assertSame("0", $this->formatter->asInteger("")); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asCurrency(null)); + } + + /** + * https://github.com/yiisoft/yii2/pull/5261 + */ + public function testIntlIssue5261() + { + $this->formatter->locale = 'en-US'; + $this->formatter->numberFormatterOptions = [ + \NumberFormatter::FRACTION_DIGITS => 0 + ]; + $this->formatter->numberFormatterTextOptions = [ + \NumberFormatter::CURRENCY_CODE => 'EUR' + ]; + $this->assertSame('€100', $this->formatter->asCurrency(100, 'EUR')); + } + + public function testAsCurrency() + { + $this->formatter->currencyCode = 'USD'; + $this->assertSame('USD 123.00', $this->formatter->asCurrency('123')); + $this->assertSame('USD 0.00', $this->formatter->asCurrency('0')); + $this->assertSame('USD -123.45', $this->formatter->asCurrency('-123.45')); + $this->assertSame('USD -123.45', $this->formatter->asCurrency(-123.45)); + + $this->formatter->currencyCode = 'EUR'; + $this->assertSame('EUR 123.00', $this->formatter->asCurrency('123')); + $this->assertSame('EUR 0.00', $this->formatter->asCurrency('0')); + $this->assertSame('EUR -123.45', $this->formatter->asCurrency('-123.45')); + $this->assertSame('EUR -123.45', $this->formatter->asCurrency(-123.45)); + + // empty input + $this->assertSame("0", $this->formatter->asInteger(false)); + $this->assertSame("0", $this->formatter->asInteger("")); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asCurrency(null)); + } + + public function testIntlAsScientific() + { + $value = '123'; + $this->assertSame('1.23E2', $this->formatter->asScientific($value)); + $value = '123456'; + $this->assertSame("1.23456E5", $this->formatter->asScientific($value)); + $value = '-123456.123'; + $this->assertSame("-1.23456123E5", $this->formatter->asScientific($value)); + + // empty input + $this->assertSame("0", $this->formatter->asInteger(false)); + $this->assertSame("0", $this->formatter->asInteger("")); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asScientific(null)); + } + + public function testAsScientific() + { + $value = '123'; + $this->assertSame('1.23E+2', $this->formatter->asScientific($value, 2)); + $value = '123456'; + $this->assertSame("1.234560E+5", $this->formatter->asScientific($value)); + $value = '-123456.123'; + $this->assertSame("-1.234561E+5", $this->formatter->asScientific($value)); + + // empty input + $this->assertSame("0", $this->formatter->asInteger(false)); + $this->assertSame("0", $this->formatter->asInteger("")); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asScientific(null)); + } + + public function testIntlAsSpellout() + { + $this->assertSame('one hundred twenty-three', $this->formatter->asSpellout(123)); + + $this->formatter->locale = 'de_DE'; + $this->assertSame('ein­hundert­drei­und­zwanzig', $this->formatter->asSpellout(123)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asSpellout(null)); + } + + public function testIntlAsOrdinal() + { + $this->assertSame('0th', $this->formatter->asOrdinal(0)); + $this->assertSame('1st', $this->formatter->asOrdinal(1)); + $this->assertSame('2nd', $this->formatter->asOrdinal(2)); + $this->assertSame('3rd', $this->formatter->asOrdinal(3)); + $this->assertSame('5th', $this->formatter->asOrdinal(5)); + + $this->formatter->locale = 'de_DE'; + $this->assertSame('0.', $this->formatter->asOrdinal(0)); + $this->assertSame('1.', $this->formatter->asOrdinal(1)); + $this->assertSame('2.', $this->formatter->asOrdinal(2)); + $this->assertSame('3.', $this->formatter->asOrdinal(3)); + $this->assertSame('5.', $this->formatter->asOrdinal(5)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asOrdinal(null)); + } + + public function testIntlAsShortSize() + { + $this->formatter->numberFormatterOptions = [ + \NumberFormatter::MIN_FRACTION_DIGITS => 0, + \NumberFormatter::MAX_FRACTION_DIGITS => 2, + ]; + + // tests for base 1000 + $this->formatter->sizeFormatBase = 1000; + $this->assertSame("999 B", $this->formatter->asShortSize(999)); + $this->assertSame("999 B", $this->formatter->asShortSize('999')); + $this->assertSame("1.05 MB", $this->formatter->asShortSize(1024 * 1024)); + $this->assertSame("1 KB", $this->formatter->asShortSize(1000)); + $this->assertSame("1.02 KB", $this->formatter->asShortSize(1023)); + $this->assertNotEquals("3 PB", $this->formatter->asShortSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB + // tests for base 1024 + $this->formatter->sizeFormatBase = 1024; + $this->assertSame("1 KiB", $this->formatter->asShortSize(1024)); + $this->assertSame("1 MiB", $this->formatter->asShortSize(1024 * 1024)); + // https://github.com/yiisoft/yii2/issues/4960 + $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); + $this->assertSame("5 GiB", $this->formatter->asShortSize(5 * 1024 * 1024 * 1024)); + $this->assertNotEquals("5 PiB", $this->formatter->asShortSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB + //$this->assertSame("1 YiB", $this->formatter->asShortSize(pow(2, 80))); + $this->assertSame("2 GiB", $this->formatter->asShortSize(2147483647)); // round 1.999 up to 2 + $this->formatter->decimalSeparator = ','; + $this->formatter->numberFormatterOptions = []; + $this->assertSame("1,001 KiB", $this->formatter->asShortSize(1025, 3)); + + // empty values + $this->assertSame('0 B', $this->formatter->asShortSize(0)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asShortSize(null)); + } + + public function testAsShortSize() + { + // tests for base 1000 + $this->formatter->sizeFormatBase = 1000; + $this->assertSame("999 B", $this->formatter->asShortSize(999)); + $this->assertSame("999 B", $this->formatter->asShortSize('999')); + $this->assertSame("1.05 MB", $this->formatter->asShortSize(1024 * 1024)); + $this->assertSame("1.0486 MB", $this->formatter->asShortSize(1024 * 1024, 4)); + $this->assertSame("1.00 KB", $this->formatter->asShortSize(1000)); + $this->assertSame("1.02 KB", $this->formatter->asShortSize(1023)); + $this->assertNotEquals("3 PB", $this->formatter->asShortSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB + // tests for base 1024 + $this->formatter->sizeFormatBase = 1024; + $this->assertSame("1.00 KiB", $this->formatter->asShortSize(1024)); + $this->assertSame("1.00 MiB", $this->formatter->asShortSize(1024 * 1024)); + // https://github.com/yiisoft/yii2/issues/4960 + $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); + $this->assertSame("5.00 GiB", $this->formatter->asShortSize(5 * 1024 * 1024 * 1024)); + $this->assertNotEquals("5.00 PiB", $this->formatter->asShortSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB + //$this->assertSame("1 YiB", $this->formatter->asShortSize(pow(2, 80))); + $this->assertSame("2.00 GiB", $this->formatter->asShortSize(2147483647)); // round 1.999 up to 2 + $this->formatter->decimalSeparator = ','; + $this->assertSame("1,001 KiB", $this->formatter->asShortSize(1025, 3)); + + // empty values + $this->assertSame('0 B', $this->formatter->asShortSize(0)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asShortSize(null)); + } + + public function testIntlAsSize() + { + $this->formatter->numberFormatterOptions = [ + \NumberFormatter::MIN_FRACTION_DIGITS => 0, + \NumberFormatter::MAX_FRACTION_DIGITS => 2, + ]; + + // tests for base 1000 + $this->formatter->sizeFormatBase = 1000; + $this->assertSame("999 bytes", $this->formatter->asSize(999)); + $this->assertSame("999 bytes", $this->formatter->asSize('999')); + $this->assertSame("1.05 megabytes", $this->formatter->asSize(1024 * 1024)); + $this->assertSame("1 kilobyte", $this->formatter->asSize(1000)); + $this->assertSame("1.02 kilobytes", $this->formatter->asSize(1023)); + $this->assertSame("3 gigabytes", $this->formatter->asSize(3 * 1000 * 1000 * 1000)); + $this->assertNotEquals("3 PB", $this->formatter->asSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB + // tests for base 1024 + $this->formatter->sizeFormatBase = 1024; + $this->assertSame("1 kibibyte", $this->formatter->asSize(1024)); + $this->assertSame("1 mebibyte", $this->formatter->asSize(1024 * 1024)); + $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); + $this->assertSame("5 gibibytes", $this->formatter->asSize(5 * 1024 * 1024 * 1024)); + $this->assertNotEquals("5 pibibytes", $this->formatter->asSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB + $this->assertSame("2 gibibytes", $this->formatter->asSize(2147483647)); // round 1.999 up to 2 + $this->formatter->decimalSeparator = ','; + $this->formatter->numberFormatterOptions = []; + $this->assertSame("1,001 kibibytes", $this->formatter->asSize(1025, 3)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asSize(null)); + } + + public function testAsSize() + { + // tests for base 1000 + $this->formatter->sizeFormatBase = 1000; + $this->assertSame("999 bytes", $this->formatter->asSize(999)); + $this->assertSame("999 bytes", $this->formatter->asSize('999')); + $this->assertSame("1.05 megabytes", $this->formatter->asSize(1024 * 1024)); + $this->assertSame("1.0486 megabytes", $this->formatter->asSize(1024 * 1024, 4)); + $this->assertSame("1.00 kilobyte", $this->formatter->asSize(1000)); + $this->assertSame("1.02 kilobytes", $this->formatter->asSize(1023)); + $this->assertSame("3.00 gigabytes", $this->formatter->asSize(3 * 1000 * 1000 * 1000)); + $this->assertNotEquals("3 PB", $this->formatter->asSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB + // tests for base 1024 + $this->formatter->sizeFormatBase = 1024; + $this->assertSame("1.00 kibibyte", $this->formatter->asSize(1024)); + $this->assertSame("1.00 mebibyte", $this->formatter->asSize(1024 * 1024)); + $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); + $this->assertSame("5.00 gibibytes", $this->formatter->asSize(5 * 1024 * 1024 * 1024)); + $this->assertNotEquals("5.00 pibibytes", $this->formatter->asSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB + $this->assertSame("2.00 gibibytes", $this->formatter->asSize(2147483647)); // round 1.999 up to 2 + $this->formatter->decimalSeparator = ','; + $this->formatter->numberFormatterOptions = []; + $this->assertSame("1,001 kibibytes", $this->formatter->asSize(1025, 3)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asSize(null)); + } + + public function testIntlAsSizeConfiguration() + { + $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); + $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); + $this->formatter->thousandSeparator = '.'; + $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); + $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); + } + + /** + * https://github.com/yiisoft/yii2/issues/4960 + */ + public function testAsSizeConfiguration() + { + $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); + $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); + $this->formatter->thousandSeparator = '.'; + $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); + $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); + } +} diff --git a/tests/framework/i18n/FormatterTest.php b/tests/framework/i18n/FormatterTest.php new file mode 100644 index 0000000..4751d3b --- /dev/null +++ b/tests/framework/i18n/FormatterTest.php @@ -0,0 +1,194 @@ +mockApplication([ + 'timeZone' => 'UTC', + 'language' => 'ru-RU', + ]); + $this->formatter = new Formatter(['locale' => 'en-US']); + } + + protected function tearDown() + { + parent::tearDown(); + IntlTestHelper::resetIntlStatus(); + $this->formatter = null; + } + + + public function testFormat() + { + $value = time(); + $this->assertSame(date('M j, Y', $value), $this->formatter->format($value, 'date')); + $this->assertSame(date('M j, Y', $value), $this->formatter->format($value, 'DATE')); + $this->assertSame(date('Y/m/d', $value), $this->formatter->format($value, ['date', 'php:Y/m/d'])); + $this->setExpectedException('\yii\base\InvalidParamException'); + $this->assertSame(date('Y-m-d', $value), $this->formatter->format($value, 'data')); + } + + public function testLocale() + { + // locale is configured explicitly + $f = new Formatter(['locale' => 'en-US']); + $this->assertEquals('en-US', $f->locale); + + // if not, take from application + $f = new Formatter(); + $this->assertEquals('ru-RU', $f->locale); + } + + + public function testAsRaw() + { + $value = '123'; + $this->assertSame($value, $this->formatter->asRaw($value)); + $value = 123; + $this->assertSame($value, $this->formatter->asRaw($value)); + $value = '<>'; + $this->assertSame($value, $this->formatter->asRaw($value)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asRaw(null)); + } + + public function testAsText() + { + $value = '123'; + $this->assertSame($value, $this->formatter->asText($value)); + $value = 123; + $this->assertSame("$value", $this->formatter->asText($value)); + $value = '<>'; + $this->assertSame('<>', $this->formatter->asText($value)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asText(null)); + } + + public function testAsNtext() + { + $value = '123'; + $this->assertSame($value, $this->formatter->asNtext($value)); + $value = 123; + $this->assertSame("$value", $this->formatter->asNtext($value)); + $value = '<>'; + $this->assertSame('<>', $this->formatter->asNtext($value)); + $value = "123\n456"; + $this->assertSame("123
        \n456", $this->formatter->asNtext($value)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asNtext(null)); + } + + public function testAsParagraphs() + { + $value = '123'; + $this->assertSame("

        $value

        ", $this->formatter->asParagraphs($value)); + $value = 123; + $this->assertSame("

        $value

        ", $this->formatter->asParagraphs($value)); + $value = '<>'; + $this->assertSame('

        <>

        ', $this->formatter->asParagraphs($value)); + $value = "123\n456"; + $this->assertSame("

        123\n456

        ", $this->formatter->asParagraphs($value)); + $value = "123\n\n456"; + $this->assertSame("

        123

        \n

        456

        ", $this->formatter->asParagraphs($value)); + $value = "123\n\n\n456"; + $this->assertSame("

        123

        \n

        456

        ", $this->formatter->asParagraphs($value)); + $value = "123\r\n456"; + $this->assertSame("

        123\r\n456

        ", $this->formatter->asParagraphs($value)); + $value = "123\r\n\r\n456"; + $this->assertSame("

        123

        \n

        456

        ", $this->formatter->asParagraphs($value)); + $value = "123\r\n\r\n\r\n456"; + $this->assertSame("

        123

        \n

        456

        ", $this->formatter->asParagraphs($value)); + $value = "123\r456"; + $this->assertSame("

        123\r456

        ", $this->formatter->asParagraphs($value)); + $value = "123\r\r456"; + $this->assertSame("

        123

        \n

        456

        ", $this->formatter->asParagraphs($value)); + $value = "123\r\r\r456"; + $this->assertSame("

        123

        \n

        456

        ", $this->formatter->asParagraphs($value)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asParagraphs(null)); + } + + public function testAsHtml() + { + // todo: dependency on HtmlPurifier + } + + public function testAsEmail() + { + $value = 'test@sample.com'; + $this->assertSame("$value", $this->formatter->asEmail($value)); + $value = 'test@sample.com'; + $this->assertSame("$value", $this->formatter->asEmail($value, ['target' => '_blank'])); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asEmail(null)); + } + + public function testAsUrl() + { + $value = 'http://www.yiiframework.com/'; + $this->assertSame("$value", $this->formatter->asUrl($value)); + $value = 'https://www.yiiframework.com/'; + $this->assertSame("$value", $this->formatter->asUrl($value)); + $value = 'www.yiiframework.com/'; + $this->assertSame("$value", $this->formatter->asUrl($value)); + $value = 'https://www.yiiframework.com/?name=test&value=5"'; + $this->assertSame("https://www.yiiframework.com/?name=test&value=5"", $this->formatter->asUrl($value)); + $value = 'http://www.yiiframework.com/'; + $this->assertSame("$value", $this->formatter->asUrl($value, ['target' => '_blank'])); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asUrl(null)); + } + + public function testAsImage() + { + $value = 'http://sample.com/img.jpg'; + $this->assertSame("\"\"", $this->formatter->asImage($value)); + $value = 'http://sample.com/img.jpg'; + $alt = "Hello!"; + $this->assertSame("\"$alt\"", $this->formatter->asImage($value, ['alt' => $alt])); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asImage(null)); + } + + public function testAsBoolean() + { + $this->assertSame('Yes', $this->formatter->asBoolean(true)); + $this->assertSame('No', $this->formatter->asBoolean(false)); + $this->assertSame('Yes', $this->formatter->asBoolean("111")); + $this->assertSame('No', $this->formatter->asBoolean("")); + $this->assertSame('No', $this->formatter->asBoolean(0)); + + // null display + $this->assertSame($this->formatter->nullDisplay, $this->formatter->asBoolean(null)); + } +} diff --git a/tests/framework/i18n/GettextMessageSourceTest.php b/tests/framework/i18n/GettextMessageSourceTest.php new file mode 100644 index 0000000..cb586de --- /dev/null +++ b/tests/framework/i18n/GettextMessageSourceTest.php @@ -0,0 +1,16 @@ +markTestIncomplete(); + } +} diff --git a/tests/framework/i18n/GettextMoFileTest.php b/tests/framework/i18n/GettextMoFileTest.php new file mode 100644 index 0000000..b9ef897 --- /dev/null +++ b/tests/framework/i18n/GettextMoFileTest.php @@ -0,0 +1,98 @@ +load($moFilePath, 'context1'); + $context2 = $moFile->load($moFilePath, 'context2'); + + // item count + $this->assertCount(3, $context1); + $this->assertCount(2, $context2); + + // original messages + $this->assertArrayNotHasKey("Missing\n\r\t\"translation.", $context1); + $this->assertArrayHasKey("Aliquam tempus elit vel purus molestie placerat. In sollicitudin tincidunt\naliquet. Integer tincidunt gravida tempor. In convallis blandit dui vel malesuada.\nNunc vel sapien nunc, a pretium nulla.", $context1); + $this->assertArrayHasKey("String number two.", $context1); + $this->assertArrayHasKey("Nunc vel sapien nunc, a pretium nulla.\nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.", $context1); + + $this->assertArrayHasKey("The other\n\ncontext.\n", $context2); + $this->assertArrayHasKey("test1\\ntest2\n\\\ntest3", $context2); + + // translated messages + $this->assertFalse(in_array("", $context1)); + $this->assertTrue(in_array("Олицетворение однократно. Представленный лексико-семантический анализ является\nпсихолингвистическим в своей основе, но механизм сочленений полидисперсен. Впечатление\nоднократно. Различное расположение выбирает сюжетный механизм сочленений.", $context1)); + $this->assertTrue(in_array('Строка номер два.', $context1)); + $this->assertTrue(in_array('Короткий перевод.', $context1)); + + $this->assertTrue(in_array("Другой\n\nконтекст.\n", $context2)); + $this->assertTrue(in_array("тест1\\nтест2\n\\\nтест3", $context2)); + } + + public function testSave() + { + // initial data + $s = chr(4); + $messages = [ + 'Hello!' => 'Привет!', + "context1{$s}Hello?" => 'Привет?', + 'Hello!?' => '', + "context1{$s}Hello!?!" => '', + "context2{$s}\"Quotes\"" => '"Кавычки"', + "context2{$s}\nNew lines\n" => "\nПереносы строк\n", + "context2{$s}\tTabs\t" => "\tТабы\t", + "context2{$s}\rCarriage returns\r" => "\rВозвраты кареток\r", + ]; + + // create temporary directory and dump messages + $poFileDirectory = __DIR__ . '/../../runtime/i18n'; + if (!is_dir($poFileDirectory)) { + mkdir($poFileDirectory); + } + if (is_file($poFileDirectory . '/test.mo')) { + unlink($poFileDirectory . '/test.mo'); + } + + $moFile = new GettextMoFile(); + $moFile->save($poFileDirectory . '/test.mo', $messages); + + // load messages + $context1 = $moFile->load($poFileDirectory . '/test.mo', 'context1'); + $context2 = $moFile->load($poFileDirectory . '/test.mo', 'context2'); + + // context1 + $this->assertCount(2, $context1); + + $this->assertArrayHasKey('Hello?', $context1); + $this->assertTrue(in_array('Привет?', $context1)); + + $this->assertArrayHasKey('Hello!?!', $context1); + $this->assertTrue(in_array('', $context1)); + + // context2 + $this->assertCount(4, $context2); + + $this->assertArrayHasKey("\"Quotes\"", $context2); + $this->assertTrue(in_array('"Кавычки"', $context2)); + + $this->assertArrayHasKey("\nNew lines\n", $context2); + $this->assertTrue(in_array("\nПереносы строк\n", $context2)); + + $this->assertArrayHasKey("\tTabs\t", $context2); + $this->assertTrue(in_array("\tТабы\t", $context2)); + + $this->assertArrayHasKey("\rCarriage returns\r", $context2); + $this->assertTrue(in_array("\rВозвраты кареток\r", $context2)); + } +} diff --git a/tests/framework/i18n/GettextPoFileTest.php b/tests/framework/i18n/GettextPoFileTest.php new file mode 100644 index 0000000..42aa24a --- /dev/null +++ b/tests/framework/i18n/GettextPoFileTest.php @@ -0,0 +1,98 @@ +load($poFilePath, 'context1'); + $context2 = $poFile->load($poFilePath, 'context2'); + + // item count + $this->assertCount(4, $context1); + $this->assertCount(2, $context2); + + // original messages + $this->assertArrayHasKey("Missing\n\r\t\"translation.", $context1); + $this->assertArrayHasKey("Aliquam tempus elit vel purus molestie placerat. In sollicitudin tincidunt\naliquet. Integer tincidunt gravida tempor. In convallis blandit dui vel malesuada.\nNunc vel sapien nunc, a pretium nulla.", $context1); + $this->assertArrayHasKey("String number two.", $context1); + $this->assertArrayHasKey("Nunc vel sapien nunc, a pretium nulla.\nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.", $context1); + + $this->assertArrayHasKey("The other\n\ncontext.\n", $context2); + $this->assertArrayHasKey("test1\\\ntest2\n\\\\\ntest3", $context2); + + // translated messages + $this->assertTrue(in_array("", $context1)); + $this->assertTrue(in_array("Олицетворение однократно. Представленный лексико-семантический анализ является\nпсихолингвистическим в своей основе, но механизм сочленений полидисперсен. Впечатление\nоднократно. Различное расположение выбирает сюжетный механизм сочленений.", $context1)); + $this->assertTrue(in_array('Строка номер два.', $context1)); + $this->assertTrue(in_array('Короткий перевод.', $context1)); + + $this->assertTrue(in_array("Другой\n\nконтекст.\n", $context2)); + $this->assertTrue(in_array("тест1\\\nтест2\n\\\\\nтест3", $context2)); + } + + public function testSave() + { + // initial data + $s = chr(4); + $messages = [ + 'Hello!' => 'Привет!', + "context1{$s}Hello?" => 'Привет?', + 'Hello!?' => '', + "context1{$s}Hello!?!" => '', + "context2{$s}\"Quotes\"" => '"Кавычки"', + "context2{$s}\nNew lines\n" => "\nПереносы строк\n", + "context2{$s}\tTabs\t" => "\tТабы\t", + "context2{$s}\rCarriage returns\r" => "\rВозвраты кареток\r", + ]; + + // create temporary directory and dump messages + $poFileDirectory = __DIR__ . '/../../runtime/i18n'; + if (!is_dir($poFileDirectory)) { + mkdir($poFileDirectory); + } + if (is_file($poFileDirectory . '/test.po')) { + unlink($poFileDirectory . '/test.po'); + } + + $poFile = new GettextPoFile(); + $poFile->save($poFileDirectory . '/test.po', $messages); + + // load messages + $context1 = $poFile->load($poFileDirectory . '/test.po', 'context1'); + $context2 = $poFile->load($poFileDirectory . '/test.po', 'context2'); + + // context1 + $this->assertCount(2, $context1); + + $this->assertArrayHasKey('Hello?', $context1); + $this->assertTrue(in_array('Привет?', $context1)); + + $this->assertArrayHasKey('Hello!?!', $context1); + $this->assertTrue(in_array('', $context1)); + + // context2 + $this->assertCount(4, $context2); + + $this->assertArrayHasKey("\"Quotes\"", $context2); + $this->assertTrue(in_array('"Кавычки"', $context2)); + + $this->assertArrayHasKey("\nNew lines\n", $context2); + $this->assertTrue(in_array("\nПереносы строк\n", $context2)); + + $this->assertArrayHasKey("\tTabs\t", $context2); + $this->assertTrue(in_array("\tТабы\t", $context2)); + + $this->assertArrayHasKey("\rCarriage returns\r", $context2); + $this->assertTrue(in_array("\rВозвраты кареток\r", $context2)); + } +} diff --git a/tests/framework/i18n/I18NTest.php b/tests/framework/i18n/I18NTest.php new file mode 100644 index 0000000..f6c4d2c --- /dev/null +++ b/tests/framework/i18n/I18NTest.php @@ -0,0 +1,177 @@ + + * @since 2.0 + * @group i18n + */ +class I18NTest extends TestCase +{ + /** + * @var I18N + */ + public $i18n; + + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + $this->i18n = new I18N([ + 'translations' => [ + 'test' => new PhpMessageSource([ + 'basePath' => '@yiiunit/data/i18n/messages', + ]) + ] + ]); + } + + public function testTranslate() + { + $msg = 'The dog runs fast.'; + + // source = target. Should be returned as is. + $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', $msg, [], 'en')); + + // exact match + $this->assertEquals('Der Hund rennt schnell.', $this->i18n->translate('test', $msg, [], 'de-DE')); + + // fallback to just language code with absent exact match + $this->assertEquals('Собака бегает быстро.', $this->i18n->translate('test', $msg, [], 'ru-RU')); + + // fallback to just langauge code with present exact match + $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); + } + + public function testDefaultSource() + { + $i18n = new I18N([ + 'translations' => [ + '*' => new PhpMessageSource([ + 'basePath' => '@yiiunit/data/i18n/messages', + 'fileMap' => [ + 'test' => 'test.php', + 'foo' => 'test.php', + ], + ]) + ] + ]); + + $msg = 'The dog runs fast.'; + + // source = target. Should be returned as is. + $this->assertEquals($msg, $i18n->translate('test', $msg, [], 'en')); + + // exact match + $this->assertEquals('Der Hund rennt schnell.', $i18n->translate('test', $msg, [], 'de-DE')); + $this->assertEquals('Der Hund rennt schnell.', $i18n->translate('foo', $msg, [], 'de-DE')); + $this->assertEquals($msg, $i18n->translate('bar', $msg, [], 'de-DE')); + + // fallback to just language code with absent exact match + $this->assertEquals('Собака бегает быстро.', $i18n->translate('test', $msg, [], 'ru-RU')); + + // fallback to just langauge code with present exact match + $this->assertEquals('Hallo Welt!', $i18n->translate('test', 'Hello world!', [], 'de-DE')); + } + + public function testTranslateParams() + { + $msg = 'His speed is about {n} km/h.'; + $params = ['n' => 42]; + $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en-US')); + $this->assertEquals('Seine Geschwindigkeit beträgt 42 km/h.', $this->i18n->translate('test', $msg, $params, 'de-DE')); + } + + public function testTranslateParams2() + { + if (!extension_loaded("intl")) { + $this->markTestSkipped("intl not installed. Skipping."); + } + $msg = 'His name is {name} and his speed is about {n, number} km/h.'; + $params = [ + 'n' => 42, + 'name' => 'DA VINCI', // http://petrix.com/dognames/d.html + ]; + $this->assertEquals('His name is DA VINCI and his speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en-US')); + $this->assertEquals('Er heißt DA VINCI und ist 42 km/h schnell.', $this->i18n->translate('test', $msg, $params, 'de-DE')); + } + + public function testSpecialParams() + { + $msg = 'His speed is about {0} km/h.'; + + $this->assertEquals('His speed is about 0 km/h.', $this->i18n->translate('test', $msg, 0, 'en-US')); + $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, 42, 'en-US')); + $this->assertEquals('His speed is about {0} km/h.', $this->i18n->translate('test', $msg, null, 'en-US')); + $this->assertEquals('His speed is about {0} km/h.', $this->i18n->translate('test', $msg, [], 'en-US')); + } + + /** + * When translation is missing source language should be used for formatting. + * https://github.com/yiisoft/yii2/issues/2209 + */ + public function testMissingTranslationFormatting() + { + $this->assertEquals('1 item', $this->i18n->translate('test', '{0, number} {0, plural, one{item} other{items}}', 1, 'hu')); + } + + /** + * https://github.com/yiisoft/yii2/issues/7093 + */ + public function testRussianPlurals() + { + $this->assertEquals('На диване лежит 6 кошек!', $this->i18n->translate('test', 'There {n, plural, =0{no cats} =1{one cat} other{are # cats}} on lying on the sofa!', ['n' => 6], 'ru')); + } + + public function testUsingSourceLanguageForMissingTranslation() + { + \Yii::$app->sourceLanguage = 'ru'; + \Yii::$app->language = 'en'; + + $msg = '{n, plural, =0{Нет комментариев} =1{# комментарий} one{# комментарий} few{# комментария} many{# комментариев} other{# комментария}}'; + $this->assertEquals('5 комментариев', \Yii::t('app', $msg, ['n' => 5])); + $this->assertEquals('3 комментария', \Yii::t('app', $msg, ['n' => 3])); + $this->assertEquals('1 комментарий', \Yii::t('app', $msg, ['n' => 1])); + $this->assertEquals('21 комментарий', \Yii::t('app', $msg, ['n' => 21])); + $this->assertEquals('Нет комментариев', \Yii::t('app', $msg, ['n' => 0])); + } + + /** + * https://github.com/yiisoft/yii2/issues/2519 + */ + public function testMissingTranslationEvent() + { + $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); + $this->assertEquals('Missing translation message.', $this->i18n->translate('test', 'Missing translation message.', [], 'de-DE')); + $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); + + Event::on(PhpMessageSource::className(), PhpMessageSource::EVENT_MISSING_TRANSLATION, function ($event) {}); + $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); + $this->assertEquals('Missing translation message.', $this->i18n->translate('test', 'Missing translation message.', [], 'de-DE')); + $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); + Event::off(PhpMessageSource::className(), PhpMessageSource::EVENT_MISSING_TRANSLATION); + + Event::on(PhpMessageSource::className(), PhpMessageSource::EVENT_MISSING_TRANSLATION, function ($event) { + if ($event->message == 'New missing translation message.') { + $event->translatedMessage = 'TRANSLATION MISSING HERE!'; + } + }); + $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); + $this->assertEquals('Another missing translation message.', $this->i18n->translate('test', 'Another missing translation message.', [], 'de-DE')); + $this->assertEquals('Missing translation message.', $this->i18n->translate('test', 'Missing translation message.', [], 'de-DE')); + $this->assertEquals('TRANSLATION MISSING HERE!', $this->i18n->translate('test', 'New missing translation message.', [], 'de-DE')); + $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); + Event::off(PhpMessageSource::className(), PhpMessageSource::EVENT_MISSING_TRANSLATION); + } +} diff --git a/tests/framework/i18n/IntlTestHelper.php b/tests/framework/i18n/IntlTestHelper.php new file mode 100644 index 0000000..d9a4eb7 --- /dev/null +++ b/tests/framework/i18n/IntlTestHelper.php @@ -0,0 +1,77 @@ +getName(false), 'testIntl', 8) === 0) { + if (!extension_loaded('intl')) { + $test->markTestSkipped('intl extension is not installed.'); + } + static::$enableIntl = true; + } else { + static::$enableIntl = false; + } + } + + public static function resetIntlStatus() + { + static::$enableIntl = null; + } + } +} + +namespace yii\i18n { + use yiiunit\framework\i18n\IntlTestHelper; + + if (!function_exists('yii\i18n\extension_loaded')) { + function extension_loaded($name) + { + if ($name === 'intl' && IntlTestHelper::$enableIntl !== null) { + return IntlTestHelper::$enableIntl; + } + return \extension_loaded($name); + } + } +} + +namespace yii\helpers { + use yiiunit\framework\i18n\IntlTestHelper; + + if (!function_exists('yii\helpers\extension_loaded')) { + function extension_loaded($name) + { + if ($name === 'intl' && IntlTestHelper::$enableIntl !== null) { + return IntlTestHelper::$enableIntl; + } + return \extension_loaded($name); + } + } +} + +namespace yii\validators { + use yiiunit\framework\i18n\IntlTestHelper; + + if (!function_exists('yii\validators\extension_loaded')) { + function extension_loaded($name) + { + if ($name === 'intl' && IntlTestHelper::$enableIntl !== null) { + return IntlTestHelper::$enableIntl; + } + return \extension_loaded($name); + } + } +} diff --git a/tests/framework/i18n/MessageFormatterTest.php b/tests/framework/i18n/MessageFormatterTest.php new file mode 100644 index 0000000..85f0c52 --- /dev/null +++ b/tests/framework/i18n/MessageFormatterTest.php @@ -0,0 +1,337 @@ + + * @since 2.0 + * @group i18n + */ +class MessageFormatterTest extends TestCase +{ + const N = 'n'; + const N_VALUE = 42; + const SUBJECT = 'сабж'; + const SUBJECT_VALUE = 'Answer to the Ultimate Question of Life, the Universe, and Everything'; + + public function patterns() + { + return [ + [ + '{'.self::SUBJECT.'} is {'.self::N.', number}', // pattern + self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected + [ // params + self::N => self::N_VALUE, + self::SUBJECT => self::SUBJECT_VALUE, + ] + ], + + [ + '{'.self::SUBJECT.'} is {'.self::N.', number, integer}', // pattern + self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected + [ // params + self::N => self::N_VALUE, + self::SUBJECT => self::SUBJECT_VALUE, + ] + ], + + // This one was provided by Aura.Intl. Thanks! + [<<<_MSG_ +{gender_of_host, select, + female {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to her party.} + =2 {{host} invites {guest} and one other person to her party.} + other {{host} invites {guest} and # other people to her party.}}} + male {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to his party.} + =2 {{host} invites {guest} and one other person to his party.} + other {{host} invites {guest} and # other people to his party.}}} + other {{num_guests, plural, offset:1 + =0 {{host} does not give a party.} + =1 {{host} invites {guest} to their party.} + =2 {{host} invites {guest} and one other person to their party.} + other {{host} invites {guest} and # other people to their party.}}}} +_MSG_ + , + 'ralph invites beep and 3 other people to his party.', + [ + 'gender_of_host' => 'male', + 'num_guests' => 4, + 'host' => 'ralph', + 'guest' => 'beep' + ], + defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.8', '<'), + 'select format is available in ICU > 4.4 and plural format with =X selector is avilable since 4.8' + ], + + [ + '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', + 'Alexander is male and he loves Yii!', + [ + 'name' => 'Alexander', + 'gender' => 'male', + ], + defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), + 'select format is available in ICU > 4.4' + ], + + // verify pattern in select does not get replaced + [ + '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', + 'Alexander is male and he loves Yii!', + [ + 'name' => 'Alexander', + 'gender' => 'male', + // following should not be replaced + 'he' => 'wtf', + 'she' => 'wtf', + 'it' => 'wtf', + ], + defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), + 'select format is available in ICU > 4.4' + ], + + // verify pattern in select message gets replaced + [ + '{name} is {gender} and {gender, select, female{she} male{{he}} other{it}} loves Yii!', + 'Alexander is male and wtf loves Yii!', + [ + 'name' => 'Alexander', + 'gender' => 'male', + 'he' => 'wtf', + 'she' => 'wtf', + ], + defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.8', '<'), + 'parameters in select format do not seem to work in ICU < 4.8' + ], + + // some parser specific verifications + [ + '{gender} and {gender, select, female{she} male{{he}} other{it}} loves {nr, number} is {gender}!', + 'male and wtf loves 42 is male!', + [ + 'nr' => 42, + 'gender' => 'male', + 'he' => 'wtf', + 'she' => 'wtf', + ], + defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), + 'select format is available in ICU > 4.4' + ], + + // test ICU version compatibility + [ + 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', + 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', + [], + ], + [ + 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', + 'Showing 1-10 of 12 items.', + [// A + 'begin' => 1, + 'end' => 10, + 'count' => 10, + 'totalCount' => 12, + 'page' => 1, + 'pageCount' => 2, + ] + ], + [ + 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', + 'Showing 1-1 of 1 item.', + [// B + 'begin' => 1, + 'end' => 1, + 'count' => 1, + 'totalCount' => 1, + 'page' => 1, + 'pageCount' => 1, + ] + ], + [ + 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', + 'Showing 0-0 of 0 items.', + [// C + 'begin' => 0, + 'end' => 0, + 'count' => 0, + 'totalCount' => 0, + 'page' => 1, + 'pageCount' => 1, + ] + ], + [ + 'Total {count, number} {count, plural, one{item} other{items}}.', + 'Total {count, number} {count, plural, one{item} other{items}}.', + [] + ], + [ + 'Total {count, number} {count, plural, one{item} other{items}}.', + 'Total 1 item.', + [ + 'count' => 1, + ] + ], + [ + 'Total {count, number} {count, plural, one{item} other{items}}.', + 'Total 1 item.', + [ + 'begin' => 5, + 'count' => 1, + 'end' => 10, + ] + ], + [ + '{0, plural, one {offer} other {offers}}', + '{0, plural, one {offer} other {offers}}', + [], + ], + [ + '{0, plural, one {offer} other {offers}}', + 'offers', + [0], + ], + [ + '{0, plural, one {offer} other {offers}}', + 'offer', + [1], + ], + [ + '{0, plural, one {offer} other {offers}}', + 'offers', + [13], + ], + ]; + } + + public function parsePatterns() + { + return [ + [ + self::SUBJECT_VALUE.' is {0, number}', // pattern + self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected + [ // params + 0 => self::N_VALUE, + ] + ], + + [ + self::SUBJECT_VALUE.' is {'.self::N.', number}', // pattern + self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected + [ // params + self::N => self::N_VALUE, + ] + ], + + [ + self::SUBJECT_VALUE.' is {'.self::N.', number, integer}', // pattern + self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected + [ // params + self::N => self::N_VALUE, + ] + ], + + [ + "{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree", + "4,560 monkeys on 123 trees make 37.073 monkeys per tree", + [ + 0 => 4560, + 1 => 123, + 2 => 37.073 + ], + 'en-US' + ], + + [ + "{0,number,integer} Affen auf {1,number,integer} Bäumen sind {2,number} Affen pro Baum", + "4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum", + [ + 0 => 4560, + 1 => 123, + 2 => 37.073 + ], + 'de', + ], + + [ + "{monkeyCount,number,integer} monkeys on {trees,number,integer} trees make {monkeysPerTree,number} monkeys per tree", + "4,560 monkeys on 123 trees make 37.073 monkeys per tree", + [ + 'monkeyCount' => 4560, + 'trees' => 123, + 'monkeysPerTree' => 37.073 + ], + 'en-US' + ], + + [ + "{monkeyCount,number,integer} Affen auf {trees,number,integer} Bäumen sind {monkeysPerTree,number} Affen pro Baum", + "4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum", + [ + 'monkeyCount' => 4560, + 'trees' => 123, + 'monkeysPerTree' => 37.073 + ], + 'de', + ], + ]; + } + + /** + * @dataProvider patterns + */ + public function testNamedArguments($pattern, $expected, $args, $skip = false, $skipMessage = '') + { + if ($skip) { + $this->markTestSkipped($skipMessage); + } + $formatter = new MessageFormatter(); + $result = $formatter->format($pattern, $args, 'en-US'); + $this->assertEquals($expected, $result, $formatter->getErrorMessage()); + } + + /** + * @dataProvider parsePatterns + */ + public function testParseNamedArguments($pattern, $expected, $args, $locale = 'en-US') + { + if (!extension_loaded("intl")) { + $this->markTestSkipped("intl not installed. Skipping."); + } + + $formatter = new MessageFormatter(); + $result = $formatter->parse($pattern, $expected, $locale); + $this->assertEquals($args, $result, $formatter->getErrorMessage() . ' Pattern: ' . $pattern); + } + + public function testInsufficientArguments() + { + $expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; + + $formatter = new MessageFormatter(); + $result = $formatter->format('{'.self::SUBJECT.'} is {'.self::N.', number}', [ + self::N => self::N_VALUE, + ], 'en-US'); + + $this->assertEquals($expected, $result, $formatter->getErrorMessage()); + } + + public function testNoParams() + { + $pattern = '{'.self::SUBJECT.'} is '.self::N; + $formatter = new MessageFormatter(); + $result = $formatter->format($pattern, [], 'en-US'); + $this->assertEquals($pattern, $result, $formatter->getErrorMessage()); + } +} diff --git a/tests/framework/log/DbTargetTest.php b/tests/framework/log/DbTargetTest.php new file mode 100644 index 0000000..5ff7fe8 --- /dev/null +++ b/tests/framework/log/DbTargetTest.php @@ -0,0 +1,142 @@ + 'Migrator', + 'basePath' => '@yiiunit', + 'controllerMap' => [ + 'migrate' => EchoMigrateController::className(), + ], + 'components' => [ + 'db' => static::getConnection(), + 'log' => [ + 'targets' => [ + [ + 'class' => 'yii\log\DbTarget', + 'levels' => ['warning'], + 'logTable' => self::$logTable, + ], + ], + ], + ], + ]); + } + + ob_start(); + $result = Yii::$app->runAction($route, $params); + echo "Result is " . $result; + if ($result !== \yii\console\Controller::EXIT_CODE_NORMAL) { + ob_end_flush(); + } else { + ob_end_clean(); + } + } + + public static function setUpBeforeClass() + { + parent::setUpBeforeClass(); + $databases = static::getParam('databases'); + static::$database = $databases[static::$driverName]; + $pdo_database = 'pdo_' . static::$driverName; + + if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) { + static::markTestSkipped('pdo and ' . $pdo_database . ' extension are required.'); + } + + static::runConsoleAction('migrate/up', ['migrationPath' => '@yii/log/migrations/', 'interactive' => false]); + } + + public static function tearDownAfterClass() + { + static::runConsoleAction('migrate/down', ['migrationPath' => '@yii/log/migrations/', 'interactive' => false]); + if (static::$db) { + static::$db->close(); + } + Yii::$app = null; + parent::tearDownAfterClass(); + } + + protected function tearDown() + { + parent::tearDown(); + self::getConnection()->createCommand()->truncateTable(self::$logTable)->execute(); + } + + /** + * @throws \yii\base\InvalidParamException + * @throws \yii\db\Exception + * @throws \yii\base\InvalidConfigException + * @return \yii\db\Connection + */ + public static function getConnection() + { + if (static::$db == null) { + $db = new Connection; + $db->dsn = static::$database['dsn']; + if (isset(static::$database['username'])) { + $db->username = static::$database['username']; + $db->password = static::$database['password']; + } + if (isset(static::$database['attributes'])) { + $db->attributes = static::$database['attributes']; + } + if (!$db->isActive) { + $db->open(); + } + static::$db = $db; + } + return static::$db; + } + + /** + * Tests that precision isn't lost for log timestamps + * @see https://github.com/yiisoft/yii2/issues/7384 + */ + public function testTimestamp() + { + $logger = Yii::getLogger(); + + $time = 1424865393.0105; + + // forming message data manually in order to set time + $messsageData = [ + 'test', + Logger::LEVEL_WARNING, + 'test', + $time, + [] + ]; + + $logger->messages[] = $messsageData; + $logger->flush(true); + + $query = (new Query())->select('log_time')->from(self::$logTable)->where(['category' => 'test']); + $loggedTime = $query->createCommand(self::getConnection())->queryScalar(); + static::assertEquals($time, $loggedTime); + } +} \ No newline at end of file diff --git a/tests/framework/log/FileTargetTest.php b/tests/framework/log/FileTargetTest.php new file mode 100644 index 0000000..122fdee --- /dev/null +++ b/tests/framework/log/FileTargetTest.php @@ -0,0 +1,105 @@ + + */ + +namespace yiiunit\framework\log; + +use yii\helpers\FileHelper; +use yii\log\Dispatcher; +use yii\log\Logger; +use Yii; +use yiiunit\TestCase; + +/** + * @group log + */ +class FileTargetTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + + public function booleanDataProvider() + { + return [ + [true], + [false] + ]; + } + + /** + * @dataProvider booleanDataProvider + */ + public function testRotate($rotateByCopy) + { + $logFile = Yii::getAlias('@yiiunit/runtime/log/filetargettest.log'); + FileHelper::removeDirectory(dirname($logFile)); + mkdir(dirname($logFile), 0777, true); + + $logger = new Logger(); + $dispatcher = new Dispatcher([ + 'logger' => $logger, + 'targets' => [ + 'file' => [ + 'class' => 'yii\log\FileTarget', + 'logFile' => $logFile, + 'levels' => ['warning'], + 'maxFileSize' => 1024, // 1 MB + 'maxLogFiles' => 1, // one file for rotation and one normal log file + 'logVars' => [], + 'rotateByCopy' => $rotateByCopy + ] + ] + ]); + + // one file + + $logger->log(str_repeat('x', 1024), Logger::LEVEL_WARNING); + $logger->flush(true); + + clearstatcache(); + + $this->assertTrue(file_exists($logFile)); + $this->assertFalse(file_exists($logFile . '.1')); + $this->assertFalse(file_exists($logFile . '.2')); + $this->assertFalse(file_exists($logFile . '.3')); + $this->assertFalse(file_exists($logFile . '.4')); + + // exceed max size + for($i = 0; $i < 1024; $i++) { + $logger->log(str_repeat('x', 1024), Logger::LEVEL_WARNING); + } + $logger->flush(true); + + // first rotate + + $logger->log(str_repeat('x', 1024), Logger::LEVEL_WARNING); + $logger->flush(true); + + clearstatcache(); + + $this->assertTrue(file_exists($logFile)); + $this->assertTrue(file_exists($logFile . '.1')); + $this->assertFalse(file_exists($logFile . '.2')); + $this->assertFalse(file_exists($logFile . '.3')); + $this->assertFalse(file_exists($logFile . '.4')); + + // second rotate + + for($i = 0; $i < 1024; $i++) { + $logger->log(str_repeat('x', 1024), Logger::LEVEL_WARNING); + } + $logger->flush(true); + + clearstatcache(); + + $this->assertTrue(file_exists($logFile)); + $this->assertTrue(file_exists($logFile . '.1')); + $this->assertFalse(file_exists($logFile . '.2')); + $this->assertFalse(file_exists($logFile . '.3')); + $this->assertFalse(file_exists($logFile . '.4')); + } +} \ No newline at end of file diff --git a/tests/framework/log/LoggerTest.php b/tests/framework/log/LoggerTest.php new file mode 100644 index 0000000..44fd5b4 --- /dev/null +++ b/tests/framework/log/LoggerTest.php @@ -0,0 +1,33 @@ + + */ + +namespace yiiunit\framework\log; + +use yii\log\Logger; +use yiiunit\TestCase; + +/** + * @group log + */ +class LoggerTest extends TestCase +{ + + public function testLog() + { + $logger = new Logger(); + + $logger->log('test1', Logger::LEVEL_INFO); + $this->assertEquals(1, count($logger->messages)); + $this->assertEquals('test1', $logger->messages[0][0]); + $this->assertEquals(Logger::LEVEL_INFO, $logger->messages[0][1]); + $this->assertEquals('application', $logger->messages[0][2]); + + $logger->log('test2', Logger::LEVEL_ERROR, 'category'); + $this->assertEquals(2, count($logger->messages)); + $this->assertEquals('test2', $logger->messages[1][0]); + $this->assertEquals(Logger::LEVEL_ERROR, $logger->messages[1][1]); + $this->assertEquals('category', $logger->messages[1][2]); + } +} diff --git a/tests/framework/log/MySQLTargetTest.php b/tests/framework/log/MySQLTargetTest.php new file mode 100644 index 0000000..fd5e242 --- /dev/null +++ b/tests/framework/log/MySQLTargetTest.php @@ -0,0 +1,10 @@ + + */ + +namespace yiiunit\framework\log; + +use yii\log\Dispatcher; +use yii\log\Logger; +use yii\log\Target; +use yiiunit\TestCase; + +/** + * @group log + */ +class TargetTest extends TestCase +{ + public static $messages; + + public function filters() + { + return [ + [[], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']], + + [['levels' => 0], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']], + [ + ['levels' => Logger::LEVEL_INFO | Logger::LEVEL_WARNING | Logger::LEVEL_ERROR | Logger::LEVEL_TRACE], + ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] + ], + [['levels' => ['error']], ['B', 'G', 'H']], + [['levels' => Logger::LEVEL_ERROR], ['B', 'G', 'H']], + [['levels' => ['error', 'warning']], ['B', 'C', 'G', 'H']], + [['levels' => Logger::LEVEL_ERROR | Logger::LEVEL_WARNING], ['B', 'C', 'G', 'H']], + + [['categories' => ['application']], ['A', 'B', 'C', 'D', 'E']], + [['categories' => ['application*']], ['A', 'B', 'C', 'D', 'E', 'F']], + [['categories' => ['application.*']], ['F']], + [['categories' => ['application.components']], []], + [['categories' => ['application.components.Test']], ['F']], + [['categories' => ['application.components.*']], ['F']], + [['categories' => ['application.*', 'yii.db.*']], ['F', 'G', 'H']], + [['categories' => ['application.*', 'yii.db.*'], 'except' => ['yii.db.Command.*']], ['F', 'G']], + + [['categories' => ['application', 'yii.db.*'], 'levels' => Logger::LEVEL_ERROR], ['B', 'G', 'H']], + [['categories' => ['application'], 'levels' => Logger::LEVEL_ERROR], ['B']], + [['categories' => ['application'], 'levels' => Logger::LEVEL_ERROR | Logger::LEVEL_WARNING], ['B', 'C']], + ]; + } + + /** + * @dataProvider filters + */ + public function testFilter($filter, $expected) + { + static::$messages = []; + + $logger = new Logger; + $dispatcher = new Dispatcher([ + 'logger' => $logger, + 'targets' => [new TestTarget(array_merge($filter, ['logVars' => []]))], + 'flushInterval' => 1, + ]); + $logger->log('testA', Logger::LEVEL_INFO); + $logger->log('testB', Logger::LEVEL_ERROR); + $logger->log('testC', Logger::LEVEL_WARNING); + $logger->log('testD', Logger::LEVEL_TRACE); + $logger->log('testE', Logger::LEVEL_INFO, 'application'); + $logger->log('testF', Logger::LEVEL_INFO, 'application.components.Test'); + $logger->log('testG', Logger::LEVEL_ERROR, 'yii.db.Command'); + $logger->log('testH', Logger::LEVEL_ERROR, 'yii.db.Command.whatever'); + + $this->assertEquals(count($expected), count(static::$messages)); + $i = 0; + foreach ($expected as $e) { + $this->assertEquals('test' . $e, static::$messages[$i++][0]); + } + } +} + +class TestTarget extends Target +{ + public $exportInterval = 1; + + /** + * Exports log [[messages]] to a specific destination. + * Child classes must implement this method. + */ + public function export() + { + TargetTest::$messages = array_merge(TargetTest::$messages, $this->messages); + $this->messages = []; + } +} diff --git a/tests/framework/mail/BaseMailerTest.php b/tests/framework/mail/BaseMailerTest.php new file mode 100644 index 0000000..b6d166f --- /dev/null +++ b/tests/framework/mail/BaseMailerTest.php @@ -0,0 +1,449 @@ +mockApplication([ + 'components' => [ + 'mailer' => $this->createTestMailComponent(), + ] + ]); + $filePath = $this->getTestFilePath(); + if (!file_exists($filePath)) { + FileHelper::createDirectory($filePath); + } + } + + public function tearDown() + { + $filePath = $this->getTestFilePath(); + if (file_exists($filePath)) { + FileHelper::removeDirectory($filePath); + } + } + + /** + * @return string test file path. + */ + protected function getTestFilePath() + { + return Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . basename(get_class($this)) . '_' . getmypid(); + } + + /** + * @return Mailer test email component instance. + */ + protected function createTestMailComponent() + { + $component = new Mailer(); + $component->viewPath = $this->getTestFilePath(); + + return $component; + } + + /** + * @return Mailer mailer instance + */ + protected function getTestMailComponent() + { + return Yii::$app->get('mailer'); + } + + // Tests : + + public function testSetupView() + { + $mailer = new Mailer(); + + $view = new View(); + $mailer->setView($view); + $this->assertEquals($view, $mailer->getView(), 'Unable to setup view!'); + + $viewConfig = [ + 'params' => [ + 'param1' => 'value1', + 'param2' => 'value2', + ] + ]; + $mailer->setView($viewConfig); + $view = $mailer->getView(); + $this->assertTrue(is_object($view), 'Unable to setup view via config!'); + $this->assertEquals($viewConfig['params'], $view->params, 'Unable to configure view via config array!'); + } + + /** + * @depends testSetupView + */ + public function testGetDefaultView() + { + $mailer = new Mailer(); + $view = $mailer->getView(); + $this->assertTrue(is_object($view), 'Unable to get default view!'); + } + + public function testCreateMessage() + { + $mailer = new Mailer(); + $message = $mailer->compose(); + $this->assertTrue(is_object($message), 'Unable to create message instance!'); + $this->assertEquals($mailer->messageClass, get_class($message), 'Invalid message class!'); + } + + /** + * @depends testCreateMessage + */ + public function testDefaultMessageConfig() + { + $mailer = new Mailer(); + + $notPropertyConfig = [ + 'charset' => 'utf-16', + 'from' => 'from@domain.com', + 'to' => 'to@domain.com', + 'cc' => 'cc@domain.com', + 'bcc' => 'bcc@domain.com', + 'subject' => 'Test subject', + 'textBody' => 'Test text body', + 'htmlBody' => 'Test HTML body', + ]; + $propertyConfig = [ + 'id' => 'test-id', + 'encoding' => 'test-encoding', + ]; + $messageConfig = array_merge($notPropertyConfig, $propertyConfig); + $mailer->messageConfig = $messageConfig; + + $message = $mailer->compose(); + + foreach ($notPropertyConfig as $name => $value) { + $this->assertEquals($value, $message->{'_' . $name}); + } + foreach ($propertyConfig as $name => $value) { + $this->assertEquals($value, $message->$name); + } + } + + /** + * @depends testGetDefaultView + */ + public function testRender() + { + $mailer = $this->getTestMailComponent(); + + $viewName = 'test_view'; + $viewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $viewName . '.php'; + $viewFileContent = ''; + file_put_contents($viewFileName, $viewFileContent); + + $params = [ + 'testParam' => 'test output' + ]; + $renderResult = $mailer->render($viewName, $params); + $this->assertEquals($params['testParam'], $renderResult); + } + + /** + * @depends testRender + */ + public function testRenderLayout() + { + $mailer = $this->getTestMailComponent(); + + $filePath = $this->getTestFilePath(); + + $viewName = 'test_view2'; + $viewFileName = $filePath . DIRECTORY_SEPARATOR . $viewName . '.php'; + $viewFileContent = 'view file content'; + file_put_contents($viewFileName, $viewFileContent); + + $layoutName = 'test_layout'; + $layoutFileName = $filePath . DIRECTORY_SEPARATOR . $layoutName . '.php'; + $layoutFileContent = 'Begin Layout End Layout'; + file_put_contents($layoutFileName, $layoutFileContent); + + $renderResult = $mailer->render($viewName, [], $layoutName); + $this->assertEquals('Begin Layout ' . $viewFileContent . ' End Layout', $renderResult); + } + + /** + * @depends testCreateMessage + * @depends testRender + */ + public function testCompose() + { + $mailer = $this->getTestMailComponent(); + $mailer->htmlLayout = false; + $mailer->textLayout = false; + + $htmlViewName = 'test_html_view'; + $htmlViewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $htmlViewName . '.php'; + $htmlViewFileContent = 'HTML view file content'; + file_put_contents($htmlViewFileName, $htmlViewFileContent); + + $textViewName = 'test_text_view'; + $textViewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $textViewName . '.php'; + $textViewFileContent = 'Plain text view file content'; + file_put_contents($textViewFileName, $textViewFileContent); + + $message = $mailer->compose([ + 'html' => $htmlViewName, + 'text' => $textViewName, + ]); + $this->assertEquals($htmlViewFileContent, $message->_htmlBody, 'Unable to render html!'); + $this->assertEquals($textViewFileContent, $message->_textBody, 'Unable to render text!'); + + $message = $mailer->compose($htmlViewName); + $this->assertEquals($htmlViewFileContent, $message->_htmlBody, 'Unable to render html by direct view!'); + $this->assertEquals(strip_tags($htmlViewFileContent), $message->_textBody, 'Unable to render text by direct view!'); + } + + public function htmlAndPlainProvider() + { + return [ + [ + 1, + 'HTML view file content http://yiifresh.com/index.php?r=site%2Freset-password&token=abcdef', + 'HTML view file content http://yiifresh.com/index.php?r=site%2Freset-password&token=abcdef', + ], + [ + 2, <<TEST + + +

        First paragraph + second line + + http://yiifresh.com/index.php?r=site%2Freset-password&token=abcdef + +

        + +

        Test Lorem ipsum...

        + + +HTML +, <<getTestMailComponent(); + $mailer->htmlLayout = false; + $mailer->textLayout = false; + + $htmlViewName = 'test_html_view' . $i; // $i is needed to generate different view files to ensure it works on HHVM + $htmlViewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $htmlViewName . '.php'; + file_put_contents($htmlViewFileName, $htmlViewFileContent); + + $message = $mailer->compose([ + 'html' => $htmlViewName, + ]); + $this->assertEqualsWithoutLE($htmlViewFileContent, $message->_htmlBody, 'Unable to render html!'); + $this->assertEqualsWithoutLE($expectedTextRendering, $message->_textBody, 'Unable to render text!'); + } + + public function testUseFileTransport() + { + $mailer = new Mailer(); + $this->assertFalse($mailer->useFileTransport); + $this->assertEquals('@runtime/mail', $mailer->fileTransportPath); + + $mailer->fileTransportPath = '@yiiunit/runtime/mail'; + $mailer->useFileTransport = true; + $mailer->fileTransportCallback = function () { + return 'message.txt'; + }; + $message = $mailer->compose() + ->setTo('to@example.com') + ->setFrom('from@example.com') + ->setSubject('test subject') + ->setTextBody('text body' . microtime(true)); + $this->assertTrue($mailer->send($message)); + $file = Yii::getAlias($mailer->fileTransportPath) . '/message.txt'; + $this->assertTrue(is_file($file)); + $this->assertEquals($message->toString(), file_get_contents($file)); + } + + public function testBeforeSendEvent() + { + $message = new Message(); + + $mailerMock = $this->getMockBuilder('yiiunit\framework\mail\Mailer')->setMethods(['beforeSend', 'afterSend'])->getMock(); + $mailerMock->expects($this->once())->method('beforeSend')->with($message)->will($this->returnValue(true)); + $mailerMock->expects($this->once())->method('afterSend')->with($message, true); + $mailerMock->send($message); + } +} + +/** + * Test Mailer class + */ +class Mailer extends BaseMailer +{ + public $messageClass = 'yiiunit\framework\mail\Message'; + public $sentMessages = []; + + protected function sendMessage($message) + { + $this->sentMessages[] = $message; + + return true; + } +} + +/** + * Test Message class + */ +class Message extends BaseMessage +{ + public $id; + public $encoding; + public $_charset; + public $_from; + public $_replyTo; + public $_to; + public $_cc; + public $_bcc; + public $_subject; + public $_textBody; + public $_htmlBody; + + public function getCharset() + { + return $this->_charset; + } + + public function setCharset($charset) + { + $this->_charset = $charset; + + return $this; + } + + public function getFrom() + { + return $this->_from; + } + + public function setFrom($from) + { + $this->_from = $from; + + return $this; + } + + public function getTo() + { + return $this->_to; + } + + public function setTo($to) + { + $this->_to = $to; + + return $this; + } + + public function getCc() + { + return $this->_cc; + } + + public function setCc($cc) + { + $this->_cc = $cc; + + return $this; + } + + public function getBcc() + { + return $this->_bcc; + } + + public function setBcc($bcc) + { + $this->_bcc = $bcc; + + return $this; + } + + public function getSubject() + { + return $this->_subject; + } + + public function setSubject($subject) + { + $this->_subject = $subject; + + return $this; + } + + public function getReplyTo() + { + return $this->_replyTo; + } + + public function setReplyTo($replyTo) + { + $this->_replyTo = $replyTo; + + return $this; + } + + public function setTextBody($text) + { + $this->_textBody = $text; + + return $this; + } + + public function setHtmlBody($html) + { + $this->_htmlBody = $html; + + return $this; + } + + public function attachContent($content, array $options = []) {} + + public function attach($fileName, array $options = []) {} + + public function embed($fileName, array $options = []) {} + + public function embedContent($content, array $options = []) {} + + public function toString() + { + $mailer = $this->mailer; + $this->mailer = null; + $s = var_export($this, true); + $this->mailer = $mailer; + return $s; + } +} diff --git a/tests/framework/mail/BaseMessageTest.php b/tests/framework/mail/BaseMessageTest.php new file mode 100644 index 0000000..539b730 --- /dev/null +++ b/tests/framework/mail/BaseMessageTest.php @@ -0,0 +1,153 @@ +mockApplication([ + 'components' => [ + 'mailer' => $this->createTestEmailComponent() + ] + ]); + } + + /** + * @return Mailer test email component instance. + */ + protected function createTestEmailComponent() + { + $component = new TestMailer(); + + return $component; + } + + /** + * @return TestMailer mailer instance. + */ + protected function getMailer() + { + return Yii::$app->get('mailer'); + } + + // Tests : + + public function testSend() + { + $mailer = $this->getMailer(); + $message = $mailer->compose(); + $message->send($mailer); + $this->assertEquals($message, $mailer->sentMessages[0], 'Unable to send message!'); + } + + public function testToString() + { + $mailer = $this->getMailer(); + $message = $mailer->compose(); + $this->assertEquals($message->toString(), '' . $message); + } +} + +/** + * Test Mailer class + */ +class TestMailer extends BaseMailer +{ + public $messageClass = 'yiiunit\framework\mail\TestMessage'; + public $sentMessages = []; + + protected function sendMessage($message) + { + $this->sentMessages[] = $message; + } +} + +/** + * Test Message class + */ +class TestMessage extends BaseMessage +{ + public $text; + public $html; + + public function getCharset() + { + return ''; + } + + public function setCharset($charset) {} + + public function getFrom() + { + return ''; + } + + public function setFrom($from) {} + + public function getReplyTo() + { + return ''; + } + + public function setReplyTo($replyTo) {} + + public function getTo() + { + return ''; + } + + public function setTo($to) {} + + public function getCc() + { + return ''; + } + + public function setCc($cc) {} + + public function getBcc() + { + return ''; + } + + public function setBcc($bcc) {} + + public function getSubject() + { + return ''; + } + + public function setSubject($subject) {} + + public function setTextBody($text) + { + $this->text = $text; + } + + public function setHtmlBody($html) + { + $this->html = $html; + } + + public function attachContent($content, array $options = []) {} + + public function attach($fileName, array $options = []) {} + + public function embed($fileName, array $options = []) {} + + public function embedContent($content, array $options = []) {} + + public function toString() + { + return get_class($this); + } +} diff --git a/tests/framework/rbac/AuthorRule.php b/tests/framework/rbac/AuthorRule.php new file mode 100644 index 0000000..fa4e794 --- /dev/null +++ b/tests/framework/rbac/AuthorRule.php @@ -0,0 +1,21 @@ + 'Migrator', + 'basePath' => '@yiiunit', + 'controllerMap' => [ + 'migrate' => EchoMigrateController::className(), + ], + 'components' => [ + 'db' => static::getConnection(), + 'authManager' => '\yii\rbac\DbManager', + ], + ]); + } + + ob_start(); + $result = Yii::$app->runAction($route, $params); + echo "Result is " . $result; + if ($result !== Controller::EXIT_CODE_NORMAL) { + ob_end_flush(); + } else { + ob_end_clean(); + } + } + + public static function setUpBeforeClass() + { + parent::setUpBeforeClass(); + $databases = static::getParam('databases'); + static::$database = $databases[static::$driverName]; + $pdo_database = 'pdo_' . static::$driverName; + + if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) { + static::markTestSkipped('pdo and ' . $pdo_database . ' extension are required.'); + } + + static::runConsoleAction('migrate/up', ['migrationPath' => '@yii/rbac/migrations/', 'interactive' => false]); + } + + public static function tearDownAfterClass() + { + static::runConsoleAction('migrate/down', ['migrationPath' => '@yii/rbac/migrations/', 'interactive' => false]); + if (static::$db) { + static::$db->close(); + } + Yii::$app = null; + parent::tearDownAfterClass(); + } + + protected function setUp() + { + parent::setUp(); + $this->auth = $this->createManager(); + } + + protected function tearDown() + { + parent::tearDown(); + $this->auth->removeAll(); + } + + /** + * @throws \yii\base\InvalidParamException + * @throws \yii\db\Exception + * @throws \yii\base\InvalidConfigException + * @return \yii\db\Connection + */ + public static function getConnection() + { + if (static::$db == null) { + $db = new Connection; + $db->dsn = static::$database['dsn']; + if (isset(static::$database['username'])) { + $db->username = static::$database['username']; + $db->password = static::$database['password']; + } + if (isset(static::$database['attributes'])) { + $db->attributes = static::$database['attributes']; + } + if (!$db->isActive) { + $db->open(); + } + static::$db = $db; + } + return static::$db; + } + + /** + * @return \yii\rbac\ManagerInterface + */ + protected function createManager() + { + return new DbManager(['db' => $this->getConnection()]); + } +} diff --git a/tests/framework/rbac/ExposedPhpManager.php b/tests/framework/rbac/ExposedPhpManager.php new file mode 100644 index 0000000..bf7c111 --- /dev/null +++ b/tests/framework/rbac/ExposedPhpManager.php @@ -0,0 +1,37 @@ + item + /** + * @var array + */ + public $children = []; // itemName, childName => child + /** + * @var \yii\rbac\Assignment[] + */ + public $assignments = []; // userId, itemName => assignment + /** + * @var \yii\rbac\Rule[] + */ + public $rules = []; // ruleName => rule + + public function load() + { + parent::load(); + } + + public function save() + { + parent::save(); + } +} \ No newline at end of file diff --git a/tests/framework/rbac/ManagerTestCase.php b/tests/framework/rbac/ManagerTestCase.php new file mode 100644 index 0000000..0acc791 --- /dev/null +++ b/tests/framework/rbac/ManagerTestCase.php @@ -0,0 +1,289 @@ +auth->createRole('admin'); + $this->assertTrue($role instanceof Role); + $this->assertEquals(Item::TYPE_ROLE, $role->type); + $this->assertEquals('admin', $role->name); + } + + public function testCreatePermission() + { + $permission = $this->auth->createPermission('edit post'); + $this->assertTrue($permission instanceof Permission); + $this->assertEquals(Item::TYPE_PERMISSION, $permission->type); + $this->assertEquals('edit post', $permission->name); + } + + public function testAdd() + { + $role = $this->auth->createRole('admin'); + $role->description = 'administrator'; + $this->assertTrue($this->auth->add($role)); + + $permission = $this->auth->createPermission('edit post'); + $permission->description = 'edit a post'; + $this->assertTrue($this->auth->add($permission)); + + $rule = new AuthorRule(['name' => 'is author', 'reallyReally' => true]); + $this->assertTrue($this->auth->add($rule)); + + // todo: check duplication of name + } + + public function testGetChildren() + { + $user = $this->auth->createRole('user'); + $this->auth->add($user); + $this->assertCount(0, $this->auth->getChildren($user->name)); + + $changeName = $this->auth->createPermission('changeName'); + $this->auth->add($changeName); + $this->auth->addChild($user, $changeName); + $this->assertCount(1, $this->auth->getChildren($user->name)); + } + + public function testGetRule() + { + $this->prepareData(); + + $rule = $this->auth->getRule('isAuthor'); + $this->assertInstanceOf('yii\rbac\Rule', $rule); + $this->assertEquals('isAuthor', $rule->name); + + $rule = $this->auth->getRule('nonExisting'); + $this->assertNull($rule); + } + + public function testAddRule() + { + $this->prepareData(); + + $ruleName = 'isReallyReallyAuthor'; + $rule = new AuthorRule(['name' => $ruleName, 'reallyReally' => true]); + $this->auth->add($rule); + + $rule = $this->auth->getRule($ruleName); + $this->assertEquals($ruleName, $rule->name); + $this->assertEquals(true, $rule->reallyReally); + } + + public function testUpdateRule() + { + $this->prepareData(); + + $rule = $this->auth->getRule('isAuthor'); + $rule->name = "newName"; + $rule->reallyReally = false; + $this->auth->update('isAuthor', $rule); + + $rule = $this->auth->getRule('isAuthor'); + $this->assertEquals(null, $rule); + + $rule = $this->auth->getRule('newName'); + $this->assertEquals("newName", $rule->name); + $this->assertEquals(false, $rule->reallyReally); + + $rule->reallyReally = true; + $this->auth->update('newName', $rule); + + $rule = $this->auth->getRule('newName'); + $this->assertEquals(true, $rule->reallyReally); + } + + public function testGetRules() + { + $this->prepareData(); + + $rule = new AuthorRule(['name' => 'isReallyReallyAuthor', 'reallyReally' => true]); + $this->auth->add($rule); + + $rules = $this->auth->getRules(); + + $ruleNames = []; + foreach ($rules as $rule) { + $ruleNames[] = $rule->name; + } + + $this->assertContains('isReallyReallyAuthor', $ruleNames); + $this->assertContains('isAuthor', $ruleNames); + } + + public function testRemoveRule() + { + $this->prepareData(); + + $this->auth->remove($this->auth->getRule('isAuthor')); + $rules = $this->auth->getRules(); + + $this->assertEmpty($rules); + } + + public function testCheckAccess() + { + $this->prepareData(); + + $testSuites = [ + 'reader A' => [ + 'createPost' => false, + 'readPost' => true, + 'updatePost' => false, + 'updateAnyPost' => false, + ], + 'author B' => [ + 'createPost' => true, + 'readPost' => true, + 'updatePost' => true, + 'updateAnyPost' => false, + ], + 'admin C' => [ + 'createPost' => true, + 'readPost' => true, + 'updatePost' => false, + 'updateAnyPost' => true, + ], + ]; + + $params = ['authorID' => 'author B']; + + foreach ($testSuites as $user => $tests) { + foreach ($tests as $permission => $result) { + $this->assertEquals($result, $this->auth->checkAccess($user, $permission, $params), "Checking $user can $permission"); + } + } + } + + protected function prepareData() + { + $rule = new AuthorRule; + $this->auth->add($rule); + + $createPost = $this->auth->createPermission('createPost'); + $createPost->description = 'create a post'; + $this->auth->add($createPost); + + $readPost = $this->auth->createPermission('readPost'); + $readPost->description = 'read a post'; + $this->auth->add($readPost); + + $updatePost = $this->auth->createPermission('updatePost'); + $updatePost->description = 'update a post'; + $updatePost->ruleName = $rule->name; + $this->auth->add($updatePost); + + $updateAnyPost = $this->auth->createPermission('updateAnyPost'); + $updateAnyPost->description = 'update any post'; + $this->auth->add($updateAnyPost); + + $reader = $this->auth->createRole('reader'); + $this->auth->add($reader); + $this->auth->addChild($reader, $readPost); + + $author = $this->auth->createRole('author'); + $this->auth->add($author); + $this->auth->addChild($author, $createPost); + $this->auth->addChild($author, $updatePost); + $this->auth->addChild($author, $reader); + + $admin = $this->auth->createRole('admin'); + $this->auth->add($admin); + $this->auth->addChild($admin, $author); + $this->auth->addChild($admin, $updateAnyPost); + + $this->auth->assign($reader, 'reader A'); + $this->auth->assign($author, 'author B'); + $this->auth->assign($admin, 'admin C'); + } + + public function testGetPermissionsByRole() + { + $this->prepareData(); + $roles = $this->auth->getPermissionsByRole('admin'); + $expectedPermissions = ['createPost', 'updatePost', 'readPost', 'updateAnyPost']; + $this->assertEquals(count($roles), count($expectedPermissions)); + foreach ($expectedPermissions as $permission) { + $this->assertTrue($roles[$permission] instanceof Permission); + } + } + + public function testGetPermissionsByUser() + { + $this->prepareData(); + $roles = $this->auth->getPermissionsByUser('author B'); + $expectedPermissions = ['createPost', 'updatePost', 'readPost']; + $this->assertEquals(count($roles), count($expectedPermissions)); + foreach ($expectedPermissions as $permission) { + $this->assertTrue($roles[$permission] instanceof Permission); + } + } + + public function testGetRolesByUser() + { + $this->prepareData(); + $roles = $this->auth->getRolesByUser('reader A'); + $this->assertTrue(reset($roles) instanceof Role); + $this->assertEquals($roles['reader']->name, 'reader'); + } + + public function testAssignMultipleRoles() + { + $this->prepareData(); + + $reader = $this->auth->getRole('reader'); + $author = $this->auth->getRole('author'); + $this->auth->assign($reader, 'readingAuthor'); + $this->auth->assign($author, 'readingAuthor'); + + $this->auth = $this->createManager(); + + $roles = $this->auth->getRolesByUser('readingAuthor'); + $roleNames = []; + foreach ($roles as $role) { + $roleNames[] = $role->name; + } + + $this->assertContains('reader', $roleNames, 'Roles should contain reader. Currently it has: ' . implode(', ', $roleNames)); + $this->assertContains('author', $roleNames, 'Roles should contain author. Currently it has: ' . implode(', ', $roleNames)); + } + + public function testAssignmentsToIntegerId() + { + $this->prepareData(); + + $reader = $this->auth->getRole('reader'); + $author = $this->auth->getRole('author'); + $this->auth->assign($reader, 42); + $this->auth->assign($author, 1337); + $this->auth->assign($reader, 1337); + + $this->auth = $this->createManager(); + + $this->assertEquals(0, count($this->auth->getAssignments(0))); + $this->assertEquals(1, count($this->auth->getAssignments(42))); + $this->assertEquals(2, count($this->auth->getAssignments(1337))); + } +} diff --git a/tests/framework/rbac/MySQLManagerCacheTest.php b/tests/framework/rbac/MySQLManagerCacheTest.php new file mode 100644 index 0000000..615b137 --- /dev/null +++ b/tests/framework/rbac/MySQLManagerCacheTest.php @@ -0,0 +1,24 @@ + $this->getConnection(), + 'cache' => new FileCache(['cachePath' => '@yiiunit/runtime/cache']), + ]); + } +} diff --git a/tests/framework/rbac/MySQLManagerTest.php b/tests/framework/rbac/MySQLManagerTest.php new file mode 100644 index 0000000..d64c0cd --- /dev/null +++ b/tests/framework/rbac/MySQLManagerTest.php @@ -0,0 +1,12 @@ +getRuntimePath() . '/rbac-items.php'; + } + + protected function getAssignmentFile() + { + return Yii::$app->getRuntimePath() . '/rbac-assignments.php'; + } + + protected function getRuleFile() + { + return Yii::$app->getRuntimePath() . '/rbac-rules.php'; + } + + protected function removeDataFiles() + { + @unlink($this->getItemFile()); + @unlink($this->getAssignmentFile()); + @unlink($this->getRuleFile()); + } + + /** + * @inheritdoc + */ + protected function createManager() + { + return new ExposedPhpManager([ + 'itemFile' => $this->getItemFile(), + 'assignmentFile' => $this->getAssignmentFile(), + 'ruleFile' => $this->getRuleFile(), + ]); + } + + protected function setUp() + { + static::$filemtime = null; + static::$time = null; + parent::setUp(); + + if (defined('HHVM_VERSION')) { + $this->markTestSkipped('PhpManager is not compatible with HHVM.'); + } + + $this->mockApplication(); + $this->removeDataFiles(); + $this->auth = $this->createManager(); + } + + protected function tearDown() + { + $this->removeDataFiles(); + static::$filemtime = null; + static::$time = null; + parent::tearDown(); + } + + public function testSaveLoad() + { + static::$time = static::$filemtime = \time(); + + $this->prepareData(); + $items = $this->auth->items; + $children = $this->auth->children; + $assignments = $this->auth->assignments; + $rules = $this->auth->rules; + $this->auth->save(); + + $this->auth = $this->createManager(); + $this->auth->load(); + + $this->assertEquals($items, $this->auth->items); + $this->assertEquals($children, $this->auth->children); + $this->assertEquals($assignments, $this->auth->assignments); + $this->assertEquals($rules, $this->auth->rules); + } + + public function testUpdateItemName() + { + $this->prepareData(); + + $name = 'readPost'; + $permission = $this->auth->getPermission($name); + $permission->name = 'UPDATED-NAME'; + $this->assertTrue($this->auth->update($name, $permission), 'You should be able to update name.'); + } + + public function testUpdateDescription() { + $this->prepareData(); + $name = 'readPost'; + $permission = $this->auth->getPermission($name); + $permission->description = 'UPDATED-DESCRIPTION'; + $this->assertTrue($this->auth->update($name, $permission), 'You should be able to save w/o changing name.'); + } + + /** + * @expectedException \yii\base\InvalidParamException + */ + public function testOverwriteName() + { + $this->prepareData(); + $name = 'readPost'; + $permission = $this->auth->getPermission($name); + $permission->name = 'createPost'; + $this->auth->update($name, $permission); + } +} diff --git a/tests/framework/rbac/SqliteManagerTest.php b/tests/framework/rbac/SqliteManagerTest.php new file mode 100644 index 0000000..2b77fd0 --- /dev/null +++ b/tests/framework/rbac/SqliteManagerTest.php @@ -0,0 +1,12 @@ + [ + 'name' => 'Requirement 1', + 'mandatory' => true, + 'condition' => true, + 'by' => 'Requirement 1', + 'memo' => 'Requirement 1', + ], + 'requirementError' => [ + 'name' => 'Requirement 2', + 'mandatory' => true, + 'condition' => false, + 'by' => 'Requirement 2', + 'memo' => 'Requirement 2', + ], + 'requirementWarning' => [ + 'name' => 'Requirement 3', + 'mandatory' => false, + 'condition' => false, + 'by' => 'Requirement 3', + 'memo' => 'Requirement 3', + ], + ]; + + $checkResult = $requirementsChecker->check($requirements)->getResult(); + $summary = $checkResult['summary']; + + $this->assertEquals(count($requirements), $summary['total'], 'Wrong summary total!'); + $this->assertEquals(1, $summary['errors'], 'Wrong summary errors!'); + $this->assertEquals(1, $summary['warnings'], 'Wrong summary warnings!'); + + $checkedRequirements = $checkResult['requirements']; + $requirementsKeys = array_flip(array_keys($requirements)); + + $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['error'], 'Passed requirement has an error!'); + $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['warning'], 'Passed requirement has a warning!'); + + $this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementError']]['error'], 'Error requirement has no error!'); + + $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementWarning']]['error'], 'Error requirement has an error!'); + $this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementWarning']]['warning'], 'Error requirement has no warning!'); + } + + /** + * @depends testCheck + */ + public function testCheckEval() + { + $requirementsChecker = new YiiRequirementChecker(); + + $requirements = [ + 'requirementPass' => [ + 'name' => 'Requirement 1', + 'mandatory' => true, + 'condition' => 'eval:2>1', + 'by' => 'Requirement 1', + 'memo' => 'Requirement 1', + ], + 'requirementError' => [ + 'name' => 'Requirement 2', + 'mandatory' => true, + 'condition' => 'eval:2<1', + 'by' => 'Requirement 2', + 'memo' => 'Requirement 2', + ], + ]; + + $checkResult = $requirementsChecker->check($requirements)->getResult(); + $checkedRequirements = $checkResult['requirements']; + $requirementsKeys = array_flip(array_keys($requirements)); + + $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['error'], 'Passed requirement has an error!'); + $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['warning'], 'Passed requirement has a warning!'); + + $this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementError']]['error'], 'Error requirement has no error!'); + } + + /** + * @depends testCheck + */ + public function testCheckChained() + { + $requirementsChecker = new YiiRequirementChecker(); + + $requirements1 = [ + [ + 'name' => 'Requirement 1', + 'mandatory' => true, + 'condition' => true, + 'by' => 'Requirement 1', + 'memo' => 'Requirement 1', + ], + ]; + $requirements2 = [ + [ + 'name' => 'Requirement 2', + 'mandatory' => true, + 'condition' => true, + 'by' => 'Requirement 2', + 'memo' => 'Requirement 2', + ], + ]; + $checkResult = $requirementsChecker->check($requirements1)->check($requirements2)->getResult(); + + $mergedRequirements = array_merge($requirements1, $requirements2); + + $this->assertEquals(count($mergedRequirements), $checkResult['summary']['total'], 'Wrong total checks count!'); + foreach ($mergedRequirements as $key => $mergedRequirement) { + $this->assertEquals($mergedRequirement['name'], $checkResult['requirements'][$key]['name'], 'Wrong requirements list!'); + } + } + + public function testCheckPhpExtensionVersion() + { + if (defined('HHVM_VERSION')) { + $this->markTestSkipped('Can not test this on HHVM.'); + } + + $requirementsChecker = new YiiRequirementChecker(); + + $this->assertFalse($requirementsChecker->checkPhpExtensionVersion('some_unexisting_php_extension', '0.1'), 'No fail while checking unexisting extension!'); + $this->assertTrue($requirementsChecker->checkPhpExtensionVersion('pdo', '1.0'), 'Unable to check PDO version!'); + } + + /** + * Data provider for [[testGetByteSize()]]. + * @return array + */ + public function dataProviderGetByteSize() + { + return [ + ['456', 456], + ['5K', 5*1024], + ['16KB', 16*1024], + ['4M', 4*1024*1024], + ['14MB', 14*1024*1024], + ['7G', 7*1024*1024*1024], + ['12GB', 12*1024*1024*1024], + ]; + } + + /** + * @dataProvider dataProviderGetByteSize + * + * @param string $verboseValue verbose value. + * @param integer $expectedByteSize expected byte size. + */ + public function testGetByteSize($verboseValue, $expectedByteSize) + { + $requirementsChecker = new YiiRequirementChecker(); + + $this->assertEquals($expectedByteSize, $requirementsChecker->getByteSize($verboseValue), "Wrong byte size for '{$verboseValue}'!"); + } + + /** + * Data provider for [[testCompareByteSize()]] + * @return array + */ + public function dataProviderCompareByteSize() + { + return [ + ['2M', '2K', '>', true], + ['2M', '2K', '>=', true], + ['1K', '1024', '==', true], + ['10M', '11M', '<', true], + ['10M', '11M', '<=', true], + ]; + } + + /** + * @depends testGetByteSize + * @dataProvider dataProviderCompareByteSize + * + * @param string $a first value. + * @param string $b second value. + * @param string $compare comparison. + * @param boolean $expectedComparisonResult expected comparison result. + */ + public function testCompareByteSize($a, $b, $compare, $expectedComparisonResult) + { + $requirementsChecker = new YiiRequirementChecker(); + $this->assertEquals($expectedComparisonResult, $requirementsChecker->compareByteSize($a, $b, $compare), "Wrong compare '{$a}{$compare}{$b}'"); + } +} diff --git a/tests/framework/test/ActiveFixtureTest.php b/tests/framework/test/ActiveFixtureTest.php new file mode 100644 index 0000000..b73f4ff --- /dev/null +++ b/tests/framework/test/ActiveFixtureTest.php @@ -0,0 +1,96 @@ +unloadFixtures(); + $this->loadFixtures(); + } + + public function tearDown() + { + } + + public function fixtures() + { + return [ + 'customers' => CustomerFixture::className(), + ]; + } + + public function globalFixtures() + { + return [ + InitDbFixture::className(), + ]; + } +} + +/** + * + * @author Qiang Xue + * @since 2.0 + */ +class ActiveFixtureTest extends DatabaseTestCase +{ + public function setUp() + { + parent::setUp(); + \Yii::$app->set('db', $this->getConnection()); + ActiveRecord::$db = $this->getConnection(); + } + + public function tearDown() + { + parent::tearDown(); + } + + public function testGetData() + { + $test = new MyDbTestCase(); + $test->setUp(); + $fixture = $test->getFixture('customers'); + $this->assertEquals(CustomerFixture::className(), get_class($fixture)); + $this->assertEquals(2, count($fixture)); + $this->assertEquals(1, $fixture['customer1']['id']); + $this->assertEquals('customer1@example.com', $fixture['customer1']['email']); + $this->assertEquals(2, $fixture['customer2']['id']); + $this->assertEquals('customer2@example.com', $fixture['customer2']['email']); + $test->tearDown(); + } + + public function testGetModel() + { + $test = new MyDbTestCase(); + $test->setUp(); + $fixture = $test->getFixture('customers'); + $this->assertEquals(Customer::className(), get_class($fixture->getModel('customer1'))); + $this->assertEquals(1, $fixture->getModel('customer1')->id); + $this->assertEquals('customer1@example.com', $fixture->getModel('customer1')->email); + $this->assertEquals(2, $fixture->getModel('customer2')->id); + $this->assertEquals('customer2@example.com', $fixture->getModel('customer2')->email); + $test->tearDown(); + } +} diff --git a/tests/framework/test/ArrayFixtureTest.php b/tests/framework/test/ArrayFixtureTest.php new file mode 100644 index 0000000..994dd9f --- /dev/null +++ b/tests/framework/test/ArrayFixtureTest.php @@ -0,0 +1,58 @@ +_fixture = new ArrayFixture(); + } + + public function testLoadUnloadParticularFile() + { + $this->_fixture->dataFile = '@yiiunit/framework/test/data/array_fixture.php'; + $this->assertEmpty($this->_fixture->data, 'fixture data should be empty'); + + $this->_fixture->load(); + + $this->assertCount(2, $this->_fixture->data, 'fixture data should match needed total count'); + $this->assertEquals('customer1', $this->_fixture['customer1']['name'], 'first fixture data should match'); + $this->assertEquals('customer2@example.com', $this->_fixture['customer2']['email'], 'second fixture data should match'); + } + + public function testNothingToLoad() + { + $this->_fixture->dataFile = false; + $this->assertEmpty($this->_fixture->data, 'fixture data should be empty'); + + $this->_fixture->load(); + $this->assertEmpty($this->_fixture->data, 'fixture data should not be loaded'); + } + + /** + * @expectedException \yii\base\InvalidConfigException + */ + public function testWrongDataFileException() + { + $this->_fixture->dataFile = 'wrong/fixtures/data/path/alias'; + $this->_fixture->load(); + } + +} diff --git a/tests/framework/test/FixtureTest.php b/tests/framework/test/FixtureTest.php new file mode 100644 index 0000000..9284d99 --- /dev/null +++ b/tests/framework/test/FixtureTest.php @@ -0,0 +1,169 @@ +loadFixtures(); + } + + public function tearDown() + { + $this->unloadFixtures(); + } + + public function fetchFixture($name) + { + return $this->getFixture($name); + } + + public function fixtures() + { + switch ($this->scenario) { + case 0: return []; + case 1: return [ + 'fixture1' => Fixture1::className(), + ]; + case 2: return [ + 'fixture2' => Fixture2::className(), + ]; + case 3: return [ + 'fixture3' => Fixture3::className(), + ]; + case 4: return [ + 'fixture1' => Fixture1::className(), + 'fixture2' => Fixture2::className(), + ]; + case 5: return [ + 'fixture2' => Fixture2::className(), + 'fixture3' => Fixture3::className(), + ]; + case 6: return [ + 'fixture1' => Fixture1::className(), + 'fixture3' => Fixture3::className(), + ]; + case 7: + default: return [ + 'fixture1' => Fixture1::className(), + 'fixture2' => Fixture2::className(), + 'fixture3' => Fixture3::className(), + ]; + } + } +} + +class FixtureTest extends TestCase +{ + public function testDependencies() + { + foreach ($this->getDependencyTests() as $scenario => $result) { + $test = new MyTestCase(); + $test->scenario = $scenario; + $test->setUp(); + foreach ($result as $name => $loaded) { + $this->assertEquals($loaded, $test->fetchFixture($name) !== null, "Verifying scenario $scenario fixture $name"); + } + } + } + + public function testLoadSequence() + { + foreach ($this->getLoadSequenceTests() as $scenario => $result) { + $test = new MyTestCase(); + $test->scenario = $scenario; + MyTestCase::$load = ''; + MyTestCase::$unload = ''; + $test->setUp(); + $this->assertEquals($result[0], MyTestCase::$load, "Verifying scenario $scenario load sequence"); + $test->tearDown(); + $this->assertEquals($result[1], MyTestCase::$unload, "Verifying scenario $scenario unload sequence"); + } + } + + protected function getDependencyTests() + { + return [ + 0 => ['fixture1' => false, 'fixture2' => false, 'fixture3' => false], + 1 => ['fixture1' => true, 'fixture2' => false, 'fixture3' => false], + 2 => ['fixture1' => false, 'fixture2' => true, 'fixture3' => false], + 3 => ['fixture1' => false, 'fixture2' => false, 'fixture3' => true], + 4 => ['fixture1' => true, 'fixture2' => true, 'fixture3' => false], + 5 => ['fixture1' => false, 'fixture2' => true, 'fixture3' => true], + 6 => ['fixture1' => true, 'fixture2' => false, 'fixture3' => true], + 7 => ['fixture1' => true, 'fixture2' => true, 'fixture3' => true], + ]; + } + + protected function getLoadSequenceTests() + { + return [ + 0 => ['', ''], + 1 => ['321', '123'], + 2 => ['32', '23'], + 3 => ['3', '3'], + 4 => ['321', '123'], + 5 => ['32', '23'], + 6 => ['321', '123'], + 7 => ['321', '123'], + ]; + } +} diff --git a/tests/framework/test/data/array_fixture.php b/tests/framework/test/data/array_fixture.php new file mode 100644 index 0000000..c5ccd4b --- /dev/null +++ b/tests/framework/test/data/array_fixture.php @@ -0,0 +1,16 @@ + [ + 'email' => 'customer1@example.com', + 'name' => 'customer1', + 'address' => 'address1', + 'status' => 1, + ], + 'customer2' => [ + 'email' => 'customer2@example.com', + 'name' => 'customer2', + 'address' => 'address2', + 'status' => 2, + ], +]; diff --git a/tests/framework/test/data/customer.php b/tests/framework/test/data/customer.php new file mode 100644 index 0000000..c5ccd4b --- /dev/null +++ b/tests/framework/test/data/customer.php @@ -0,0 +1,16 @@ + [ + 'email' => 'customer1@example.com', + 'name' => 'customer1', + 'address' => 'address1', + 'status' => 1, + ], + 'customer2' => [ + 'email' => 'customer2@example.com', + 'name' => 'customer2', + 'address' => 'address2', + 'status' => 2, + ], +]; diff --git a/tests/framework/validators/BooleanValidatorTest.php b/tests/framework/validators/BooleanValidatorTest.php new file mode 100644 index 0000000..d8441bc --- /dev/null +++ b/tests/framework/validators/BooleanValidatorTest.php @@ -0,0 +1,60 @@ +mockApplication(); + } + + public function testValidateValue() + { + $val = new BooleanValidator; + $this->assertTrue($val->validate(true)); + $this->assertTrue($val->validate(false)); + $this->assertTrue($val->validate('0')); + $this->assertTrue($val->validate('1')); + $this->assertFalse($val->validate('5')); + $this->assertFalse($val->validate(null)); + $this->assertFalse($val->validate([])); + $val->strict = true; + $this->assertTrue($val->validate('0')); + $this->assertTrue($val->validate('1')); + $this->assertFalse($val->validate(true)); + $this->assertFalse($val->validate(false)); + $val->trueValue = true; + $val->falseValue = false; + $this->assertFalse($val->validate('0')); + $this->assertFalse($val->validate([])); + $this->assertTrue($val->validate(true)); + $this->assertTrue($val->validate(false)); + } + + public function testValidateAttributeAndError() + { + $obj = new FakedValidationModel; + $obj->attrA = true; + $obj->attrB = '1'; + $obj->attrC = '0'; + $obj->attrD = []; + $val = new BooleanValidator; + $val->validateAttribute($obj, 'attrA'); + $this->assertFalse($obj->hasErrors('attrA')); + $val->validateAttribute($obj, 'attrC'); + $this->assertFalse($obj->hasErrors('attrC')); + $val->strict = true; + $val->validateAttribute($obj, 'attrB'); + $this->assertFalse($obj->hasErrors('attrB')); + $val->validateAttribute($obj, 'attrD'); + $this->assertTrue($obj->hasErrors('attrD')); + } +} diff --git a/tests/framework/validators/CompareValidatorTest.php b/tests/framework/validators/CompareValidatorTest.php new file mode 100644 index 0000000..239be30 --- /dev/null +++ b/tests/framework/validators/CompareValidatorTest.php @@ -0,0 +1,176 @@ +mockApplication(); + } + + public function testValidateValueException() + { + $this->setExpectedException('yii\base\InvalidConfigException'); + $val = new CompareValidator; + $val->validate('val'); + } + + public function testValidateValue() + { + $value = 18449; + // default config + $val = new CompareValidator(['compareValue' => $value]); + $this->assertTrue($val->validate($value)); + $this->assertTrue($val->validate((string) $value)); + $this->assertFalse($val->validate($value + 1)); + foreach ($this->getOperationTestData($value) as $op => $tests) { + $val = new CompareValidator(['compareValue' => $value]); + $val->operator = $op; + foreach ($tests as $test) { + $this->assertEquals($test[1], $val->validate($test[0]), "Testing $op"); + } + } + } + + protected function getOperationTestData($value) + { + return [ + '===' => [ + [$value, true], + [(string) $value, true], + [(float) $value, true], + [$value + 1, false], + ], + '!=' => [ + [$value, false], + [(string) $value, false], + [(float) $value, false], + [$value + 0.00001, true], + [false, true], + ], + '!==' => [ + [$value, false], + [(string) $value, false], + [(float) $value, false], + [false, true], + ], + '>' => [ + [$value, false], + [$value + 1, true], + [$value - 1, false], + ], + '>=' => [ + [$value, true], + [$value + 1, true], + [$value - 1, false], + ], + '<' => [ + [$value, false], + [$value + 1, false], + [$value - 1, true], + ], + '<=' => [ + [$value, true], + [$value + 1, false], + [$value - 1, true], + ], + //'non-op' => [ + // [$value, false], + // [$value + 1, false], + // [$value - 1, false], + //], + ]; + } + + public function testValidateAttribute() + { + // invalid-array + $val = new CompareValidator; + $model = new FakedValidationModel; + $model->attr = ['test_val']; + $val->validateAttribute($model, 'attr'); + $this->assertTrue($model->hasErrors('attr')); + $val = new CompareValidator(['compareValue' => 'test-string']); + $model = new FakedValidationModel; + $model->attr_test = 'test-string'; + $val->validateAttribute($model, 'attr_test'); + $this->assertFalse($model->hasErrors('attr_test')); + $val = new CompareValidator(['compareAttribute' => 'attr_test_val']); + $model = new FakedValidationModel; + $model->attr_test = 'test-string'; + $model->attr_test_val = 'test-string'; + $val->validateAttribute($model, 'attr_test'); + $this->assertFalse($model->hasErrors('attr_test')); + $this->assertFalse($model->hasErrors('attr_test_val')); + $val = new CompareValidator(['compareAttribute' => 'attr_test_val']); + $model = new FakedValidationModel; + $model->attr_test = 'test-string'; + $model->attr_test_val = 'test-string-false'; + $val->validateAttribute($model, 'attr_test'); + $this->assertTrue($model->hasErrors('attr_test')); + $this->assertFalse($model->hasErrors('attr_test_val')); + // assume: _repeat + $val = new CompareValidator; + $model = new FakedValidationModel; + $model->attr_test = 'test-string'; + $model->attr_test_repeat = 'test-string'; + $val->validateAttribute($model, 'attr_test'); + $this->assertFalse($model->hasErrors('attr_test')); + $this->assertFalse($model->hasErrors('attr_test_repeat')); + $val = new CompareValidator; + $model = new FakedValidationModel; + $model->attr_test = 'test-string'; + $model->attr_test_repeat = 'test-string2'; + $val->validateAttribute($model, 'attr_test'); + $this->assertTrue($model->hasErrors('attr_test')); + $this->assertFalse($model->hasErrors('attr_test_repeat')); + // not existing op + $val = new CompareValidator(); + $val->operator = '<>'; + $model = FakedValidationModel::createWithAttributes(['attr_o' => 5, 'attr_o_repeat' => 5]); + $val->validateAttribute($model, 'attr_o'); + $this->assertTrue($model->hasErrors('attr_o')); + } + + public function testValidateAttributeOperators() + { + $value = 55; + foreach ($this->getOperationTestData($value) as $operator => $tests) { + $val = new CompareValidator(['operator' => $operator, 'compareValue' => $value]); + foreach ($tests as $test) { + $model = new FakedValidationModel; + $model->attr_test = $test[0]; + $val->validateAttribute($model, 'attr_test'); + $this->assertEquals($test[1], !$model->hasErrors('attr_test')); + } + + } + } + + public function testEnsureMessageSetOnInit() + { + foreach ($this->getOperationTestData(1337) as $operator => $tests) { + $val = new CompareValidator(['operator' => $operator]); + $this->assertTrue(strlen($val->message) > 1); + } + try { + new CompareValidator(['operator' => '<>']); + } catch (InvalidConfigException $e) { + return; + } catch (\Exception $e) { + $this->fail('InvalidConfigException expected' . get_class($e) . 'received'); + + return; + } + $this->fail('InvalidConfigException expected none received'); + } +} diff --git a/tests/framework/validators/DateValidatorTest.php b/tests/framework/validators/DateValidatorTest.php new file mode 100644 index 0000000..58e60a5 --- /dev/null +++ b/tests/framework/validators/DateValidatorTest.php @@ -0,0 +1,201 @@ +mockApplication([ + 'timeZone' => 'UTC', + 'language' => 'ru-RU', + ]); + } + + protected function tearDown() + { + parent::tearDown(); + IntlTestHelper::resetIntlStatus(); + } + + public function testEnsureMessageIsSet() + { + $val = new DateValidator; + $this->assertTrue($val->message !== null && strlen($val->message) > 1); + } + + public function testIntlValidateValue() + { + $this->testValidateValue(); + + $this->mockApplication([ + 'language' => 'en-GB', + 'components' => [ + 'formatter' => [ + 'dateFormat' => 'short', + ] + ] + ]); + $val = new DateValidator(); + $this->assertTrue($val->validate('31/5/2017')); + $this->assertFalse($val->validate('5/31/2017')); + $val = new DateValidator(['format' => 'short', 'locale' => 'en-GB']); + $this->assertTrue($val->validate('31/5/2017')); + $this->assertFalse($val->validate('5/31/2017')); + + $this->mockApplication([ + 'language' => 'de-DE', + 'components' => [ + 'formatter' => [ + 'dateFormat' => 'short', + ] + ] + ]); + $val = new DateValidator(); + $this->assertTrue($val->validate('31.5.2017')); + $this->assertFalse($val->validate('5.31.2017')); + $val = new DateValidator(['format' => 'short', 'locale' => 'de-DE']); + $this->assertTrue($val->validate('31.5.2017')); + $this->assertFalse($val->validate('5.31.2017')); + } + + public function testValidateValue() + { + // test PHP format + $val = new DateValidator(['format' => 'php:Y-m-d']); + $this->assertFalse($val->validate('3232-32-32')); + $this->assertTrue($val->validate('2013-09-13')); + $this->assertFalse($val->validate('31.7.2013')); + $this->assertFalse($val->validate('31-7-2013')); + $this->assertFalse($val->validate('20121212')); + $this->assertFalse($val->validate('asdasdfasfd')); + $this->assertFalse($val->validate('2012-12-12foo')); + $this->assertFalse($val->validate('')); + $this->assertFalse($val->validate(time())); + $val->format = 'php:U'; + $this->assertTrue($val->validate(time())); + $val->format = 'php:d.m.Y'; + $this->assertTrue($val->validate('31.7.2013')); + $val->format = 'php:Y-m-!d H:i:s'; + $this->assertTrue($val->validate('2009-02-15 15:16:17')); + + // test ICU format + $val = new DateValidator(['format' => 'yyyy-MM-dd']); + $this->assertFalse($val->validate('3232-32-32')); + $this->assertTrue($val->validate('2013-09-13')); + $this->assertFalse($val->validate('31.7.2013')); + $this->assertFalse($val->validate('31-7-2013')); + $this->assertFalse($val->validate('20121212')); + $this->assertFalse($val->validate('asdasdfasfd')); + $this->assertFalse($val->validate('2012-12-12foo')); + $this->assertFalse($val->validate('')); + $this->assertFalse($val->validate(time())); + $val->format = 'dd.MM.yyyy'; + $this->assertTrue($val->validate('31.7.2013')); + $val->format = 'yyyy-MM-dd HH:mm:ss'; + $this->assertTrue($val->validate('2009-02-15 15:16:17')); + } + + public function testIntlValidateAttributePHPFormat() + { + $this->testValidateAttributePHPFormat(); + } + + public function testValidateAttributePHPFormat() + { + // error-array-add + $val = new DateValidator(['format' => 'php:Y-m-d']); + $model = new FakedValidationModel; + $model->attr_date = '2013-09-13'; + $val->validateAttribute($model, 'attr_date'); + $this->assertFalse($model->hasErrors('attr_date')); + $model = new FakedValidationModel; + $model->attr_date = '1375293913'; + $val->validateAttribute($model, 'attr_date'); + $this->assertTrue($model->hasErrors('attr_date')); + //// timestamp attribute + $val = new DateValidator(['format' => 'php:Y-m-d', 'timestampAttribute' => 'attr_timestamp']); + $model = new FakedValidationModel; + $model->attr_date = '2013-09-13'; + $model->attr_timestamp = true; + $val->validateAttribute($model, 'attr_date'); + $this->assertFalse($model->hasErrors('attr_date')); + $this->assertFalse($model->hasErrors('attr_timestamp')); + $this->assertEquals( + mktime(0, 0, 0, 9, 13, 2013), // 2013-09-13 +// DateTime::createFromFormat('Y-m-d', '2013-09-13')->getTimestamp(), + $model->attr_timestamp + ); + $val = new DateValidator(['format' => 'php:Y-m-d']); + $model = FakedValidationModel::createWithAttributes(['attr_date' => []]); + $val->validateAttribute($model, 'attr_date'); + $this->assertTrue($model->hasErrors('attr_date')); + + } + + public function testIntlValidateAttributeICUFormat() + { + $this->testValidateAttributeICUFormat(); + } + + public function testValidateAttributeICUFormat() + { + // error-array-add + $val = new DateValidator(['format' => 'yyyy-MM-dd']); + $model = new FakedValidationModel; + $model->attr_date = '2013-09-13'; + $val->validateAttribute($model, 'attr_date'); + $this->assertFalse($model->hasErrors('attr_date')); + $model = new FakedValidationModel; + $model->attr_date = '1375293913'; + $val->validateAttribute($model, 'attr_date'); + $this->assertTrue($model->hasErrors('attr_date')); + //// timestamp attribute + $val = new DateValidator(['format' => 'yyyy-MM-dd', 'timestampAttribute' => 'attr_timestamp']); + $model = new FakedValidationModel; + $model->attr_date = '2013-09-13'; + $model->attr_timestamp = true; + $val->validateAttribute($model, 'attr_date'); + $this->assertFalse($model->hasErrors('attr_date')); + $this->assertFalse($model->hasErrors('attr_timestamp')); + $this->assertEquals( + mktime(0, 0, 0, 9, 13, 2013), // 2013-09-13 +// DateTime::createFromFormat('Y-m-d', '2013-09-13')->getTimestamp(), + $model->attr_timestamp + ); + $val = new DateValidator(['format' => 'yyyy-MM-dd']); + $model = FakedValidationModel::createWithAttributes(['attr_date' => []]); + $val->validateAttribute($model, 'attr_date'); + $this->assertTrue($model->hasErrors('attr_date')); + $val = new DateValidator(['format' => 'yyyy-MM-dd']); + $model = FakedValidationModel::createWithAttributes(['attr_date' => '2012-12-12foo']); + $val->validateAttribute($model, 'attr_date'); + $this->assertTrue($model->hasErrors('attr_date')); + } + + public function testIntlMultibyteString() + { + $val = new DateValidator(['format' => 'dd MMM yyyy', 'locale' => 'de_DE']); + $model = FakedValidationModel::createWithAttributes(['attr_date' => '12 Mai 2014']); + $val->validateAttribute($model, 'attr_date'); + $this->assertFalse($model->hasErrors('attr_date')); + + $val = new DateValidator(['format' => 'dd MMM yyyy', 'locale' => 'ru_RU']); + $model = FakedValidationModel::createWithAttributes(['attr_date' => '12 мая 2014']); + $val->validateAttribute($model, 'attr_date'); + $this->assertFalse($model->hasErrors('attr_date')); + } +} diff --git a/tests/framework/validators/DefaultValueValidatorTest.php b/tests/framework/validators/DefaultValueValidatorTest.php new file mode 100644 index 0000000..80a0fdc --- /dev/null +++ b/tests/framework/validators/DefaultValueValidatorTest.php @@ -0,0 +1,40 @@ +mockApplication(); + } + + public function testValidateAttribute() + { + $val = new DefaultValueValidator; + $val->value = 'test_value'; + $obj = new \stdclass; + $obj->attrA = 'attrA'; + $obj->attrB = null; + $obj->attrC = ''; + // original values to chek which attritubes where modified + $objB = clone $obj; + $val->validateAttribute($obj, 'attrB'); + $this->assertEquals($val->value, $obj->attrB); + $this->assertEquals($objB->attrA, $obj->attrA); + $val->value = 'new_test_value'; + $obj = clone $objB; // get clean object + $val->validateAttribute($obj, 'attrC'); + $this->assertEquals('new_test_value', $obj->attrC); + $this->assertEquals($objB->attrA, $obj->attrA); + $val->validateAttribute($obj, 'attrA'); + $this->assertEquals($objB->attrA, $obj->attrA); + } +} diff --git a/tests/framework/validators/EachValidatorTest.php b/tests/framework/validators/EachValidatorTest.php new file mode 100644 index 0000000..3a50e59 --- /dev/null +++ b/tests/framework/validators/EachValidatorTest.php @@ -0,0 +1,75 @@ +mockApplication(); + } + + public function testArrayFormat() + { + $validator = new EachValidator(['rule' => ['required']]); + + $this->assertFalse($validator->validate('not array')); + $this->assertTrue($validator->validate(['value'])); + } + + /** + * @depends testArrayFormat + */ + public function testValidate() + { + $validator = new EachValidator(['rule' => ['integer']]); + + $this->assertTrue($validator->validate([1, 3, 8])); + $this->assertFalse($validator->validate([1, 'text', 8])); + } + + /** + * @depends testArrayFormat + */ + public function testFilter() + { + $model = FakedValidationModel::createWithAttributes([ + 'attr_one' => [ + ' to be trimmed ' + ], + ]); + $validator = new EachValidator(['rule' => ['trim']]); + $validator->validateAttribute($model, 'attr_one'); + $this->assertEquals('to be trimmed', $model->attr_one[0]); + } + + /** + * @depends testValidate + */ + public function testAllowMessageFromRule() + { + $model = FakedValidationModel::createWithAttributes([ + 'attr_one' => [ + 'text' + ], + ]); + $validator = new EachValidator(['rule' => ['integer']]); + + $validator->allowMessageFromRule = true; + $validator->validateAttribute($model, 'attr_one'); + $this->assertContains('integer', $model->getFirstError('attr_one')); + + $model->clearErrors(); + $validator->allowMessageFromRule = false; + $validator->validateAttribute($model, 'attr_one'); + $this->assertNotContains('integer', $model->getFirstError('attr_one')); + } +} \ No newline at end of file diff --git a/tests/framework/validators/EmailValidatorTest.php b/tests/framework/validators/EmailValidatorTest.php new file mode 100644 index 0000000..4365a81 --- /dev/null +++ b/tests/framework/validators/EmailValidatorTest.php @@ -0,0 +1,118 @@ +mockApplication(); + } + + public function testValidateValue() + { + $validator = new EmailValidator(); + + $this->assertTrue($validator->validate('sam@rmcreative.ru')); + $this->assertTrue($validator->validate('5011@gmail.com')); + $this->assertFalse($validator->validate('rmcreative.ru')); + $this->assertFalse($validator->validate('Carsten Brandt ')); + $this->assertFalse($validator->validate('"Carsten Brandt" ')); + $this->assertFalse($validator->validate('')); + $this->assertFalse($validator->validate('info@örtliches.de')); + $this->assertFalse($validator->validate('sam@рмкреатиф.ru')); + + $validator->allowName = true; + + $this->assertTrue($validator->validate('sam@rmcreative.ru')); + $this->assertTrue($validator->validate('5011@gmail.com')); + $this->assertFalse($validator->validate('rmcreative.ru')); + $this->assertTrue($validator->validate('Carsten Brandt ')); + $this->assertTrue($validator->validate('"Carsten Brandt" ')); + $this->assertTrue($validator->validate('')); + $this->assertFalse($validator->validate('info@örtliches.de')); + $this->assertFalse($validator->validate('sam@рмкреатиф.ru')); + $this->assertFalse($validator->validate('Informtation info@oertliches.de')); + $this->assertTrue($validator->validate('test@example.com')); + $this->assertTrue($validator->validate('John Smith ')); + $this->assertFalse($validator->validate('John Smith ')); + } + + public function testValidateValueIdn() + { + if (!function_exists('idn_to_ascii')) { + $this->markTestSkipped('Intl extension required'); + + return; + } + $validator = new EmailValidator(); + $validator->enableIDN = true; + + $this->assertTrue($validator->validate('5011@example.com')); + $this->assertTrue($validator->validate('example@äüößìà.de')); + $this->assertTrue($validator->validate('example@xn--zcack7ayc9a.de')); + $this->assertTrue($validator->validate('info@örtliches.de')); + $this->assertTrue($validator->validate('sam@рмкреатиф.ru')); + $this->assertTrue($validator->validate('sam@rmcreative.ru')); + $this->assertTrue($validator->validate('5011@gmail.com')); + $this->assertFalse($validator->validate('rmcreative.ru')); + $this->assertFalse($validator->validate('Carsten Brandt ')); + $this->assertFalse($validator->validate('"Carsten Brandt" ')); + $this->assertFalse($validator->validate('')); + + $validator->allowName = true; + + $this->assertTrue($validator->validate('info@örtliches.de')); + $this->assertTrue($validator->validate('Informtation ')); + $this->assertFalse($validator->validate('Informtation info@örtliches.de')); + $this->assertTrue($validator->validate('sam@рмкреатиф.ru')); + $this->assertTrue($validator->validate('sam@rmcreative.ru')); + $this->assertTrue($validator->validate('5011@gmail.com')); + $this->assertFalse($validator->validate('rmcreative.ru')); + $this->assertTrue($validator->validate('Carsten Brandt ')); + $this->assertTrue($validator->validate('"Carsten Brandt" ')); + $this->assertTrue($validator->validate('')); + $this->assertTrue($validator->validate('test@example.com')); + $this->assertTrue($validator->validate('John Smith ')); + $this->assertFalse($validator->validate('John Smith ')); + } + + public function testValidateValueMx() + { + $validator = new EmailValidator(); + + $validator->checkDNS = true; + $this->assertTrue($validator->validate('5011@gmail.com')); + + $validator->checkDNS = false; + $this->assertTrue($validator->validate('test@nonexistingsubdomain.example.com')); + $validator->checkDNS = true; + $this->assertFalse($validator->validate('test@nonexistingsubdomain.example.com')); + + $validator->checkDNS = true; + $validator->allowName = true; + $emails = [ + 'ipetrov@gmail.com', + 'Ivan Petrov ', + ]; + foreach($emails as $email) { + $this->assertTrue($validator->validate($email),"Email: '$email' failed to validate(checkDNS=true, allowName=true)"); + } + } + + public function testValidateAttribute() + { + $val = new EmailValidator(); + $model = new FakedValidationModel(); + $model->attr_email = '5011@gmail.com'; + $val->validateAttribute($model, 'attr_email'); + $this->assertFalse($model->hasErrors('attr_email')); + } +} diff --git a/tests/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php b/tests/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php new file mode 100644 index 0000000..af1d277 --- /dev/null +++ b/tests/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php @@ -0,0 +1,12 @@ +mockApplication(); + ActiveRecord::$db = $this->getConnection(); + } + + public function testValidateValueExpectedException() + { + try { + $val = new ExistValidator(); + $val->validate('ref'); + $this->fail('Exception should have been thrown at this time'); + } catch (Exception $e) { + $this->assertInstanceOf('yii\base\InvalidConfigException', $e); + $this->assertEquals('The "targetClass" property must be set.', $e->getMessage()); + } + // combine to save the time creating a new db-fixture set (likely ~5 sec) + try { + $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::className()]); + $val->validate('ref'); + $this->fail('Exception should have been thrown at this time'); + } catch (Exception $e) { + $this->assertInstanceOf('yii\base\InvalidConfigException', $e); + $this->assertEquals('The "targetAttribute" property must be configured as a string.', $e->getMessage()); + } + } + + public function testValidateValue() + { + $val = new ExistValidator(['targetClass' => ValidatorTestRefModel::className(), 'targetAttribute' => 'id']); + $this->assertTrue($val->validate(2)); + $this->assertTrue($val->validate(5)); + $this->assertFalse($val->validate(99)); + $this->assertFalse($val->validate(['1'])); + } + + public function testValidateAttribute() + { + // existing value on different table + $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::className(), 'targetAttribute' => 'id']); + $m = ValidatorTestRefModel::findOne(['id' => 1]); + $val->validateAttribute($m, 'ref'); + $this->assertFalse($m->hasErrors()); + // non-existing value on different table + $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::className(), 'targetAttribute' => 'id']); + $m = ValidatorTestRefModel::findOne(['id' => 6]); + $val->validateAttribute($m, 'ref'); + $this->assertTrue($m->hasErrors('ref')); + // existing value on same table + $val = new ExistValidator(['targetAttribute' => 'ref']); + $m = ValidatorTestRefModel::findOne(['id' => 2]); + $val->validateAttribute($m, 'test_val'); + $this->assertFalse($m->hasErrors()); + // non-existing value on same table + $val = new ExistValidator(['targetAttribute' => 'ref']); + $m = ValidatorTestRefModel::findOne(['id' => 5]); + $val->validateAttribute($m, 'test_val_fail'); + $this->assertTrue($m->hasErrors('test_val_fail')); + // check for given value (true) + $val = new ExistValidator(); + $m = ValidatorTestRefModel::findOne(['id' => 3]); + $val->validateAttribute($m, 'ref'); + $this->assertFalse($m->hasErrors()); + // check for given defaults (false) + $val = new ExistValidator(); + $m = ValidatorTestRefModel::findOne(['id' => 4]); + $m->a_field = 'some new value'; + $val->validateAttribute($m, 'a_field'); + $this->assertTrue($m->hasErrors('a_field')); + // existing array + $val = new ExistValidator(['targetAttribute' => 'ref']); + $val->allowArray = true; + $m = new ValidatorTestRefModel(); + $m->test_val = [2, 3, 4, 5]; + $val->validateAttribute($m, 'test_val'); + $this->assertFalse($m->hasErrors('test_val')); + // non-existing array + $val = new ExistValidator(['targetAttribute' => 'ref']); + $val->allowArray = true; + $m = new ValidatorTestRefModel(); + $m->test_val = [95, 96, 97, 98]; + $val->validateAttribute($m, 'test_val'); + $this->assertTrue($m->hasErrors('test_val')); + // partial-existing array + $val = new ExistValidator(['targetAttribute' => 'ref']); + $val->allowArray = true; + $m = new ValidatorTestRefModel(); + $m->test_val = [2, 97, 3, 98]; + $val->validateAttribute($m, 'test_val'); + $this->assertTrue($m->hasErrors('test_val')); + // existing array (allowArray = false) + $val = new ExistValidator(['targetAttribute' => 'ref']); + $val->allowArray = false; + $m = new ValidatorTestRefModel(); + $m->test_val = [2, 3, 4, 5]; + $val->validateAttribute($m, 'test_val'); + $this->assertTrue($m->hasErrors('test_val')); + // non-existing array (allowArray = false) + $val = new ExistValidator(['targetAttribute' => 'ref']); + $val->allowArray = false; + $m = new ValidatorTestRefModel(); + $m->test_val = [95, 96, 97, 98]; + $val->validateAttribute($m, 'test_val'); + $this->assertTrue($m->hasErrors('test_val')); + } + + public function testValidateCompositeKeys() + { + $val = new ExistValidator([ + 'targetClass' => OrderItem::className(), + 'targetAttribute' => ['order_id', 'item_id'], + ]); + // validate old record + $m = OrderItem::findOne(['order_id' => 1, 'item_id' => 2]); + $val->validateAttribute($m, 'order_id'); + $this->assertFalse($m->hasErrors('order_id')); + + // validate new record + $m = new OrderItem(['order_id' => 1, 'item_id' => 2]); + $val->validateAttribute($m, 'order_id'); + $this->assertFalse($m->hasErrors('order_id')); + $m = new OrderItem(['order_id' => 10, 'item_id' => 2]); + $val->validateAttribute($m, 'order_id'); + $this->assertTrue($m->hasErrors('order_id')); + + $val = new ExistValidator([ + 'targetClass' => OrderItem::className(), + 'targetAttribute' => ['id' => 'order_id'], + ]); + // validate old record + $m = Order::findOne(1); + $val->validateAttribute($m, 'id'); + $this->assertFalse($m->hasErrors('id')); + $m = Order::findOne(1); + $m->id = 10; + $val->validateAttribute($m, 'id'); + $this->assertTrue($m->hasErrors('id')); + + $m = new Order(['id' => 1]); + $val->validateAttribute($m, 'id'); + $this->assertFalse($m->hasErrors('id')); + $m = new Order(['id' => 10]); + $val->validateAttribute($m, 'id'); + $this->assertTrue($m->hasErrors('id')); + } +} diff --git a/tests/framework/validators/FileValidatorTest.php b/tests/framework/validators/FileValidatorTest.php new file mode 100644 index 0000000..d2d0358 --- /dev/null +++ b/tests/framework/validators/FileValidatorTest.php @@ -0,0 +1,377 @@ +mockApplication(); + } + + public function testAssureMessagesSetOnInit() + { + $val = new FileValidator(); + foreach (['message', 'uploadRequired', 'tooMany', 'wrongExtension', 'tooBig', 'tooSmall', 'wrongMimeType'] as $attr) { + $this->assertTrue(is_string($val->$attr)); + } + } + + public function testTypeSplitOnInit() + { + $val = new FileValidator(['extensions' => 'jpeg, jpg, gif']); + $this->assertEquals(['jpeg', 'jpg', 'gif'], $val->extensions); + + $val = new FileValidator(['extensions' => 'jpeg']); + $this->assertEquals(['jpeg'], $val->extensions); + + $val = new FileValidator(['extensions' => '']); + $this->assertEquals([], $val->extensions); + + $val = new FileValidator(['extensions' => []]); + $this->assertEquals([], $val->extensions); + + $val = new FileValidator(); + $this->assertEquals([], $val->extensions); + + $val = new FileValidator(['extensions' => ['jpeg', 'exe']]); + $this->assertEquals(['jpeg', 'exe'], $val->extensions); + } + + public function testMimeTypeSplitOnInit() + { + $val = new FileValidator(['mimeTypes' => 'text/plain, image/png']); + $this->assertEquals(['text/plain', 'image/png'], $val->mimeTypes); + + $val = new FileValidator(['mimeTypes' => 'text/plain']); + $this->assertEquals(['text/plain'], $val->mimeTypes); + + $val = new FileValidator(['mimeTypes' => '']); + $this->assertEquals([], $val->mimeTypes); + + $val = new FileValidator(['mimeTypes' => []]); + $this->assertEquals([], $val->mimeTypes); + + $val = new FileValidator(); + $this->assertEquals([], $val->mimeTypes); + + $val = new FileValidator(['mimeTypes' => ['text/plain', 'image/png']]); + $this->assertEquals(['text/plain', 'image/png'], $val->mimeTypes); + } + + public function testGetSizeLimit() + { + $size = $this->sizeToBytes(ini_get('upload_max_filesize')); + $val = new FileValidator(); + $this->assertEquals($size, $val->getSizeLimit()); + $val->maxSize = $size + 1; // set and test if value is overridden + $this->assertEquals($size, $val->getSizeLimit()); + $val->maxSize = abs($size - 1); + $this->assertEquals($size - 1, $val->getSizeLimit()); + $_POST['MAX_FILE_SIZE'] = $size + 1; + $this->assertEquals($size - 1, $val->getSizeLimit()); + $_POST['MAX_FILE_SIZE'] = abs($size - 2); + $this->assertSame($_POST['MAX_FILE_SIZE'], $val->getSizeLimit()); + } + + protected function sizeToBytes($sizeStr) + { + switch (substr($sizeStr, -1)) { + case 'M': + case 'm': + return (int) $sizeStr * 1048576; + case 'K': + case 'k': + return (int) $sizeStr * 1024; + case 'G': + case 'g': + return (int) $sizeStr * 1073741824; + default: + return (int) $sizeStr; + } + } + + public function testValidateAttributeMultiple() + { + $val = new FileValidator([ + 'maxFiles' => 2, + ]); + $m = FakedValidationModel::createWithAttributes(['attr_files' => 'path']); + $val->validateAttribute($m, 'attr_files'); + $this->assertTrue($m->hasErrors('attr_files')); + $m = FakedValidationModel::createWithAttributes(['attr_files' => []]); + $val->validateAttribute($m, 'attr_files'); + $this->assertTrue($m->hasErrors('attr_files')); + $this->assertSame($val->uploadRequired, current($m->getErrors('attr_files'))); + $m = FakedValidationModel::createWithAttributes( + [ + 'attr_files' => $this->createTestFiles( + [ + [ + 'name' => 'test_up_1.txt', + 'size' => 1024, + ], + [ + 'error' => UPLOAD_ERR_NO_FILE, + ], + ] + ) + ] + ); + $val->validateAttribute($m, 'attr_files'); + $this->assertFalse($m->hasErrors('attr_files')); + $m = FakedValidationModel::createWithAttributes([ + 'attr_files' => $this->createTestFiles([ + [''], [''], [''] + ]) + ]); + $val->validateAttribute($m, 'attr_files'); + $this->assertTrue($m->hasErrors()); + $this->assertTrue(stripos(current($m->getErrors('attr_files')), 'you can upload at most') !== false); + $m = FakedValidationModel::createWithAttributes( + [ + 'attr_images' => $this->createTestFiles( + [ + [ + 'name' => 'image.png', + 'size' => 1024, + 'type' => 'image/png' + ], + [ + 'name' => 'image.png', + 'size' => 1024, + 'type' => 'image/png' + ], + [ + 'name' => 'text.txt', + 'size' => 1024 + ], + ] + ) + ] + ); + $m->setScenario('validateMultipleFiles'); + $this->assertFalse($m->validate()); + $this->assertTrue(stripos(current($m->getErrors('attr_images')), + 'Only files with these extensions are allowed') !== false); + + $m = FakedValidationModel::createWithAttributes( + [ + 'attr_images' => $this->createTestFiles( + [ + [ + 'name' => 'image.png', + 'size' => 1024, + 'type' => 'image/png' + ], + [ + 'name' => 'image.png', + 'size' => 1024, + 'type' => 'image/png' + ], + ] + ) + ] + ); + $m->setScenario('validateMultipleFiles'); + $this->assertTrue($m->validate()); + + $m = FakedValidationModel::createWithAttributes( + [ + 'attr_image' => $this->createTestFiles( + [ + [ + 'name' => 'text.txt', + 'size' => 1024, + ], + ] + ) + ] + ); + $m->setScenario('validateFile'); + $this->assertFalse($m->validate()); + } + + /** + * @param array $params + * @return UploadedFile[] + */ + protected function createTestFiles($params = []) + { + $rndString = function ($len = 10) { + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $randomString = ''; + for ($i = 0; $i < $len; $i++) { + $randomString .= $characters[rand(0, strlen($characters) - 1)]; + } + + return $randomString; + }; + $files = []; + foreach ($params as $param) { + if (empty($param) && count($params) != 1) { + $files[] = ['no instance of UploadedFile']; + continue; + } + $name = isset($param['name']) ? $param['name'] : $rndString(); + $tempName = \Yii::getAlias('@yiiunit/runtime/validators/file/tmp/') . $name; + if (is_readable($tempName)) { + $size = filesize($tempName); + } else { + $size = isset($param['size']) ? $param['size'] : rand( + 1, + $this->sizeToBytes(ini_get('upload_max_filesize')) + ); + } + $type = isset($param['type']) ? $param['type'] : 'text/plain'; + $error = isset($param['error']) ? $param['error'] : UPLOAD_ERR_OK; + if (count($params) == 1) { + $error = empty($param) ? UPLOAD_ERR_NO_FILE : $error; + + return new UploadedFile([ + 'name' => $name, + 'tempName' => $tempName, + 'type' => $type, + 'size' => $size, + 'error' => $error + ]); + } + $files[] = new UploadedFile([ + 'name' => $name, + 'tempName' => $tempName, + 'type' => $type, + 'size' => $size, + 'error' => $error + ]); + } + + return $files; + } + + public function testValidateAttribute() + { + // single File + $val = new FileValidator(); + $m = $this->createModelForAttributeTest(); + $val->validateAttribute($m, 'attr_files'); + $this->assertFalse($m->hasErrors()); + $val->validateAttribute($m, 'attr_files_empty'); + $this->assertTrue($m->hasErrors('attr_files_empty')); + $this->assertSame($val->uploadRequired, current($m->getErrors('attr_files_empty'))); + + // single File with skipOnEmpty = false + $val = new FileValidator(['skipOnEmpty' => false]); + $m = $this->createModelForAttributeTest(); + $val->validateAttribute($m, 'attr_files'); + $this->assertFalse($m->hasErrors()); + $val->validateAttribute($m, 'attr_files_empty'); + $this->assertTrue($m->hasErrors('attr_files_empty')); + $this->assertSame($val->uploadRequired, current($m->getErrors('attr_files_empty'))); + $m = $this->createModelForAttributeTest(); + + // too big + $val = new FileValidator(['maxSize' => 128]); + $val->validateAttribute($m, 'attr_files'); + $this->assertTrue($m->hasErrors('attr_files')); + $this->assertTrue(stripos(current($m->getErrors('attr_files')), 'too big') !== false); + // to Small + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(['minSize' => 2048]); + $val->validateAttribute($m, 'attr_files'); + $this->assertTrue($m->hasErrors('attr_files')); + $this->assertTrue(stripos(current($m->getErrors('attr_files')), 'too small') !== false); + // UPLOAD_ERR_INI_SIZE/UPLOAD_ERR_FORM_SIZE + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_ini'); + $this->assertTrue($m->hasErrors('attr_err_ini')); + $this->assertTrue(stripos(current($m->getErrors('attr_err_ini')), 'too big') !== false); + // UPLOAD_ERR_PARTIAL + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_part'); + $this->assertTrue($m->hasErrors('attr_err_part')); + $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_part'))); + } + + public function testValidateAttributeType() + { + $val = new FileValidator([ + 'extensions' => 'jpeg, jpg', + 'checkExtensionByMimeType' => false, + ]); + $m = FakedValidationModel::createWithAttributes( + [ + 'attr_jpg' => $this->createTestFiles([['name' => 'one.jpeg']]), + 'attr_exe' => $this->createTestFiles([['name' => 'bad.exe']]), + ] + ); + $val->validateAttribute($m, 'attr_jpg'); + $this->assertFalse($m->hasErrors('attr_jpg')); + $val->validateAttribute($m, 'attr_exe'); + $this->assertTrue($m->hasErrors('attr_exe')); + $this->assertTrue(stripos(current($m->getErrors('attr_exe')), 'Only files with these extensions ') !== false); + } + + protected function createModelForAttributeTest() + { + return FakedValidationModel::createWithAttributes( + [ + 'attr_files' => $this->createTestFiles([ + ['name' => 'abc.jpg', 'size' => 1024, 'type' => 'image/jpeg'], + ]), + 'attr_files_empty' => $this->createTestFiles([[]]), + 'attr_err_ini' => $this->createTestFiles([['error' => UPLOAD_ERR_INI_SIZE]]), + 'attr_err_part' => $this->createTestFiles([['error' => UPLOAD_ERR_PARTIAL]]), + 'attr_err_tmp' => $this->createTestFiles([['error' => UPLOAD_ERR_NO_TMP_DIR]]), + 'attr_err_write' => $this->createTestFiles([['error' => UPLOAD_ERR_CANT_WRITE]]), + 'attr_err_ext' => $this->createTestFiles([['error' => UPLOAD_ERR_EXTENSION]]), + ] + ); + } + + public function testValidateAttributeErrPartial() + { + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_part'); + $this->assertTrue($m->hasErrors('attr_err_part')); + $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_part'))); + } + + public function testValidateAttributeErrCantWrite() + { + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_write'); + $this->assertTrue($m->hasErrors('attr_err_write')); + $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_write'))); + } + + public function testValidateAttributeErrExtension() + { + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_ext'); + $this->assertTrue($m->hasErrors('attr_err_ext')); + $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_ext'))); + } + + public function testValidateAttributeErrNoTmpDir() + { + $m = $this->createModelForAttributeTest(); + $val = new FileValidator(); + $val->validateAttribute($m, 'attr_err_tmp'); + $this->assertTrue($m->hasErrors('attr_err_tmp')); + $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_tmp'))); + } +} diff --git a/tests/framework/validators/FilterValidatorTest.php b/tests/framework/validators/FilterValidatorTest.php new file mode 100644 index 0000000..1b77047 --- /dev/null +++ b/tests/framework/validators/FilterValidatorTest.php @@ -0,0 +1,66 @@ +mockApplication(); + } + + public function testAssureExceptionOnInit() + { + $this->setExpectedException('yii\base\InvalidConfigException'); + new FilterValidator(); + } + + public function testValidateAttribute() + { + $m = FakedValidationModel::createWithAttributes([ + 'attr_one' => ' to be trimmed ', + 'attr_two' => 'set this to null', + 'attr_empty1' => '', + 'attr_empty2' => null, + 'attr_array' => ['Maria', 'Anna', 'Elizabeth'], + 'attr_array_skipped' => ['John', 'Bill'] + ]); + $val = new FilterValidator(['filter' => 'trim']); + $val->validateAttribute($m, 'attr_one'); + $this->assertSame('to be trimmed', $m->attr_one); + $val->filter = function ($value) { + return null; + }; + $val->validateAttribute($m, 'attr_two'); + $this->assertNull($m->attr_two); + $val->filter = [$this, 'notToBeNull']; + $val->validateAttribute($m, 'attr_empty1'); + $this->assertSame($this->notToBeNull(''), $m->attr_empty1); + $val->skipOnEmpty = true; + $val->validateAttribute($m, 'attr_empty2'); + $this->assertNotNull($m->attr_empty2); + $val->filter = function($value) { + + return implode(',', $value); + }; + $val->skipOnArray = false; + $val->validateAttribute($m, 'attr_array'); + $this->assertSame('Maria,Anna,Elizabeth', $m->attr_array); + $val->skipOnArray = true; + $val->validateAttribute($m, 'attr_array_skipped'); + $this->assertSame(['John', 'Bill'], $m->attr_array_skipped); + } + + public function notToBeNull($value) + { + return 'not null'; + } +} diff --git a/tests/framework/validators/NumberValidatorTest.php b/tests/framework/validators/NumberValidatorTest.php new file mode 100644 index 0000000..47bb1bb --- /dev/null +++ b/tests/framework/validators/NumberValidatorTest.php @@ -0,0 +1,211 @@ +mockApplication(); + } + + public function testEnsureMessageOnInit() + { + $val = new NumberValidator; + $this->assertTrue(is_string($val->message)); + $this->assertTrue(is_null($val->max)); + $val = new NumberValidator(['min' => -1, 'max' => 20, 'integerOnly' => true]); + $this->assertTrue(is_string($val->message)); + $this->assertTrue(is_string($val->tooSmall)); + $this->assertTrue(is_string($val->tooBig)); + } + + public function testValidateValueSimple() + { + $val = new NumberValidator(); + $this->assertTrue($val->validate(20)); + $this->assertTrue($val->validate(0)); + $this->assertTrue($val->validate(-20)); + $this->assertTrue($val->validate('20')); + $this->assertTrue($val->validate(25.45)); + $this->assertFalse($val->validate('25,45')); + $this->assertFalse($val->validate('12:45')); + $val = new NumberValidator(['integerOnly' => true]); + $this->assertTrue($val->validate(20)); + $this->assertTrue($val->validate(0)); + $this->assertFalse($val->validate(25.45)); + $this->assertTrue($val->validate('20')); + $this->assertFalse($val->validate('25,45')); + $this->assertTrue($val->validate('020')); + $this->assertTrue($val->validate(0x14)); + $this->assertFalse($val->validate('0x14')); // todo check this + } + + public function testValidateValueAdvanced() + { + $val = new NumberValidator(); + $this->assertTrue($val->validate('-1.23')); // signed float + $this->assertTrue($val->validate('-4.423e-12')); // signed float + exponent + $this->assertTrue($val->validate('12E3')); // integer + exponent + $this->assertFalse($val->validate('e12')); // just exponent + $this->assertFalse($val->validate('-e3')); + $this->assertFalse($val->validate('-4.534-e-12')); // 'signed' exponent + $this->assertFalse($val->validate('12.23^4')); // expression instead of value + $val = new NumberValidator(['integerOnly' => true]); + $this->assertFalse($val->validate('-1.23')); + $this->assertFalse($val->validate('-4.423e-12')); + $this->assertFalse($val->validate('12E3')); + $this->assertFalse($val->validate('e12')); + $this->assertFalse($val->validate('-e3')); + $this->assertFalse($val->validate('-4.534-e-12')); + $this->assertFalse($val->validate('12.23^4')); + } + + public function testValidateValueMin() + { + $val = new NumberValidator(['min' => 1]); + $this->assertTrue($val->validate(1)); + $this->assertFalse($val->validate(-1)); + $this->assertFalse($val->validate('22e-12')); + $this->assertTrue($val->validate(PHP_INT_MAX + 1)); + $val = new NumberValidator(['min' => 1], ['integerOnly' => true]); + $this->assertTrue($val->validate(1)); + $this->assertFalse($val->validate(-1)); + $this->assertFalse($val->validate('22e-12')); + $this->assertTrue($val->validate(PHP_INT_MAX + 1)); + } + + public function testValidateValueMax() + { + $val = new NumberValidator(['max' => 1.25]); + $this->assertTrue($val->validate(1)); + $this->assertFalse($val->validate(1.5)); + $this->assertTrue($val->validate('22e-12')); + $this->assertTrue($val->validate('125e-2')); + $val = new NumberValidator(['max' => 1.25, 'integerOnly' => true]); + $this->assertTrue($val->validate(1)); + $this->assertFalse($val->validate(1.5)); + $this->assertFalse($val->validate('22e-12')); + $this->assertFalse($val->validate('125e-2')); + } + + public function testValidateValueRange() + { + $val = new NumberValidator(['min' => -10, 'max' => 20]); + $this->assertTrue($val->validate(0)); + $this->assertTrue($val->validate(-10)); + $this->assertFalse($val->validate(-11)); + $this->assertFalse($val->validate(21)); + $val = new NumberValidator(['min' => -10, 'max' => 20, 'integerOnly' => true]); + $this->assertTrue($val->validate(0)); + $this->assertFalse($val->validate(-11)); + $this->assertFalse($val->validate(22)); + $this->assertFalse($val->validate('20e-1')); + } + + public function testValidateAttribute() + { + $val = new NumberValidator(); + $model = new FakedValidationModel(); + $model->attr_number = '5.5e1'; + $val->validateAttribute($model, 'attr_number'); + $this->assertFalse($model->hasErrors('attr_number')); + $model->attr_number = '43^32'; //expression + $val->validateAttribute($model, 'attr_number'); + $this->assertTrue($model->hasErrors('attr_number')); + $val = new NumberValidator(['min' => 10]); + $model = new FakedValidationModel(); + $model->attr_number = 10; + $val->validateAttribute($model, 'attr_number'); + $this->assertFalse($model->hasErrors('attr_number')); + $model->attr_number = 5; + $val->validateAttribute($model, 'attr_number'); + $this->assertTrue($model->hasErrors('attr_number')); + $val = new NumberValidator(['max' => 10]); + $model = new FakedValidationModel(); + $model->attr_number = 10; + $val->validateAttribute($model, 'attr_number'); + $this->assertFalse($model->hasErrors('attr_number')); + $model->attr_number = 15; + $val->validateAttribute($model, 'attr_number'); + $this->assertTrue($model->hasErrors('attr_number')); + $val = new NumberValidator(['max' => 10, 'integerOnly' => true]); + $model = new FakedValidationModel(); + $model->attr_number = 10; + $val->validateAttribute($model, 'attr_number'); + $this->assertFalse($model->hasErrors('attr_number')); + $model->attr_number = 3.43; + $val->validateAttribute($model, 'attr_number'); + $this->assertTrue($model->hasErrors('attr_number')); + $val = new NumberValidator(['min' => 1]); + $model = FakedValidationModel::createWithAttributes(['attr_num' => [1, 2, 3]]); + $val->validateAttribute($model, 'attr_num'); + $this->assertTrue($model->hasErrors('attr_num')); + } + + public function testEnsureCustomMessageIsSetOnValidateAttribute() + { + $val = new NumberValidator([ + 'tooSmall' => '{attribute} is to small.', + 'min' => 5 + ]); + $model = new FakedValidationModel(); + $model->attr_number = 0; + $val->validateAttribute($model, 'attr_number'); + $this->assertTrue($model->hasErrors('attr_number')); + $this->assertEquals(1, count($model->getErrors('attr_number'))); + $msgs = $model->getErrors('attr_number'); + $this->assertSame('attr_number is to small.', $msgs[0]); + } + + /** + * https://github.com/yiisoft/yii2/issues/3118 + */ + public function testClientValidateComparison() + { + $val = new NumberValidator([ + 'min' => 5, + 'max' => 10, + ]); + $model = new FakedValidationModel(); + $js = $val->clientValidateAttribute($model, 'attr_number', new View(['assetBundles' => ['yii\validators\ValidationAsset' => true]])); + $this->assertContains('"min":5', $js); + $this->assertContains('"max":10', $js); + + $val = new NumberValidator([ + 'min' => '5', + 'max' => '10', + ]); + $model = new FakedValidationModel(); + $js = $val->clientValidateAttribute($model, 'attr_number', new View(['assetBundles' => ['yii\validators\ValidationAsset' => true]])); + $this->assertContains('"min":5', $js); + $this->assertContains('"max":10', $js); + + $val = new NumberValidator([ + 'min' => 5.65, + 'max' => 13.37, + ]); + $model = new FakedValidationModel(); + $js = $val->clientValidateAttribute($model, 'attr_number', new View(['assetBundles' => ['yii\validators\ValidationAsset' => true]])); + $this->assertContains('"min":5.65', $js); + $this->assertContains('"max":13.37', $js); + + $val = new NumberValidator([ + 'min' => '5.65', + 'max' => '13.37', + ]); + $model = new FakedValidationModel(); + $js = $val->clientValidateAttribute($model, 'attr_number', new View(['assetBundles' => ['yii\validators\ValidationAsset' => true]])); + $this->assertContains('"min":5.65', $js); + $this->assertContains('"max":13.37', $js); + } +} diff --git a/tests/framework/validators/RangeValidatorTest.php b/tests/framework/validators/RangeValidatorTest.php new file mode 100644 index 0000000..b4cbf32 --- /dev/null +++ b/tests/framework/validators/RangeValidatorTest.php @@ -0,0 +1,108 @@ +mockApplication(); + } + + public function testInitException() + { + $this->setExpectedException('yii\base\InvalidConfigException', 'The "range" property must be set.'); + new RangeValidator(['range' => 'not an array']); + } + + public function testAssureMessageSetOnInit() + { + $val = new RangeValidator(['range' => []]); + $this->assertTrue(is_string($val->message)); + } + + public function testValidateValue() + { + $val = new RangeValidator(['range' => range(1, 10, 1)]); + $this->assertTrue($val->validate(1)); + $this->assertFalse($val->validate(0)); + $this->assertFalse($val->validate(11)); + $this->assertFalse($val->validate(5.5)); + $this->assertTrue($val->validate(10)); + $this->assertTrue($val->validate("10")); + $this->assertTrue($val->validate("5")); + } + + public function testValidateValueEmpty() + { + $val = new RangeValidator(['range' => range(10, 20, 1), 'skipOnEmpty' => false]); + $this->assertFalse($val->validate(null)); //row RangeValidatorTest.php:101 + $this->assertFalse($val->validate('0')); + $this->assertFalse($val->validate(0)); + $this->assertFalse($val->validate('')); + $val->allowArray = true; + $this->assertTrue($val->validate([])); + } + + public function testValidateArrayValue() + { + $val = new RangeValidator(['range' => range(1, 10, 1)]); + $val->allowArray = true; + $this->assertTrue($val->validate([1, 2, 3, 4, 5])); + $this->assertTrue($val->validate([6, 7, 8, 9, 10])); + $this->assertFalse($val->validate([0, 1, 2])); + $this->assertFalse($val->validate([10, 11, 12])); + $this->assertTrue($val->validate(["1", "2", "3", 4, 5, 6])); + } + + public function testValidateValueStrict() + { + $val = new RangeValidator(['range' => range(1, 10, 1), 'strict' => true]); + $this->assertTrue($val->validate(1)); + $this->assertTrue($val->validate(5)); + $this->assertTrue($val->validate(10)); + $this->assertFalse($val->validate("1")); + $this->assertFalse($val->validate("10")); + $this->assertFalse($val->validate("5.5")); + } + + public function testValidateArrayValueStrict() + { + $val = new RangeValidator(['range' => range(1, 10, 1), 'strict' => true]); + $val->allowArray = true; + $this->assertFalse($val->validate(["1", "2", "3", "4", "5", "6"])); + $this->assertFalse($val->validate(["1", "2", "3", 4, 5, 6])); + } + + public function testValidateValueNot() + { + $val = new RangeValidator(['range' => range(1, 10, 1), 'not' => true]); + $this->assertFalse($val->validate(1)); + $this->assertTrue($val->validate(0)); + $this->assertTrue($val->validate(11)); + $this->assertTrue($val->validate(5.5)); + $this->assertFalse($val->validate(10)); + $this->assertFalse($val->validate("10")); + $this->assertFalse($val->validate("5")); + } + + public function testValidateAttribute() + { + $val = new RangeValidator(['range' => range(1, 10, 1)]); + $m = FakedValidationModel::createWithAttributes(['attr_r1' => 5, 'attr_r2' => 999]); + $val->validateAttribute($m, 'attr_r1'); + $this->assertFalse($m->hasErrors()); + $val->validateAttribute($m, 'attr_r2'); + $this->assertTrue($m->hasErrors('attr_r2')); + $err = $m->getErrors('attr_r2'); + $this->assertTrue(stripos($err[0], 'attr_r2') !== false); + } +} diff --git a/tests/framework/validators/RegularExpressionValidatorTest.php b/tests/framework/validators/RegularExpressionValidatorTest.php new file mode 100644 index 0000000..e9c3ce7 --- /dev/null +++ b/tests/framework/validators/RegularExpressionValidatorTest.php @@ -0,0 +1,55 @@ +mockApplication(); + } + + public function testValidateValue() + { + $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); + $this->assertTrue($val->validate('b.4')); + $this->assertFalse($val->validate('b./')); + $this->assertFalse($val->validate(['a', 'b'])); + $val->not = true; + $this->assertFalse($val->validate('b.4')); + $this->assertTrue($val->validate('b./')); + $this->assertFalse($val->validate(['a', 'b'])); + } + + public function testValidateAttribute() + { + $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); + $m = FakedValidationModel::createWithAttributes(['attr_reg1' => 'b.4']); + $val->validateAttribute($m, 'attr_reg1'); + $this->assertFalse($m->hasErrors('attr_reg1')); + $m->attr_reg1 = 'b./'; + $val->validateAttribute($m, 'attr_reg1'); + $this->assertTrue($m->hasErrors('attr_reg1')); + } + + public function testMessageSetOnInit() + { + $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); + $this->assertTrue(is_string($val->message)); + } + + public function testInitException() + { + $this->setExpectedException('yii\base\InvalidConfigException'); + $val = new RegularExpressionValidator(); + $val->validate('abc'); + } +} diff --git a/tests/framework/validators/RequiredValidatorTest.php b/tests/framework/validators/RequiredValidatorTest.php new file mode 100644 index 0000000..ce62773 --- /dev/null +++ b/tests/framework/validators/RequiredValidatorTest.php @@ -0,0 +1,62 @@ +mockApplication(); + } + + public function testValidateValueWithDefaults() + { + $val = new RequiredValidator(); + $this->assertFalse($val->validate(null)); + $this->assertFalse($val->validate([])); + $this->assertTrue($val->validate('not empty')); + $this->assertTrue($val->validate(['with', 'elements'])); + } + + public function testValidateValueWithValue() + { + $val = new RequiredValidator(['requiredValue' => 55]); + $this->assertTrue($val->validate(55)); + $this->assertTrue($val->validate("55")); + $this->assertTrue($val->validate("0x37")); + $this->assertFalse($val->validate("should fail")); + $this->assertTrue($val->validate(true)); + $val->strict = true; + $this->assertTrue($val->validate(55)); + $this->assertFalse($val->validate("55")); + $this->assertFalse($val->validate("0x37")); + $this->assertFalse($val->validate("should fail")); + $this->assertFalse($val->validate(true)); + } + + public function testValidateAttribute() + { + // empty req-value + $val = new RequiredValidator(); + $m = FakedValidationModel::createWithAttributes(['attr_val' => null]); + $val->validateAttribute($m, 'attr_val'); + $this->assertTrue($m->hasErrors('attr_val')); + $this->assertTrue(stripos(current($m->getErrors('attr_val')), 'blank') !== false); + $val = new RequiredValidator(['requiredValue' => 55]); + $m = FakedValidationModel::createWithAttributes(['attr_val' => 56]); + $val->validateAttribute($m, 'attr_val'); + $this->assertTrue($m->hasErrors('attr_val')); + $this->assertTrue(stripos(current($m->getErrors('attr_val')), 'must be') !== false); + $val = new RequiredValidator(['requiredValue' => 55]); + $m = FakedValidationModel::createWithAttributes(['attr_val' => 55]); + $val->validateAttribute($m, 'attr_val'); + $this->assertFalse($m->hasErrors('attr_val')); + } +} diff --git a/tests/framework/validators/StringValidatorTest.php b/tests/framework/validators/StringValidatorTest.php new file mode 100644 index 0000000..3f6100f --- /dev/null +++ b/tests/framework/validators/StringValidatorTest.php @@ -0,0 +1,118 @@ +mockApplication(); + } + + public function testValidateValue() + { + $val = new StringValidator(); + $this->assertFalse($val->validate(['not a string'])); + $this->assertTrue($val->validate('Just some string')); + } + + public function testValidateValueLength() + { + $val = new StringValidator(['length' => 25]); + $this->assertTrue($val->validate(str_repeat('x', 25))); + $this->assertTrue($val->validate(str_repeat('€', 25))); + $this->assertFalse($val->validate(str_repeat('x', 125))); + $this->assertFalse($val->validate('')); + $val = new StringValidator(['length' => [25]]); + $this->assertTrue($val->validate(str_repeat('x', 25))); + $this->assertTrue($val->validate(str_repeat('x', 1250))); + $this->assertFalse($val->validate(str_repeat('Ä', 24))); + $this->assertFalse($val->validate('')); + $val = new StringValidator(['length' => [10, 20]]); + $this->assertTrue($val->validate(str_repeat('x', 15))); + $this->assertTrue($val->validate(str_repeat('x', 10))); + $this->assertTrue($val->validate(str_repeat('x', 20))); + $this->assertFalse($val->validate(str_repeat('x', 5))); + $this->assertFalse($val->validate(str_repeat('x', 25))); + $this->assertFalse($val->validate('')); + // make sure min/max are overridden + $val = new StringValidator(['length' => [10, 20], 'min' => 25, 'max' => 35]); + $this->assertTrue($val->validate(str_repeat('x', 15))); + $this->assertFalse($val->validate(str_repeat('x', 30))); + } + + public function testValidateValueMinMax() + { + $val = new StringValidator(['min' => 10]); + $this->assertTrue($val->validate(str_repeat('x', 10))); + $this->assertFalse($val->validate('xxxx')); + $val = new StringValidator(['max' => 10]); + $this->assertTrue($val->validate('xxxx')); + $this->assertFalse($val->validate(str_repeat('y', 20))); + $val = new StringValidator(['min' => 10, 'max' => 20]); + $this->assertTrue($val->validate(str_repeat('y', 15))); + $this->assertFalse($val->validate('abc')); + $this->assertFalse($val->validate(str_repeat('b', 25))); + } + + public function testValidateAttribute() + { + $val = new StringValidator(); + $model = new FakedValidationModel(); + $model->attr_string = 'a tet string'; + $val->validateAttribute($model, 'attr_string'); + $this->assertFalse($model->hasErrors()); + $val = new StringValidator(['length' => 20]); + $model = new FakedValidationModel(); + $model->attr_string = str_repeat('x', 20); + $val->validateAttribute($model, 'attr_string'); + $this->assertFalse($model->hasErrors()); + $model = new FakedValidationModel(); + $model->attr_string = 'abc'; + $val->validateAttribute($model, 'attr_string'); + $this->assertTrue($model->hasErrors('attr_string')); + $val = new StringValidator(['max' => 2]); + $model = new FakedValidationModel(); + $model->attr_string = 'a'; + $val->validateAttribute($model, 'attr_string'); + $this->assertFalse($model->hasErrors()); + $model = new FakedValidationModel(); + $model->attr_string = 'abc'; + $val->validateAttribute($model, 'attr_string'); + $this->assertTrue($model->hasErrors('attr_string')); + $val = new StringValidator(['max' => 1]); + $model = FakedValidationModel::createWithAttributes(['attr_str' => ['abc']]); + $val->validateAttribute($model, 'attr_str'); + $this->assertTrue($model->hasErrors('attr_str')); + } + + public function testEnsureMessagesOnInit() + { + $val = new StringValidator(['min' => 1, 'max' => 2]); + $this->assertTrue(is_string($val->message)); + $this->assertTrue(is_string($val->tooLong)); + $this->assertTrue(is_string($val->tooShort)); + } + + public function testCustomErrorMessageInValidateAttribute() + { + $val = new StringValidator([ + 'min' => 5, + 'tooShort' => '{attribute} to short. Min is {min}', + ]); + $model = new FakedValidationModel(); + $model->attr_string = 'abc'; + $val->validateAttribute($model, 'attr_string'); + $this->assertTrue($model->hasErrors('attr_string')); + $errorMsg = $model->getErrors('attr_string'); + $this->assertEquals('attr_string to short. Min is 5', $errorMsg[0]); + } +} diff --git a/tests/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php b/tests/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php new file mode 100644 index 0000000..d892193 --- /dev/null +++ b/tests/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php @@ -0,0 +1,13 @@ +mockApplication(); + ActiveRecord::$db = $this->getConnection(); + } + + public function testAssureMessageSetOnInit() + { + $val = new UniqueValidator(); + $this->assertTrue(is_string($val->message)); + } + + public function testValidateAttributeDefault() + { + $val = new UniqueValidator(); + $m = ValidatorTestMainModel::find()->one(); + $val->validateAttribute($m, 'id'); + $this->assertFalse($m->hasErrors('id')); + $m = ValidatorTestRefModel::findOne(1); + $val->validateAttribute($m, 'ref'); + $this->assertTrue($m->hasErrors('ref')); + // new record: + $m = new ValidatorTestRefModel(); + $m->ref = 5; + $val->validateAttribute($m, 'ref'); + $this->assertTrue($m->hasErrors('ref')); + $m = new ValidatorTestRefModel(); + $m->id = 7; + $m->ref = 12121; + $val->validateAttribute($m, 'ref'); + $this->assertFalse($m->hasErrors('ref')); + $m->save(false); + $val->validateAttribute($m, 'ref'); + $this->assertFalse($m->hasErrors('ref')); + // array error + $m = FakedValidationModel::createWithAttributes(['attr_arr' => ['a', 'b']]); + $val->validateAttribute($m, 'attr_arr'); + $this->assertTrue($m->hasErrors('attr_arr')); + } + + public function testValidateAttributeOfNonARModel() + { + $val = new UniqueValidator(['targetClass' => ValidatorTestRefModel::className(), 'targetAttribute' => 'ref']); + $m = FakedValidationModel::createWithAttributes(['attr_1' => 5, 'attr_2' => 1313]); + $val->validateAttribute($m, 'attr_1'); + $this->assertTrue($m->hasErrors('attr_1')); + $val->validateAttribute($m, 'attr_2'); + $this->assertFalse($m->hasErrors('attr_2')); + } + + public function testValidateNonDatabaseAttribute() + { + $val = new UniqueValidator(['targetClass' => ValidatorTestRefModel::className(), 'targetAttribute' => 'ref']); + $m = ValidatorTestMainModel::findOne(1); + $val->validateAttribute($m, 'testMainVal'); + $this->assertFalse($m->hasErrors('testMainVal')); + $m = ValidatorTestMainModel::findOne(1); + $m->testMainVal = 4; + $val->validateAttribute($m, 'testMainVal'); + $this->assertTrue($m->hasErrors('testMainVal')); + } + + public function testValidateAttributeAttributeNotInTableException() + { + $this->setExpectedException('yii\db\Exception'); + $val = new UniqueValidator(); + $m = new ValidatorTestMainModel(); + $val->validateAttribute($m, 'testMainVal'); + } + + public function testValidateCompositeKeys() + { + $val = new UniqueValidator([ + 'targetClass' => OrderItem::className(), + 'targetAttribute' => ['order_id', 'item_id'], + ]); + // validate old record + $m = OrderItem::findOne(['order_id' => 1, 'item_id' => 2]); + $val->validateAttribute($m, 'order_id'); + $this->assertFalse($m->hasErrors('order_id')); + $m->item_id = 1; + $val->validateAttribute($m, 'order_id'); + $this->assertTrue($m->hasErrors('order_id')); + + // validate new record + $m = new OrderItem(['order_id' => 1, 'item_id' => 2]); + $val->validateAttribute($m, 'order_id'); + $this->assertTrue($m->hasErrors('order_id')); + $m = new OrderItem(['order_id' => 10, 'item_id' => 2]); + $val->validateAttribute($m, 'order_id'); + $this->assertFalse($m->hasErrors('order_id')); + + $val = new UniqueValidator([ + 'targetClass' => OrderItem::className(), + 'targetAttribute' => ['id' => 'order_id'], + ]); + // validate old record + $m = Order::findOne(1); + $val->validateAttribute($m, 'id'); + $this->assertTrue($m->hasErrors('id')); + $m = Order::findOne(1); + $m->id = 2; + $val->validateAttribute($m, 'id'); + $this->assertTrue($m->hasErrors('id')); + $m = Order::findOne(1); + $m->id = 10; + $val->validateAttribute($m, 'id'); + $this->assertFalse($m->hasErrors('id')); + + $m = new Order(['id' => 1]); + $val->validateAttribute($m, 'id'); + $this->assertTrue($m->hasErrors('id')); + $m = new Order(['id' => 10]); + $val->validateAttribute($m, 'id'); + $this->assertFalse($m->hasErrors('id')); + } +} diff --git a/tests/framework/validators/UrlValidatorTest.php b/tests/framework/validators/UrlValidatorTest.php new file mode 100644 index 0000000..5ae66c9 --- /dev/null +++ b/tests/framework/validators/UrlValidatorTest.php @@ -0,0 +1,103 @@ +mockApplication(); + } + + public function testValidateValue() + { + $val = new UrlValidator; + $this->assertFalse($val->validate('google.de')); + $this->assertTrue($val->validate('http://google.de')); + $this->assertTrue($val->validate('https://google.de')); + $this->assertFalse($val->validate('htp://yiiframework.com')); + $this->assertTrue($val->validate('https://www.google.de/search?q=yii+framework&ie=utf-8&oe=utf-8' + .'&rls=org.mozilla:de:official&client=firefox-a&gws_rd=cr')); + $this->assertFalse($val->validate('ftp://ftp.ruhr-uni-bochum.de/')); + $this->assertFalse($val->validate('http://invalid,domain')); + $this->assertFalse($val->validate('http://äüö?=!"§$%&/()=}][{³²€.edu')); + } + + public function testValidateValueWithDefaultScheme() + { + $val = new UrlValidator(['defaultScheme' => 'https']); + $this->assertTrue($val->validate('yiiframework.com')); + $this->assertTrue($val->validate('http://yiiframework.com')); + } + + public function testValidateValueWithoutScheme() + { + $val = new UrlValidator(['pattern' => '/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)/i']); + $this->assertTrue($val->validate('yiiframework.com')); + } + + public function testValidateWithCustomScheme() + { + $val = new UrlValidator([ + 'validSchemes' => ['http', 'https', 'ftp', 'ftps'], + 'defaultScheme' => 'http', + ]); + $this->assertTrue($val->validate('ftp://ftp.ruhr-uni-bochum.de/')); + $this->assertTrue($val->validate('google.de')); + $this->assertTrue($val->validate('http://google.de')); + $this->assertTrue($val->validate('https://google.de')); + $this->assertFalse($val->validate('htp://yiiframework.com')); + // relative urls not supported + $this->assertFalse($val->validate('//yiiframework.com')); + } + + public function testValidateWithIdn() + { + if (!function_exists('idn_to_ascii')) { + $this->markTestSkipped('intl package required'); + + return; + } + $val = new UrlValidator([ + 'enableIDN' => true, + ]); + $this->assertTrue($val->validate('http://äüößìà.de')); + // converted via http://mct.verisign-grs.com/convertServlet + $this->assertTrue($val->validate('http://xn--zcack7ayc9a.de')); + } + + public function testValidateLength() + { + $url = 'http://' . str_pad('base', 2000, 'url') . '.de'; + $val = new UrlValidator; + $this->assertFalse($val->validate($url)); + } + + public function testValidateAttributeAndError() + { + $obj = new FakedValidationModel; + $obj->attr_url = 'http://google.de'; + $val = new UrlValidator; + $val->validateAttribute($obj, 'attr_url'); + $this->assertFalse($obj->hasErrors('attr_url')); + $this->assertSame('http://google.de', $obj->attr_url); + $obj = new FakedValidationModel; + $val->defaultScheme = 'http'; + $obj->attr_url = 'google.de'; + $val->validateAttribute($obj, 'attr_url'); + $this->assertFalse($obj->hasErrors('attr_url')); + $this->assertTrue(stripos($obj->attr_url, 'http') !== false); + $obj = new FakedValidationModel; + $obj->attr_url = 'gttp;/invalid string'; + $val->validateAttribute($obj, 'attr_url'); + $this->assertTrue($obj->hasErrors('attr_url')); + } +} diff --git a/tests/framework/validators/ValidatorTest.php b/tests/framework/validators/ValidatorTest.php new file mode 100644 index 0000000..b5ae88a --- /dev/null +++ b/tests/framework/validators/ValidatorTest.php @@ -0,0 +1,228 @@ +mockApplication(); + } + + protected function getTestModel($additionalAttributes = []) + { + $attributes = array_merge( + ['attr_runMe1' => true, 'attr_runMe2' => true, 'attr_skip' => true], + $additionalAttributes + ); + + return FakedValidationModel::createWithAttributes($attributes); + } + + public function testCreateValidator() + { + $model = FakedValidationModel::createWithAttributes(['attr_test1' => 'abc', 'attr_test2' => '2013']); + /* @var $numberVal NumberValidator */ + $numberVal = TestValidator::createValidator('number', $model, ['attr_test1']); + $this->assertInstanceOf(NumberValidator::className(), $numberVal); + $numberVal = TestValidator::createValidator('integer', $model, ['attr_test2']); + $this->assertInstanceOf(NumberValidator::className(), $numberVal); + $this->assertTrue($numberVal->integerOnly); + $val = TestValidator::createValidator( + 'boolean', + $model, + ['attr_test1', 'attr_test2'], + ['on' => ['a', 'b']] + ); + $this->assertInstanceOf(BooleanValidator::className(), $val); + $this->assertSame(['a', 'b'], $val->on); + $this->assertSame(['attr_test1', 'attr_test2'], $val->attributes); + $val = TestValidator::createValidator( + 'boolean', + $model, + ['attr_test1', 'attr_test2'], + ['on' => ['a', 'b'], 'except' => ['c', 'd', 'e']] + ); + $this->assertInstanceOf(BooleanValidator::className(), $val); + $this->assertSame(['a', 'b'], $val->on); + $this->assertSame(['c', 'd', 'e'], $val->except); + $val = TestValidator::createValidator('inlineVal', $model, ['val_attr_a'], ['params' => ['foo' => 'bar']]); + $this->assertInstanceOf(InlineValidator::className(), $val); + $this->assertSame('inlineVal', $val->method); + $this->assertSame(['foo' => 'bar'], $val->params); + } + + public function testValidate() + { + $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2']]); + $model = $this->getTestModel(); + $val->validateAttributes($model); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + } + + public function testValidateWithAttributeIntersect() + { + $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2']]); + $model = $this->getTestModel(); + $val->validateAttributes($model, ['attr_runMe1']); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertFalse($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + } + + public function testValidateWithEmptyAttributes() + { + $val = new TestValidator(); + $model = $this->getTestModel(); + $val->validateAttributes($model, ['attr_runMe1']); + $this->assertFalse($val->isAttributeValidated('attr_runMe1')); + $this->assertFalse($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + $val->validateAttributes($model); + $this->assertFalse($val->isAttributeValidated('attr_runMe1')); + $this->assertFalse($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + } + + public function testValidateWithError() + { + $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2'], 'skipOnError' => false]); + $model = $this->getTestModel(); + $val->validateAttributes($model); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe2')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); + $val->validateAttributes($model, ['attr_runMe2']); + $this->assertEquals(2, $val->countAttributeValidations('attr_runMe2')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); + $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); + $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2'], 'skipOnError' => true]); + $model = $this->getTestModel(); + $val->enableErrorOnValidateAttribute(); + $val->validateAttributes($model); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_skip')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); + $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); + $val->validateAttributes($model, ['attr_runMe2']); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe2')); + $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); + $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); + } + + public function testValidateWithEmpty() + { + $val = new TestValidator([ + 'attributes' => [ + 'attr_runMe1', + 'attr_runMe2', + 'attr_empty1', + 'attr_empty2' + ], + 'skipOnEmpty' => true, + ]); + $model = $this->getTestModel(['attr_empty1' => '', 'attr_emtpy2' => ' ']); + $val->validateAttributes($model); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe2')); + $this->assertFalse($val->isAttributeValidated('attr_empty1')); + $this->assertFalse($val->isAttributeValidated('attr_empty2')); + $model->attr_empty1 = 'not empty anymore'; + $val->validateAttributes($model); + $this->assertTrue($val->isAttributeValidated('attr_empty1')); + $this->assertFalse($val->isAttributeValidated('attr_empty2')); + $val = new TestValidator([ + 'attributes' => [ + 'attr_runMe1', + 'attr_runMe2', + 'attr_empty1', + 'attr_empty2' + ], + 'skipOnEmpty' => false, + ]); + $model = $this->getTestModel(['attr_empty1' => '', 'attr_emtpy2' => ' ']); + $val->validateAttributes($model); + $this->assertTrue($val->isAttributeValidated('attr_runMe1')); + $this->assertTrue($val->isAttributeValidated('attr_runMe2')); + $this->assertTrue($val->isAttributeValidated('attr_empty1')); + $this->assertTrue($val->isAttributeValidated('attr_empty2')); + } + + public function testIsEmpty() + { + $val = new TestValidator(); + $this->assertTrue($val->isEmpty(null)); + $this->assertTrue($val->isEmpty([])); + $this->assertTrue($val->isEmpty('')); + $this->assertFalse($val->isEmpty(5)); + $this->assertFalse($val->isEmpty(0)); + $this->assertFalse($val->isEmpty(new \stdClass())); + $this->assertFalse($val->isEmpty(' ')); + } + + public function testValidateValue() + { + $this->setExpectedException( + 'yii\base\NotSupportedException', + TestValidator::className() . ' does not support validateValue().' + ); + $val = new TestValidator(); + $val->validate('abc'); + } + + public function testClientValidateAttribute() + { + $val = new TestValidator(); + $this->assertNull( + $val->clientValidateAttribute($this->getTestModel(), 'attr_runMe1', []) + ); //todo pass a view instead of array + } + + public function testIsActive() + { + $val = new TestValidator(); + $this->assertTrue($val->isActive('scenA')); + $this->assertTrue($val->isActive('scenB')); + $val->except = ['scenB']; + $this->assertTrue($val->isActive('scenA')); + $this->assertFalse($val->isActive('scenB')); + $val->on = ['scenC']; + $this->assertFalse($val->isActive('scenA')); + $this->assertFalse($val->isActive('scenB')); + $this->assertTrue($val->isActive('scenC')); + } + + public function testAddError() + { + $val = new TestValidator(); + $m = $this->getTestModel(['attr_msg_val' => 'abc']); + $val->addError($m, 'attr_msg_val', '{attribute}::{value}'); + $errors = $m->getErrors('attr_msg_val'); + $this->assertEquals('attr_msg_val::abc', $errors[0]); + $m = $this->getTestModel(['attr_msg_val' => ['bcc']]); + $val->addError($m, 'attr_msg_val', '{attribute}::{value}'); + $errors = $m->getErrors('attr_msg_val'); + $this->assertEquals('attr_msg_val::array()', $errors[0]); + $m = $this->getTestModel(['attr_msg_val' => 'abc']); + $val->addError($m, 'attr_msg_val', '{attribute}::{value}::{param}', ['param' => 'param_value']); + $errors = $m->getErrors('attr_msg_val'); + $this->assertEquals('attr_msg_val::abc::param_value', $errors[0]); + } +} diff --git a/tests/framework/web/AssetBundleTest.php b/tests/framework/web/AssetBundleTest.php new file mode 100644 index 0000000..2f67ebe --- /dev/null +++ b/tests/framework/web/AssetBundleTest.php @@ -0,0 +1,273 @@ + + */ + +namespace yiiunit\framework\web; + +use Yii; +use yii\web\View; +use yii\web\AssetBundle; +use yii\web\AssetManager; + +/** + * @group web + */ +class AssetBundleTest extends \yiiunit\TestCase +{ + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + + Yii::setAlias('@testWeb', '/'); + Yii::setAlias('@testWebRoot', '@yiiunit/data/web'); + } + + protected function getView() + { + $view = new View(); + $view->setAssetManager(new AssetManager([ + 'basePath' => '@testWebRoot/assets', + 'baseUrl' => '@testWeb/assets', + ])); + + return $view; + } + + public function testRegister() + { + $view = $this->getView(); + + $this->assertEmpty($view->assetBundles); + TestSimpleAsset::register($view); + $this->assertEquals(1, count($view->assetBundles)); + $this->assertArrayHasKey('yiiunit\\framework\\web\\TestSimpleAsset', $view->assetBundles); + $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestSimpleAsset'] instanceof AssetBundle); + + $expected = <<4 +EOF; + $this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); + } + + public function testSimpleDependency() + { + $view = $this->getView(); + + $this->assertEmpty($view->assetBundles); + TestAssetBundle::register($view); + $this->assertEquals(3, count($view->assetBundles)); + $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles); + $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles); + $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetLevel3', $view->assetBundles); + $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle); + $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle); + $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3'] instanceof AssetBundle); + + $expected = <<23 +4 +EOF; + $this->assertEqualsWithoutLE($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); + } + + public function positionProvider() + { + return [ + [View::POS_HEAD, true], + [View::POS_HEAD, false], + [View::POS_BEGIN, true], + [View::POS_BEGIN, false], + [View::POS_END, true], + [View::POS_END, false], + ]; + } + + /** + * @dataProvider positionProvider + */ + public function testPositionDependency($pos, $jqAlreadyRegistered) + { + $view = $this->getView(); + + $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestAssetBundle'] = [ + 'jsOptions' => [ + 'position' => $pos, + ], + ]; + + $this->assertEmpty($view->assetBundles); + if ($jqAlreadyRegistered) { + TestJqueryAsset::register($view); + } + TestAssetBundle::register($view); + $this->assertEquals(3, count($view->assetBundles)); + $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles); + $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles); + $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetLevel3', $view->assetBundles); + + $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle); + $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle); + $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3'] instanceof AssetBundle); + + $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions); + $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions['position']); + $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions); + $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions['position']); + $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3']->jsOptions); + $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3']->jsOptions['position']); + + switch ($pos) { + case View::POS_HEAD: + $expected = << + +234 +EOF; + break; + case View::POS_BEGIN: + $expected = <<2 +34 +EOF; + break; + default: + case View::POS_END: + $expected = <<23 +4 +EOF; + break; + } + $this->assertEqualsWithoutLE($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); + } + + public function positionProvider2() + { + return [ + [View::POS_BEGIN, true], + [View::POS_BEGIN, false], + [View::POS_END, true], + [View::POS_END, false], + ]; + } + + /** + * @dataProvider positionProvider + */ + public function testPositionDependencyConflict($pos, $jqAlreadyRegistered) + { + $view = $this->getView(); + + $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestAssetBundle'] = [ + 'jsOptions' => [ + 'position' => $pos - 1, + ], + ]; + $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestJqueryAsset'] = [ + 'jsOptions' => [ + 'position' => $pos, + ], + ]; + + $this->assertEmpty($view->assetBundles); + if ($jqAlreadyRegistered) { + TestJqueryAsset::register($view); + } + $this->setExpectedException('yii\\base\\InvalidConfigException'); + TestAssetBundle::register($view); + } + + public function testCircularDependency() + { + $this->setExpectedException('yii\\base\\InvalidConfigException'); + TestAssetCircleA::register($this->getView()); + } + + public function testDuplicateAssetFile() + { + $view = $this->getView(); + + $this->assertEmpty($view->assetBundles); + TestSimpleAsset::register($view); + $this->assertEquals(1, count($view->assetBundles)); + $this->assertArrayHasKey('yiiunit\\framework\\web\\TestSimpleAsset', $view->assetBundles); + $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestSimpleAsset'] instanceof AssetBundle); + // register TestJqueryAsset which also has the jquery.js + TestJqueryAsset::register($view); + + $expected = <<4 +EOF; + $this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); + } +} + +class TestSimpleAsset extends AssetBundle +{ + public $basePath = '@testWebRoot/js'; + public $baseUrl = '@testWeb/js'; + public $js = [ + 'jquery.js', + ]; +} + +class TestAssetBundle extends AssetBundle +{ + public $basePath = '@testWebRoot/files'; + public $baseUrl = '@testWeb/files'; + public $css = [ + 'cssFile.css', + ]; + public $js = [ + 'jsFile.js', + ]; + public $depends = [ + 'yiiunit\\framework\\web\\TestJqueryAsset' + ]; +} + +class TestJqueryAsset extends AssetBundle +{ + public $basePath = '@testWebRoot/js'; + public $baseUrl = '@testWeb/js'; + public $js = [ + 'jquery.js', + ]; + public $depends = [ + 'yiiunit\\framework\\web\\TestAssetLevel3' + ]; +} + +class TestAssetLevel3 extends AssetBundle +{ + public $basePath = '@testWebRoot/js'; + public $baseUrl = '@testWeb/js'; +} + +class TestAssetCircleA extends AssetBundle +{ + public $basePath = '@testWebRoot/js'; + public $baseUrl = '@testWeb/js'; + public $js = [ + 'jquery.js', + ]; + public $depends = [ + 'yiiunit\\framework\\web\\TestAssetCircleB' + ]; +} + +class TestAssetCircleB extends AssetBundle +{ + public $basePath = '@testWebRoot/js'; + public $baseUrl = '@testWeb/js'; + public $js = [ + 'jquery.js', + ]; + public $depends = [ + 'yiiunit\\framework\\web\\TestAssetCircleA' + ]; +} diff --git a/tests/framework/web/AssetConverterTest.php b/tests/framework/web/AssetConverterTest.php new file mode 100644 index 0000000..15f699f --- /dev/null +++ b/tests/framework/web/AssetConverterTest.php @@ -0,0 +1,87 @@ + + */ + +namespace yiiunit\framework\web; + +use yii\helpers\FileHelper; +use yii\web\AssetConverter; + +/** + * @group web + */ +class AssetConverterTest extends \yiiunit\TestCase +{ + /** + * @var string temporary files path + */ + protected $tmpPath; + + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + $this->tmpPath = \Yii::$app->runtimePath . '/assetConverterTest_' . getmypid(); + if (!is_dir($this->tmpPath)) { + mkdir($this->tmpPath, 0777, true); + } + } + + protected function tearDown() + { + if (is_dir($this->tmpPath)) { + FileHelper::removeDirectory($this->tmpPath); + } + parent::tearDown(); + } + + // Tests : + + public function testConvert() + { + $tmpPath = $this->tmpPath; + file_put_contents($tmpPath . '/test.php', <<commands['php'] = ['txt', 'php {from} > {to}']; + $this->assertEquals('test.txt', $converter->convert('test.php', $tmpPath)); + + $this->assertTrue(file_exists($tmpPath . '/test.txt'), 'Failed asserting that asset output file exists.'); + $this->assertEquals("Hello World!\nHello Yii!", file_get_contents($tmpPath . '/test.txt')); + } + + /** + * @depends testConvert + */ + public function testForceConvert() + { + $tmpPath = $this->tmpPath; + file_put_contents($tmpPath . '/test.php', <<commands['php'] = ['txt', 'php {from} > {to}']; + + $converter->convert('test.php', $tmpPath); + $initialConvertTime = file_get_contents($tmpPath . '/test.txt'); + + usleep(1); + $converter->convert('test.php', $tmpPath); + $this->assertEquals($initialConvertTime, file_get_contents($tmpPath . '/test.txt')); + + $converter->forceConvert = true; + $converter->convert('test.php', $tmpPath); + $this->assertNotEquals($initialConvertTime, file_get_contents($tmpPath . '/test.txt')); + } +} diff --git a/tests/framework/web/CacheSessionTest.php b/tests/framework/web/CacheSessionTest.php new file mode 100644 index 0000000..c81e01a --- /dev/null +++ b/tests/framework/web/CacheSessionTest.php @@ -0,0 +1,36 @@ +mockApplication(); + Yii::$app->set('cache', new FileCache()); + } + + public function testCacheSession() + { + $session = new CacheSession(); + + $session->writeSession('test', 'sessionData'); + $this->assertEquals('sessionData', $session->readSession('test')); + $session->destroySession('test'); + $this->assertEquals('', $session->readSession('test')); + } + + public function testInvalidCache() + { + $this->setExpectedException('\Exception'); + new CacheSession(['cache' => 'invalid']); + } +} diff --git a/tests/framework/web/FormatterTest.php b/tests/framework/web/FormatterTest.php new file mode 100644 index 0000000..1c99879 --- /dev/null +++ b/tests/framework/web/FormatterTest.php @@ -0,0 +1,77 @@ +mockApplication(); + $this->response = new Response; + $this->formatter = $this->getFormatterInstance(); + } + + /** + * @return ResponseFormatterInterface + */ + abstract protected function getFormatterInstance(); + + /** + * Formatter should not format null + */ + public function testFormatNull() + { + $this->response->data = null; + $this->formatter->format($this->response); + $this->assertEquals(null, $this->response->content); + } + + /** + * @param mixed $data the data to be formatted + * @param string $json the expected JSON body + * @dataProvider formatScalarDataProvider + */ + public function testFormatScalar($data, $json) + { + $this->response->data = $data; + $this->formatter->format($this->response); + $this->assertEquals($json, $this->response->content); + } + + /** + * @param mixed $data the data to be formatted + * @param string $json the expected JSON body + * @dataProvider formatArrayDataProvider + */ + public function testFormatArrays($data, $json) + { + $this->response->data = $data; + $this->formatter->format($this->response); + $this->assertEquals($json, $this->response->content); + } + + /** + * @param mixed $data the data to be formatted + * @param string $json the expected JSON body + * @dataProvider formatObjectDataProvider + */ + public function testFormatObjects($data, $json) + { + $this->response->data = $data; + $this->formatter->format($this->response); + $this->assertEquals($json, $this->response->content); + } +} \ No newline at end of file diff --git a/tests/framework/web/GroupUrlRuleTest.php b/tests/framework/web/GroupUrlRuleTest.php new file mode 100644 index 0000000..29482d4 --- /dev/null +++ b/tests/framework/web/GroupUrlRuleTest.php @@ -0,0 +1,216 @@ +mockApplication(); + } + + public function testCreateUrl() + { + $manager = new UrlManager(['cache' => null]); + $suites = $this->getTestsForCreateUrl(); + foreach ($suites as $i => $suite) { + list ($name, $config, $tests) = $suite; + $rule = new GroupUrlRule($config); + foreach ($tests as $j => $test) { + list ($route, $params, $expected) = $test; + $url = $rule->createUrl($manager, $route, $params); + $this->assertEquals($expected, $url, "Test#$i-$j: $name"); + } + } + } + + public function testParseRequest() + { + $manager = new UrlManager(['cache' => null]); + $request = new Request(['hostInfo' => 'http://en.example.com']); + $suites = $this->getTestsForParseRequest(); + foreach ($suites as $i => $suite) { + list ($name, $config, $tests) = $suite; + $rule = new GroupUrlRule($config); + foreach ($tests as $j => $test) { + $request->pathInfo = $test[0]; + $route = $test[1]; + $params = isset($test[2]) ? $test[2] : []; + $result = $rule->parseRequest($manager, $request); + if ($route === false) { + $this->assertFalse($result, "Test#$i-$j: $name"); + } else { + $this->assertEquals([$route, $params], $result, "Test#$i-$j: $name"); + } + } + } + } + + protected function getTestsForCreateUrl() + { + // structure of each test + // message for the test + // config for the URL rule + // list of inputs and outputs + // route + // params + // expected output + return [ + [ + 'no prefix', + [ + 'rules' => [ + 'login' => 'user/login', + 'logout' => 'user/logout', + ], + ], + [ + ['user/login', [], 'login'], + ['user/logout', [], 'logout'], + ['user/create', [], false], + ], + ], + [ + 'prefix only', + [ + 'prefix' => 'admin', + 'rules' => [ + 'login' => 'user/login', + 'logout' => 'user/logout', + ], + ], + [ + ['admin/user/login', [], 'admin/login'], + ['admin/user/logout', [], 'admin/logout'], + ['user/create', [], false], + ], + ], + [ + 'prefix and routePrefix different', + [ + 'prefix' => '_', + 'routePrefix' => 'admin', + 'rules' => [ + 'login' => 'user/login', + 'logout' => 'user/logout', + ], + ], + [ + ['admin/user/login', [], '_/login'], + ['admin/user/logout', [], '_/logout'], + ['user/create', [], false], + ], + ], + [ + 'ruleConfig with suffix', + [ + 'prefix' => '_', + 'routePrefix' => 'admin', + 'ruleConfig' => [ + 'suffix' => '.html', + 'class' => 'yii\\web\\UrlRule' + ], + 'rules' => [ + 'login' => 'user/login', + 'logout' => 'user/logout', + ], + ], + [ + ['admin/user/login', [], '_/login.html'], + ['admin/user/logout', [], '_/logout.html'], + ['user/create', [], false], + ], + ], + ]; + } + + protected function getTestsForParseRequest() + { + // structure of each test + // message for the test + // config for the URL rule + // list of inputs and outputs + // pathInfo + // expected route, or false if the rule doesn't apply + // expected params, or not set if empty + return [ + [ + 'no prefix', + [ + 'rules' => [ + 'login' => 'user/login', + 'logout' => 'user/logout', + ], + ], + [ + ['login', 'user/login'], + ['logout', 'user/logout'], + ['create', false], + ], + ], + [ + 'prefix only', + [ + 'prefix' => 'admin', + 'rules' => [ + 'login' => 'user/login', + 'logout' => 'user/logout', + ], + ], + [ + ['admin/login', 'admin/user/login'], + ['admin/logout', 'admin/user/logout'], + ['admin/create', false], + ['create', false], + ], + ], + [ + 'prefix and routePrefix different', + [ + 'prefix' => '_', + 'routePrefix' => 'admin', + 'rules' => [ + 'login' => 'user/login', + 'logout' => 'user/logout', + ], + ], + [ + ['_/login', 'admin/user/login'], + ['_/logout', 'admin/user/logout'], + ['_/create', false], + ['create', false], + ], + ], + [ + 'ruleConfig with suffix', + [ + 'prefix' => '_', + 'routePrefix' => 'admin', + 'ruleConfig' => [ + 'suffix' => '.html', + 'class' => 'yii\\web\\UrlRule' + ], + 'rules' => [ + 'login' => 'user/login', + 'logout' => 'user/logout', + ], + ], + [ + ['_/login.html', 'admin/user/login'], + ['_/logout.html', 'admin/user/logout'], + ['_/logout', false], + ['_/create.html', false], + ], + ], + ]; + } +} diff --git a/tests/framework/web/JsonResponseFormatterTest.php b/tests/framework/web/JsonResponseFormatterTest.php new file mode 100644 index 0000000..ca49f48 --- /dev/null +++ b/tests/framework/web/JsonResponseFormatterTest.php @@ -0,0 +1,76 @@ + + * @since 2.0.3 + * + * @group web + */ +class JsonResponseFormatterTest extends FormatterTest +{ + /** + * @return JsonResponseFormatter + */ + protected function getFormatterInstance() + { + return new JsonResponseFormatter(); + } + + public function formatScalarDataProvider() + { + return [ + [1, 1], + ['abc', '"abc"'], + [true, 'true'], + ["<>", '"<>"'], + ]; + } + + public function formatArrayDataProvider() + { + return [ + [[], "[]"], + [[1, 'abc'], '[1,"abc"]'], + [[ + 'a' => 1, + 'b' => 'abc', + ], '{"a":1,"b":"abc"}'], + [[ + 1, + 'abc', + [2, 'def'], + true, + ], '[1,"abc",[2,"def"],true]'], + [[ + 'a' => 1, + 'b' => 'abc', + 'c' => [2, '<>'], + true, + ], '{"a":1,"b":"abc","c":[2,"<>"],"0":true}'], + ]; + } + + public function formatObjectDataProvider() + { + return [ + [new Post(123, 'abc'), '{"id":123,"title":"abc"}'], + [[ + new Post(123, 'abc'), + new Post(456, 'def'), + ], '[{"id":123,"title":"abc"},{"id":456,"title":"def"}]'], + [[ + new Post(123, '<>'), + 'a' => new Post(456, 'def'), + ], '{"0":{"id":123,"title":"<>"},"a":{"id":456,"title":"def"}}'], + ]; + } +} diff --git a/tests/framework/web/Post.php b/tests/framework/web/Post.php new file mode 100644 index 0000000..d6ebc68 --- /dev/null +++ b/tests/framework/web/Post.php @@ -0,0 +1,16 @@ +id = $id; + $this->title = $title; + } +} \ No newline at end of file diff --git a/tests/framework/web/RequestTest.php b/tests/framework/web/RequestTest.php new file mode 100644 index 0000000..2d276f9 --- /dev/null +++ b/tests/framework/web/RequestTest.php @@ -0,0 +1,81 @@ +assertEquals([], $request->parseAcceptHeader(' ')); + + $this->assertEquals([ + 'audio/basic' => ['q' => 1], + 'audio/*' => ['q' => 0.2], + ], $request->parseAcceptHeader('audio/*; q=0.2, audio/basic')); + + $this->assertEquals([ + 'application/json' => ['q' => 1, 'version' => '1.0'], + 'application/xml' => ['q' => 1, 'version' => '2.0', 'x'], + 'text/x-c' => ['q' => 1], + 'text/x-dvi' => ['q' => 0.8], + 'text/plain' => ['q' => 0.5], + ], $request->parseAcceptHeader('text/plain; q=0.5, + application/json; version=1.0, + application/xml; version=2.0; x, + text/x-dvi; q=0.8, text/x-c')); + } + + public function testPrefferedLanguage() + { + $this->mockApplication([ + 'language' => 'en', + ]); + + $request = new Request(); + $request->acceptableLanguages = []; + $this->assertEquals('en', $request->getPreferredLanguage()); + + $request = new Request(); + $request->acceptableLanguages = ['de']; + $this->assertEquals('en', $request->getPreferredLanguage()); + + $request = new Request(); + $request->acceptableLanguages = ['en-us', 'de', 'ru-RU']; + $this->assertEquals('en', $request->getPreferredLanguage(['en'])); + + $request = new Request(); + $request->acceptableLanguages = ['en-us', 'de', 'ru-RU']; + $this->assertEquals('de', $request->getPreferredLanguage(['ru', 'de'])); + $this->assertEquals('de-DE', $request->getPreferredLanguage(['ru', 'de-DE'])); + + $request = new Request(); + $request->acceptableLanguages = ['en-us', 'de', 'ru-RU']; + $this->assertEquals('de', $request->getPreferredLanguage(['de', 'ru'])); + + $request = new Request(); + $request->acceptableLanguages = ['en-us', 'de', 'ru-RU']; + $this->assertEquals('ru-ru', $request->getPreferredLanguage(['ru-ru'])); + + $request = new Request(); + $request->acceptableLanguages = ['en-us', 'de']; + $this->assertEquals('ru-ru', $request->getPreferredLanguage(['ru-ru', 'pl'])); + $this->assertEquals('ru-RU', $request->getPreferredLanguage(['ru-RU', 'pl'])); + + $request = new Request(); + $request->acceptableLanguages = ['en-us', 'de']; + $this->assertEquals('pl', $request->getPreferredLanguage(['pl', 'ru-ru'])); + } +} diff --git a/tests/framework/web/ResponseTest.php b/tests/framework/web/ResponseTest.php new file mode 100644 index 0000000..8a9c22d --- /dev/null +++ b/tests/framework/web/ResponseTest.php @@ -0,0 +1,104 @@ +mockApplication(); + $this->response = new \yii\web\Response; + } + + public function rightRanges() + { + // TODO test more cases for range requests and check for rfc compatibility + // http://www.w3.org/Protocols/rfc2616/rfc2616.txt + return [ + ['0-5', '0-5', 6, '12ёж'], + ['2-', '2-66', 65, 'ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?'], + ['-12', '55-66', 12, '(ёжик)=?'], + ]; + } + + /** + * @dataProvider rightRanges + */ + public function testSendFileRanges($rangeHeader, $expectedHeader, $length, $expectedContent) + { + $dataFile = \Yii::getAlias('@yiiunit/data/web/data.txt'); + $fullContent = file_get_contents($dataFile); + $_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader; + ob_start(); + $this->response->sendFile($dataFile)->send( ); + $content = ob_get_clean(); + + $this->assertEquals($expectedContent, $content); + $this->assertEquals(206, $this->response->statusCode); + $headers = $this->response->headers; + $this->assertEquals("bytes", $headers->get('Accept-Ranges')); + $this->assertEquals("bytes " . $expectedHeader . '/' . StringHelper::byteLength($fullContent), $headers->get('Content-Range')); + $this->assertEquals('text/plain', $headers->get('Content-Type')); + $this->assertEquals("$length", $headers->get('Content-Length')); + } + + public function wrongRanges() + { + // TODO test more cases for range requests and check for rfc compatibility + // http://www.w3.org/Protocols/rfc2616/rfc2616.txt + return [ + ['1-2,3-5,6-10'], // multiple range request not supported + ['5-1'], // last-byte-pos value is less than its first-byte-pos value + ['-100000'], // last-byte-pos bigger then content length + ['10000-'], // first-byte-pos bigger then content length + ]; + } + + /** + * @dataProvider wrongRanges + */ + public function testSendFileWrongRanges($rangeHeader) + { + $this->setExpectedException('yii\web\HttpException'); + + $dataFile = \Yii::getAlias('@yiiunit/data/web/data.txt'); + $_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader; + $this->response->sendFile($dataFile); + } + + protected function generateTestFileContent() + { + return '12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?'; + } + + /** + * https://github.com/yiisoft/yii2/issues/7529 + */ + public function testSendContentAsFile() + { + ob_start(); + $this->response->sendContentAsFile('test', 'test.txt')->send([ + 'mimeType' => 'text/plain' + ]); + $content = ob_get_clean(); + + static::assertEquals('test', $content); + static::assertEquals(200, $this->response->statusCode); + $headers = $this->response->headers; + static::assertEquals('application/octet-stream', $headers->get('Content-Type')); + static::assertEquals('attachment; filename="test.txt"', $headers->get('Content-Disposition')); + static::assertEquals(4, $headers->get('Content-Length')); + } +} diff --git a/tests/framework/web/UrlManagerTest.php b/tests/framework/web/UrlManagerTest.php new file mode 100644 index 0000000..4a2097d --- /dev/null +++ b/tests/framework/web/UrlManagerTest.php @@ -0,0 +1,372 @@ +mockApplication(); + } + + public function testCreateUrl() + { + // default setting with '/' as base url + $manager = new UrlManager([ + 'baseUrl' => '/', + 'scriptUrl' => '', + 'cache' => null, + ]); + $url = $manager->createUrl(['post/view']); + $this->assertEquals('?r=post%2Fview', $url); + $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); + $this->assertEquals('?r=post%2Fview&id=1&title=sample+post', $url); + + // default setting with '/test/' as base url + $manager = new UrlManager([ + 'baseUrl' => '/test/', + 'scriptUrl' => '/test', + 'cache' => null, + ]); + $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); + $this->assertEquals('/test?r=post%2Fview&id=1&title=sample+post', $url); + + // pretty URL without rules + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'baseUrl' => '/', + 'scriptUrl' => '', + 'cache' => null, + ]); + $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); + $this->assertEquals('/post/view?id=1&title=sample+post', $url); + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'baseUrl' => '/test/', + 'scriptUrl' => '/test', + 'cache' => null, + ]); + $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); + $this->assertEquals('/test/post/view?id=1&title=sample+post', $url); + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'baseUrl' => '/test', + 'scriptUrl' => '/test/index.php', + 'cache' => null, + ]); + $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); + $this->assertEquals('/test/index.php/post/view?id=1&title=sample+post', $url); + + // todo: test showScriptName + + // pretty URL with rules + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'cache' => null, + 'rules' => [ + [ + 'pattern' => 'post//', + 'route' => 'post/view', + ], + ], + 'baseUrl' => '/', + 'scriptUrl' => '', + ]); + $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); + $this->assertEquals('/post/1/sample+post', $url); + $url = $manager->createUrl(['post/index', 'page' => 1]); + $this->assertEquals('/post/index?page=1', $url); + + // rules with defaultAction + $url = $manager->createUrl(['/post', 'page' => 1]); + $this->assertEquals('/post?page=1', $url); + + // pretty URL with rules and suffix + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'cache' => null, + 'rules' => [ + [ + 'pattern' => 'post/<id>/<title>', + 'route' => 'post/view', + ], + ], + 'baseUrl' => '/', + 'scriptUrl' => '', + 'suffix' => '.html', + ]); + $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); + $this->assertEquals('/post/1/sample+post.html', $url); + $url = $manager->createUrl(['post/index', 'page' => 1]); + $this->assertEquals('/post/index.html?page=1', $url); + + // pretty URL with rules that have host info + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'cache' => null, + 'rules' => [ + [ + 'pattern' => 'post/<id>/<title>', + 'route' => 'post/view', + 'host' => 'http://<lang:en|fr>.example.com', + ], + ], + 'baseUrl' => '/test', + 'scriptUrl' => '/test', + ]); + $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post', 'lang' => 'en']); + $this->assertEquals('http://en.example.com/test/post/1/sample+post', $url); + $url = $manager->createUrl(['post/index', 'page' => 1]); + $this->assertEquals('/test/post/index?page=1', $url); + } + + /** + * https://github.com/yiisoft/yii2/issues/6717 + */ + public function testCreateUrlWithEmptyPattern() + { + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'cache' => null, + 'rules' => [ + '' => 'front/site/index', + ], + 'baseUrl' => '/', + 'scriptUrl' => '', + ]); + $url = $manager->createUrl(['front/site/index']); + $this->assertEquals('/', $url); + $url = $manager->createUrl(['/front/site/index']); + $this->assertEquals('/', $url); + $url = $manager->createUrl(['front/site/index', 'page' => 1]); + $this->assertEquals('/?page=1', $url); + $url = $manager->createUrl(['/front/site/index', 'page' => 1]); + $this->assertEquals('/?page=1', $url); + + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'cache' => null, + 'rules' => [ + '' => '/front/site/index', + ], + 'baseUrl' => '/', + 'scriptUrl' => '', + ]); + $url = $manager->createUrl(['front/site/index']); + $this->assertEquals('/', $url); + $url = $manager->createUrl(['/front/site/index']); + $this->assertEquals('/', $url); + $url = $manager->createUrl(['front/site/index', 'page' => 1]); + $this->assertEquals('/?page=1', $url); + $url = $manager->createUrl(['/front/site/index', 'page' => 1]); + $this->assertEquals('/?page=1', $url); + } + + public function testCreateAbsoluteUrl() + { + $manager = new UrlManager([ + 'baseUrl' => '/', + 'scriptUrl' => '', + 'hostInfo' => 'http://www.example.com', + 'cache' => null, + ]); + $url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post']); + $this->assertEquals('http://www.example.com?r=post%2Fview&id=1&title=sample+post', $url); + + $url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post'], 'https'); + $this->assertEquals('https://www.example.com?r=post%2Fview&id=1&title=sample+post', $url); + + $manager->hostInfo = 'https://www.example.com'; + $url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post'], 'http'); + $this->assertEquals('http://www.example.com?r=post%2Fview&id=1&title=sample+post', $url); + } + + public function testParseRequest() + { + $manager = new UrlManager(['cache' => null]); + $request = new Request; + + // default setting without 'r' param + unset($_GET['r']); + $result = $manager->parseRequest($request); + $this->assertEquals(['', []], $result); + + // default setting with 'r' param + $_GET['r'] = 'site/index'; + $result = $manager->parseRequest($request); + $this->assertEquals(['site/index', []], $result); + + // default setting with 'r' param as an array + $_GET['r'] = ['site/index']; + $result = $manager->parseRequest($request); + $this->assertEquals(['', []], $result); + + // pretty URL without rules + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'cache' => null, + ]); + // empty pathinfo + $request->pathInfo = ''; + $result = $manager->parseRequest($request); + $this->assertEquals(['', []], $result); + // normal pathinfo + $request->pathInfo = 'site/index'; + $result = $manager->parseRequest($request); + $this->assertEquals(['site/index', []], $result); + // pathinfo with module + $request->pathInfo = 'module/site/index'; + $result = $manager->parseRequest($request); + $this->assertEquals(['module/site/index', []], $result); + // pathinfo with trailing slashes + $request->pathInfo = '/module/site/index/'; + $result = $manager->parseRequest($request); + $this->assertEquals(['module/site/index/', []], $result); + + // pretty URL rules + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'cache' => null, + 'rules' => [ + [ + 'pattern' => 'post/<id>/<title>', + 'route' => 'post/view', + ], + ], + ]); + // matching pathinfo + $request->pathInfo = 'post/123/this+is+sample'; + $result = $manager->parseRequest($request); + $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); + // trailing slash is significant + $request->pathInfo = 'post/123/this+is+sample/'; + $result = $manager->parseRequest($request); + $this->assertEquals(['post/123/this+is+sample/', []], $result); + // empty pathinfo + $request->pathInfo = ''; + $result = $manager->parseRequest($request); + $this->assertEquals(['', []], $result); + // normal pathinfo + $request->pathInfo = 'site/index'; + $result = $manager->parseRequest($request); + $this->assertEquals(['site/index', []], $result); + // pathinfo with module + $request->pathInfo = 'module/site/index'; + $result = $manager->parseRequest($request); + $this->assertEquals(['module/site/index', []], $result); + + // pretty URL rules + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'suffix' => '.html', + 'cache' => null, + 'rules' => [ + [ + 'pattern' => 'post/<id>/<title>', + 'route' => 'post/view', + ], + ], + ]); + // matching pathinfo + $request->pathInfo = 'post/123/this+is+sample.html'; + $result = $manager->parseRequest($request); + $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); + // matching pathinfo without suffix + $request->pathInfo = 'post/123/this+is+sample'; + $result = $manager->parseRequest($request); + $this->assertFalse($result); + // empty pathinfo + $request->pathInfo = ''; + $result = $manager->parseRequest($request); + $this->assertEquals(['', []], $result); + // normal pathinfo + $request->pathInfo = 'site/index.html'; + $result = $manager->parseRequest($request); + $this->assertEquals(['site/index', []], $result); + // pathinfo without suffix + $request->pathInfo = 'site/index'; + $result = $manager->parseRequest($request); + $this->assertFalse($result); + + // strict parsing + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'enableStrictParsing' => true, + 'suffix' => '.html', + 'cache' => null, + 'rules' => [ + [ + 'pattern' => 'post/<id>/<title>', + 'route' => 'post/view', + ], + ], + ]); + // matching pathinfo + $request->pathInfo = 'post/123/this+is+sample.html'; + $result = $manager->parseRequest($request); + $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); + // unmatching pathinfo + $request->pathInfo = 'site/index.html'; + $result = $manager->parseRequest($request); + $this->assertFalse($result); + } + + public function testParseRESTRequest() + { + $request = new Request; + + // pretty URL rules + $manager = new UrlManager([ + 'enablePrettyUrl' => true, + 'showScriptName' => false, + 'cache' => null, + 'rules' => [ + 'PUT,POST post/<id>/<title>' => 'post/create', + 'DELETE post/<id>' => 'post/delete', + 'post/<id>/<title>' => 'post/view', + 'POST/GET' => 'post/get', + ], + ]); + // matching pathinfo GET request + $_SERVER['REQUEST_METHOD'] = 'GET'; + $request->pathInfo = 'post/123/this+is+sample'; + $result = $manager->parseRequest($request); + $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); + // matching pathinfo PUT/POST request + $_SERVER['REQUEST_METHOD'] = 'PUT'; + $request->pathInfo = 'post/123/this+is+sample'; + $result = $manager->parseRequest($request); + $this->assertEquals(['post/create', ['id' => '123', 'title' => 'this+is+sample']], $result); + $_SERVER['REQUEST_METHOD'] = 'POST'; + $request->pathInfo = 'post/123/this+is+sample'; + $result = $manager->parseRequest($request); + $this->assertEquals(['post/create', ['id' => '123', 'title' => 'this+is+sample']], $result); + + // no wrong matching + $_SERVER['REQUEST_METHOD'] = 'POST'; + $request->pathInfo = 'POST/GET'; + $result = $manager->parseRequest($request); + $this->assertEquals(['post/get', []], $result); + + // createUrl should ignore REST rules + $this->mockApplication([ + 'components' => [ + 'request' => [ + 'hostInfo' => 'http://localhost/', + 'baseUrl' => '/app' + ] + ] + ], \yii\web\Application::className()); + $this->assertEquals('/app/post/delete?id=123', $manager->createUrl(['post/delete', 'id' => 123])); + $this->destroyApplication(); + + unset($_SERVER['REQUEST_METHOD']); + } +} diff --git a/tests/framework/web/UrlRuleTest.php b/tests/framework/web/UrlRuleTest.php new file mode 100644 index 0000000..a376437 --- /dev/null +++ b/tests/framework/web/UrlRuleTest.php @@ -0,0 +1,710 @@ +<?php + +namespace yiiunit\framework\web; + +use yii\web\UrlManager; +use yii\web\UrlRule; +use yii\web\Request; +use yiiunit\TestCase; + +/** + * @group web + */ +class UrlRuleTest extends TestCase +{ + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + + public function testCreateUrl() + { + $manager = new UrlManager(['cache' => null]); + $suites = $this->getTestsForCreateUrl(); + foreach ($suites as $i => $suite) { + list ($name, $config, $tests) = $suite; + $rule = new UrlRule($config); + foreach ($tests as $j => $test) { + list ($route, $params, $expected) = $test; + $url = $rule->createUrl($manager, $route, $params); + $this->assertEquals($expected, $url, "Test#$i-$j: $name"); + } + } + } + + public function testParseRequest() + { + $manager = new UrlManager(['cache' => null]); + $request = new Request(['hostInfo' => 'http://en.example.com']); + $suites = $this->getTestsForParseRequest(); + foreach ($suites as $i => $suite) { + list ($name, $config, $tests) = $suite; + $rule = new UrlRule($config); + foreach ($tests as $j => $test) { + $request->pathInfo = $test[0]; + $route = $test[1]; + $params = isset($test[2]) ? $test[2] : []; + $result = $rule->parseRequest($manager, $request); + if ($route === false) { + $this->assertFalse($result, "Test#$i-$j: $name"); + } else { + $this->assertEquals([$route, $params], $result, "Test#$i-$j: $name"); + } + } + } + } + + protected function getTestsForCreateUrl() + { + // structure of each test + // message for the test + // config for the URL rule + // list of inputs and outputs + // route + // params + // expected output + return [ + [ + 'empty pattern', + [ + 'pattern' => '', + 'route' => 'post/index', + ], + [ + ['post/index', [], ''], + ['comment/index', [], false], + ['post/index', ['page' => 1], '?page=1'], + ], + ], + [ + 'without param', + [ + 'pattern' => 'posts', + 'route' => 'post/index', + ], + [ + ['post/index', [], 'posts'], + ['comment/index', [], false], + ['post/index', ['page' => 1], 'posts?page=1'], + ], + ], + [ + 'parsing only', + [ + 'pattern' => 'posts', + 'route' => 'post/index', + 'mode' => UrlRule::PARSING_ONLY, + ], + [ + ['post/index', [], false], + ], + ], + [ + 'with param', + [ + 'pattern' => 'post/<page>', + 'route' => 'post/index', + ], + [ + ['post/index', [], false], + ['comment/index', [], false], + ['post/index', ['page' => 1], 'post/1'], + ['post/index', ['page' => 1, 'tag' => 'a'], 'post/1?tag=a'], + ], + ], + [ + 'with param requirement', + [ + 'pattern' => 'post/<page:\d+>', + 'route' => 'post/index', + ], + [ + ['post/index', ['page' => 'abc'], false], + ['post/index', ['page' => 1], 'post/1'], + ['post/index', ['page' => 1, 'tag' => 'a'], 'post/1?tag=a'], + ], + ], + [ + 'with multiple params', + [ + 'pattern' => 'post/<page:\d+>-<tag>', + 'route' => 'post/index', + ], + [ + ['post/index', ['page' => '1abc'], false], + ['post/index', ['page' => 1], false], + ['post/index', ['page' => 1, 'tag' => 'a'], 'post/1-a'], + ], + ], + [ + 'with optional param', + [ + 'pattern' => 'post/<page:\d+>/<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + ], + [ + ['post/index', ['page' => 1], false], + ['post/index', ['page' => '1abc', 'tag' => 'a'], false], + ['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], + ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2/a'], + ], + ], + [ + 'with optional param not in pattern', + [ + 'pattern' => 'post/<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + ], + [ + ['post/index', ['page' => 1], false], + ['post/index', ['page' => '1abc', 'tag' => 'a'], false], + ['post/index', ['page' => 2, 'tag' => 'a'], false], + ['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], + ], + ], + [ + 'multiple optional params', + [ + 'pattern' => 'post/<page:\d+>/<tag>/<sort:yes|no>', + 'route' => 'post/index', + 'defaults' => ['page' => 1, 'sort' => 'yes'], + ], + [ + ['post/index', ['page' => 1], false], + ['post/index', ['page' => '1abc', 'tag' => 'a'], false], + ['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'YES'], false], + ['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'yes'], 'post/a'], + ['post/index', ['page' => 2, 'tag' => 'a', 'sort' => 'yes'], 'post/2/a'], + ['post/index', ['page' => 2, 'tag' => 'a', 'sort' => 'no'], 'post/2/a/no'], + ['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'no'], 'post/a/no'], + ], + ], + [ + 'optional param and required param separated by dashes', + [ + 'pattern' => 'post/<page:\d+>-<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + ], + [ + ['post/index', ['page' => 1], false], + ['post/index', ['page' => '1abc', 'tag' => 'a'], false], + ['post/index', ['page' => 1, 'tag' => 'a'], 'post/-a'], + ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2-a'], + ], + ], + [ + 'optional param at the end', + [ + 'pattern' => 'post/<tag>/<page:\d+>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + ], + [ + ['post/index', ['page' => 1], false], + ['post/index', ['page' => '1abc', 'tag' => 'a'], false], + ['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], + ['post/index', ['page' => 2, 'tag' => 'a'], 'post/a/2'], + ], + ], + [ + 'consecutive optional params', + [ + 'pattern' => 'post/<page:\d+>/<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1, 'tag' => 'a'], + ], + [ + ['post/index', ['page' => 1], false], + ['post/index', ['page' => '1abc', 'tag' => 'a'], false], + ['post/index', ['page' => 1, 'tag' => 'a'], 'post'], + ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2'], + ['post/index', ['page' => 1, 'tag' => 'b'], 'post/b'], + ['post/index', ['page' => 2, 'tag' => 'b'], 'post/2/b'], + ], + ], + [ + 'consecutive optional params separated by dash', + [ + 'pattern' => 'post/<page:\d+>-<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1, 'tag' => 'a'], + ], + [ + ['post/index', ['page' => 1], false], + ['post/index', ['page' => '1abc', 'tag' => 'a'], false], + ['post/index', ['page' => 1, 'tag' => 'a'], 'post/-'], + ['post/index', ['page' => 1, 'tag' => 'b'], 'post/-b'], + ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2-'], + ['post/index', ['page' => 2, 'tag' => 'b'], 'post/2-b'], + ], + ], + [ + 'route has parameters', + [ + 'pattern' => '<controller>/<action>', + 'route' => '<controller>/<action>', + 'defaults' => [], + ], + [ + ['post/index', ['page' => 1], 'post/index?page=1'], + ['module/post/index', [], false], + ], + ], + [ + 'route has parameters with regex', + [ + 'pattern' => '<controller:post|comment>/<action>', + 'route' => '<controller>/<action>', + 'defaults' => [], + ], + [ + ['post/index', ['page' => 1], 'post/index?page=1'], + ['comment/index', ['page' => 1], 'comment/index?page=1'], + ['test/index', ['page' => 1], false], + ['post', [], false], + ['module/post/index', [], false], + ['post/index', ['controller' => 'comment'], 'post/index?controller=comment'], + ], + ], + [ + 'route has default parameter', + [ + 'pattern' => '<controller:post|comment>/<action>', + 'route' => '<controller>/<action>', + 'defaults' => ['action' => 'index'], + ], + [ + ['post/view', ['page' => 1], 'post/view?page=1'], + ['comment/view', ['page' => 1], 'comment/view?page=1'], + ['test/view', ['page' => 1], false], + ['test/index', ['page' => 1], false], + ['post/index', ['page' => 1], 'post?page=1'], + ], + ], + [ + 'empty pattern with suffix', + [ + 'pattern' => '', + 'route' => 'post/index', + 'suffix' => '.html', + ], + [ + ['post/index', [], ''], + ['comment/index', [], false], + ['post/index', ['page' => 1], '?page=1'], + ], + ], + [ + 'regular pattern with suffix', + [ + 'pattern' => 'posts', + 'route' => 'post/index', + 'suffix' => '.html', + ], + [ + ['post/index', [], 'posts.html'], + ['comment/index', [], false], + ['post/index', ['page' => 1], 'posts.html?page=1'], + ], + ], + [ + 'empty pattern with slash suffix', + [ + 'pattern' => '', + 'route' => 'post/index', + 'suffix' => '/', + ], + [ + ['post/index', [], ''], + ['comment/index', [], false], + ['post/index', ['page' => 1], '?page=1'], + ], + ], + [ + 'regular pattern with slash suffix', + [ + 'pattern' => 'posts', + 'route' => 'post/index', + 'suffix' => '/', + ], + [ + ['post/index', [], 'posts/'], + ['comment/index', [], false], + ['post/index', ['page' => 1], 'posts/?page=1'], + ], + ], + [ + 'with host info', + [ + 'pattern' => 'post/<page:\d+>/<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + 'host' => 'http://<lang:en|fr>.example.com', + ], + [ + ['post/index', ['page' => 1, 'tag' => 'a'], false], + ['post/index', ['page' => 1, 'tag' => 'a', 'lang' => 'en'], 'http://en.example.com/post/a'], + ], + ], + [ + 'with host info in pattern', + [ + 'pattern' => 'http://<lang:en|fr>.example.com/post/<page:\d+>/<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + ], + [ + ['post/index', ['page' => 1, 'tag' => 'a'], false], + ['post/index', ['page' => 1, 'tag' => 'a', 'lang' => 'en'], 'http://en.example.com/post/a'], + ], + ], + [ + 'with unicode', + [ + 'pattern' => '/blog/search/<tag:[a-zA-Zа-яА-Я0-9\_\+\-]{1,255}>', + 'route' => 'blog/search', + ], + [ + ['blog/search', ['tag' => 'метра'], 'blog/search/%D0%BC%D0%B5%D1%82%D1%80%D0%B0'], + ], + ], + ]; + } + + protected function getTestsForParseRequest() + { + // structure of each test + // message for the test + // config for the URL rule + // list of inputs and outputs + // pathInfo + // expected route, or false if the rule doesn't apply + // expected params, or not set if empty + return [ + [ + 'empty pattern', + [ + 'pattern' => '', + 'route' => 'post/index', + ], + [ + ['', 'post/index'], + ['a', false], + ], + ], + [ + 'without param', + [ + 'pattern' => 'posts', + 'route' => 'post/index', + ], + [ + ['posts', 'post/index'], + ['a', false], + ], + ], + [ + 'with dot', // https://github.com/yiisoft/yii/issues/2945 + [ + 'pattern' => 'posts.html', + 'route' => 'post/index', + ], + [ + ['posts.html', 'post/index'], + ['postsahtml', false], + ], + ], + [ + 'creation only', + [ + 'pattern' => 'posts', + 'route' => 'post/index', + 'mode' => UrlRule::CREATION_ONLY, + ], + [ + ['posts', false], + ], + ], + [ + 'with param', + [ + 'pattern' => 'post/<page>', + 'route' => 'post/index', + ], + [ + ['post/1', 'post/index', ['page' => '1']], + ['post/a', 'post/index', ['page' => 'a']], + ['post', false], + ['posts', false], + ], + ], + [ + 'with param requirement', + [ + 'pattern' => 'post/<page:\d+>', + 'route' => 'post/index', + ], + [ + ['post/1', 'post/index', ['page' => '1']], + ['post/a', false], + ['post/1/a', false], + ], + ], + [ + 'with multiple params', + [ + 'pattern' => 'post/<page:\d+>-<tag>', + 'route' => 'post/index', + ], + [ + ['post/1-a', 'post/index', ['page' => '1', 'tag' => 'a']], + ['post/a', false], + ['post/1', false], + ['post/1/a', false], + ], + ], + [ + 'with optional param', + [ + 'pattern' => 'post/<page:\d+>/<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + ], + [ + ['post/1/a', 'post/index', ['page' => '1', 'tag' => 'a']], + ['post/2/a', 'post/index', ['page' => '2', 'tag' => 'a']], + ['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], + ['post/1', 'post/index', ['page' => '1', 'tag' => '1']], + ], + ], + [ + 'with optional param not in pattern', + [ + 'pattern' => 'post/<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + ], + [ + ['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], + ['post/1', 'post/index', ['page' => '1', 'tag' => '1']], + ['post', false], + ], + ], + [ + 'multiple optional params', + [ + 'pattern' => 'post/<page:\d+>/<tag>/<sort:yes|no>', + 'route' => 'post/index', + 'defaults' => ['page' => 1, 'sort' => 'yes'], + ], + [ + ['post/1/a/yes', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'yes']], + ['post/1/a/no', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'no']], + ['post/2/a/no', 'post/index', ['page' => '2', 'tag' => 'a', 'sort' => 'no']], + ['post/2/a', 'post/index', ['page' => '2', 'tag' => 'a', 'sort' => 'yes']], + ['post/a/no', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'no']], + ['post/a', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'yes']], + ['post', false], + ], + ], + [ + 'optional param and required param separated by dashes', + [ + 'pattern' => 'post/<page:\d+>-<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + ], + [ + ['post/1-a', 'post/index', ['page' => '1', 'tag' => 'a']], + ['post/2-a', 'post/index', ['page' => '2', 'tag' => 'a']], + ['post/-a', 'post/index', ['page' => '1', 'tag' => 'a']], + ['post/a', false], + ['post-a', false], + ], + ], + [ + 'optional param at the end', + [ + 'pattern' => 'post/<tag>/<page:\d+>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + ], + [ + ['post/a/1', 'post/index', ['page' => '1', 'tag' => 'a']], + ['post/a/2', 'post/index', ['page' => '2', 'tag' => 'a']], + ['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], + ['post/2', 'post/index', ['page' => '1', 'tag' => '2']], + ['post', false], + ], + ], + [ + 'consecutive optional params', + [ + 'pattern' => 'post/<page:\d+>/<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1, 'tag' => 'a'], + ], + [ + ['post/2/b', 'post/index', ['page' => '2', 'tag' => 'b']], + ['post/2', 'post/index', ['page' => '2', 'tag' => 'a']], + ['post', 'post/index', ['page' => '1', 'tag' => 'a']], + ['post/b', 'post/index', ['page' => '1', 'tag' => 'b']], + ['post//b', false], + ], + ], + [ + 'consecutive optional params separated by dash', + [ + 'pattern' => 'post/<page:\d+>-<tag>', + 'route' => 'post/index', + 'defaults' => ['page' => 1, 'tag' => 'a'], + ], + [ + ['post/2-b', 'post/index', ['page' => '2', 'tag' => 'b']], + ['post/2-', 'post/index', ['page' => '2', 'tag' => 'a']], + ['post/-b', 'post/index', ['page' => '1', 'tag' => 'b']], + ['post/-', 'post/index', ['page' => '1', 'tag' => 'a']], + ['post', false], + ], + ], + [ + 'route has parameters', + [ + 'pattern' => '<controller>/<action>', + 'route' => '<controller>/<action>', + 'defaults' => [], + ], + [ + ['post/index', 'post/index'], + ['module/post/index', false], + ], + ], + [ + 'route has parameters with regex', + [ + 'pattern' => '<controller:post|comment>/<action>', + 'route' => '<controller>/<action>', + 'defaults' => [], + ], + [ + ['post/index', 'post/index'], + ['comment/index', 'comment/index'], + ['test/index', false], + ['post', false], + ['module/post/index', false], + ], + ], + [ + 'route has default parameter', + [ + 'pattern' => '<controller:post|comment>/<action>', + 'route' => '<controller>/<action>', + 'defaults' => ['action' => 'index'], + ], + [ + ['post/view', 'post/view'], + ['comment/view', 'comment/view'], + ['test/view', false], + ['post', 'post/index'], + ['posts', false], + ['test', false], + ['index', false], + ], + ], + [ + 'empty pattern with suffix', + [ + 'pattern' => '', + 'route' => 'post/index', + 'suffix' => '.html', + ], + [ + ['', 'post/index'], + ['.html', false], + ['a.html', false], + ], + ], + [ + 'regular pattern with suffix', + [ + 'pattern' => 'posts', + 'route' => 'post/index', + 'suffix' => '.html', + ], + [ + ['posts.html', 'post/index'], + ['posts', false], + ['posts.HTML', false], + ['a.html', false], + ['a', false], + ], + ], + [ + 'empty pattern with slash suffix', + [ + 'pattern' => '', + 'route' => 'post/index', + 'suffix' => '/', + ], + [ + ['', 'post/index'], + ['a', false], + ], + ], + [ + 'regular pattern with slash suffix', + [ + 'pattern' => 'posts', + 'route' => 'post/index', + 'suffix' => '/', + ], + [ + ['posts/', 'post/index'], + ['posts', false], + ['a', false], + ], + ], + [ + 'with host info', + [ + 'pattern' => 'post/<page:\d+>', + 'route' => 'post/index', + 'host' => 'http://<lang:en|fr>.example.com', + ], + [ + ['post/1', 'post/index', ['page' => '1', 'lang' => 'en']], + ['post/a', false], + ['post/1/a', false], + ], + ], + [ + 'with host info in pattern', + [ + 'pattern' => 'http://<lang:en|fr>.example.com/post/<page:\d+>', + 'route' => 'post/index', + ], + [ + ['post/1', 'post/index', ['page' => '1', 'lang' => 'en']], + ['post/a', false], + ['post/1/a', false], + ], + ], + [ + 'host info + defaults', // https://github.com/yiisoft/yii2/issues/6871 + [ + 'pattern' => 'http://en.example.com/<page>', + 'route' => 'post/index', + 'defaults' => ['page' => 1], + ], + [ + ['', 'post/index', ['page' => 1]], + ['2', 'post/index', ['page' => 2]], + ], + ], + ]; + } +} diff --git a/tests/framework/web/UserTest.php b/tests/framework/web/UserTest.php new file mode 100644 index 0000000..9acb83b --- /dev/null +++ b/tests/framework/web/UserTest.php @@ -0,0 +1,137 @@ +<?php + + +namespace yii\web; + +/** + * Mock for the time() function for web classes + * @return int + */ +function time() +{ + return \yiiunit\framework\web\UserTest::$time ?: \time(); +} + +namespace yiiunit\framework\web; + +use yii\base\NotSupportedException; +use yii\base\Component; +use yii\rbac\PhpManager; +use yii\web\IdentityInterface; +use yii\web\UrlManager; +use yii\web\UrlRule; +use yii\web\Request; +use Yii; +use yiiunit\TestCase; + +/** + * @group web + */ +class UserTest extends TestCase +{ + /** + * @var integer virtual time to be returned by mocked time() function. + * Null means normal time() behavior. + */ + public static $time; + + protected function tearDown() + { + Yii::$app->session->removeAll(); + static::$time = null; + parent::tearDown(); + } + + public function testLoginExpires() + { + if (getenv('TRAVIS') == 'true') { + $this->markTestSkipped('Can not reliably test this on travis-ci.'); + } + + $appConfig = [ + 'components' => [ + 'user' => [ + 'identityClass' => UserIdentity::className(), + 'authTimeout' => 10, + ], + 'authManager' => [ + 'class' => PhpManager::className(), + 'itemFile' => '@runtime/user_test_rbac_items.php', + 'assignmentFile' => '@runtime/user_test_rbac_assignments.php', + 'ruleFile' => '@runtime/user_test_rbac_rules.php', + ] + ], + ]; + $this->mockWebApplication($appConfig); + + $am = Yii::$app->authManager; + $am->removeAll(); + $am->add($role = $am->createPermission('rUser')); + $am->add($perm = $am->createPermission('doSomething')); + $am->addChild($role, $perm); + $am->assign($role, 'user1'); + + Yii::$app->session->removeAll(); + static::$time = \time(); + Yii::$app->user->login(UserIdentity::findIdentity('user1')); + +// print_r(Yii::$app->session); +// print_r($_SESSION); + + $this->mockWebApplication($appConfig); + $this->assertFalse(Yii::$app->user->isGuest); + $this->assertTrue(Yii::$app->user->can('doSomething')); + + static::$time += 5; + $this->mockWebApplication($appConfig); + $this->assertFalse(Yii::$app->user->isGuest); + $this->assertTrue(Yii::$app->user->can('doSomething')); + + static::$time += 11; + $this->mockWebApplication($appConfig); + $this->assertTrue(Yii::$app->user->isGuest); + $this->assertFalse(Yii::$app->user->can('doSomething')); + + } + +} + +class UserIdentity extends Component implements IdentityInterface +{ + private static $ids = [ + 'user1', + 'user2', + 'user3', + ]; + + private $_id; + + public static function findIdentity($id) + { + if (in_array($id, static::$ids)) { + $identitiy = new static(); + $identitiy->_id = $id; + return $identitiy; + } + } + + public static function findIdentityByAccessToken($token, $type = null) + { + throw new NotSupportedException(); + } + + public function getId() + { + return $this->_id; + } + + public function getAuthKey() + { + throw new NotSupportedException(); + } + + public function validateAuthKey($authKey) + { + throw new NotSupportedException(); + } +} \ No newline at end of file diff --git a/tests/framework/web/XmlResponseFormatterTest.php b/tests/framework/web/XmlResponseFormatterTest.php new file mode 100644 index 0000000..d98da3d --- /dev/null +++ b/tests/framework/web/XmlResponseFormatterTest.php @@ -0,0 +1,86 @@ +<?php +/** + * @link http://www.yiiframework.com/ + * @copyright Copyright (c) 2008 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +namespace yiiunit\framework\web; + +use yii\web\XmlResponseFormatter; + +/** + * @author Qiang Xue <qiang.xue@gmail.com> + * @since 2.0 + * + * @group web + */ +class XmlResponseFormatterTest extends FormatterTest +{ + /** + * @return XmlResponseFormatter + */ + protected function getFormatterInstance() + { + return new XmlResponseFormatter(); + } + + private $xmlHead = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + + private function addXmlHead(array $data) + { + foreach ($data as &$item) { + $item[1] = $this->xmlHead . $item[1]; + } + return $data; + } + + public function formatScalarDataProvider() + { + return $this->addXmlHead([ + [1, "<response>1</response>\n"], + ['abc', "<response>abc</response>\n"], + [true, "<response>1</response>\n"], + ["<>", "<response><></response>\n"], + ]); + } + + public function formatArrayDataProvider() + { + return $this->addXmlHead([ + [[], "<response/>\n"], + [[1, 'abc'], "<response><item>1</item><item>abc</item></response>\n"], + [[ + 'a' => 1, + 'b' => 'abc', + ], "<response><a>1</a><b>abc</b></response>\n"], + [[ + 1, + 'abc', + [2, 'def'], + true, + ], "<response><item>1</item><item>abc</item><item><item>2</item><item>def</item></item><item>1</item></response>\n"], + [[ + 'a' => 1, + 'b' => 'abc', + 'c' => [2, '<>'], + true, + ], "<response><a>1</a><b>abc</b><c><item>2</item><item><></item></c><item>1</item></response>\n"], + ]); + } + + public function formatObjectDataProvider() + { + return $this->addXmlHead([ + [new Post(123, 'abc'), "<response><Post><id>123</id><title>abc\n"], + [[ + new Post(123, 'abc'), + new Post(456, 'def'), + ], "123abc456def\n"], + [[ + new Post(123, '<>'), + 'a' => new Post(456, 'def'), + ], "123<>456def\n"], + ]); + } +} diff --git a/tests/framework/widgets/ActiveFieldTest.php b/tests/framework/widgets/ActiveFieldTest.php new file mode 100644 index 0000000..df419a8 --- /dev/null +++ b/tests/framework/widgets/ActiveFieldTest.php @@ -0,0 +1,366 @@ + + * + * @group widgets + */ +class ActiveFieldTest extends \yiiunit\TestCase +{ + private $activeField; + private $helperModel; + private $helperForm; + private $attributeName = 'attributeName'; + + protected function setUp() + { + parent::setUp(); + // dirty way to have Request object not throwing exception when running testHomeLinkNull() + $_SERVER['SCRIPT_FILENAME'] = "index.php"; + $_SERVER['SCRIPT_NAME'] = "index.php"; + + $this->mockWebApplication(); + + Yii::setAlias('@testWeb', '/'); + Yii::setAlias('@testWebRoot', '@yiiunit/data/web'); + + $this->helperModel = new DynamicModel(['attributeName']); + ob_start(); + $this->helperForm = new ActiveForm(['action' => '/something']); + ob_end_clean(); + + $this->activeField = new ActiveFieldExtend(true); + $this->activeField->form = $this->helperForm; + $this->activeField->form->setView($this->getView()); + $this->activeField->model = $this->helperModel; + $this->activeField->attribute = $this->attributeName; + } + + public function testRenderNoContent() + { + $expectedValue = << + + + +
        + +EOD; + + $actualValue = $this->activeField->render(); + $this->assertEqualsWithoutLE($expectedValue, $actualValue); + } + + /** + * @todo discuss|review Expected HTML shouldn't be wrapped only by the $content? + */ + public function testRenderWithCallableContent() + { + // field will be the html of the model's attribute wrapped with the return string below. + $field = $this->attributeName; + $content = function($field) { + return "
        $field
        "; + }; + + $expectedValue = << +
        + + + +
        +
        + +EOD; + + $actualValue = $this->activeField->render($content); + $this->assertEqualsWithoutLE($expectedValue, $actualValue); + } + + public function testBeginHasErros() + { + $this->helperModel->addError($this->attributeName, "Error Message"); + + $expectedValue = '
        '; + $actualValue = $this->activeField->begin(); + + $this->assertEquals($expectedValue, $actualValue); + } + + public function testBeginAttributeIsRequered() + { + $this->helperModel->addRule($this->attributeName, 'required'); + + $expectedValue = '
        '; + $actualValue = $this->activeField->begin(); + + $this->assertEquals($expectedValue, $actualValue); + } + + public function testBeginHasErrorAndRequired() + { + $this->helperModel->addError($this->attributeName, "Error Message"); + $this->helperModel->addRule($this->attributeName, 'required'); + + $expectedValue = '
        '; + $actualValue = $this->activeField->begin(); + + $this->assertEquals($expectedValue, $actualValue); + } + + public function testEnd() + { + $expectedValue = '
        '; + $actualValue = $this->activeField->end(); + + $this->assertEquals($expectedValue, $actualValue); + + // other tag + $expectedValue = ""; + $this->activeField->options['tag'] = 'article'; + $actualValue = $this->activeField->end(); + + $this->assertTrue($actualValue === $expectedValue); + } + + public function testLabel() + { + $expectedValue = ''; + $this->activeField->label(); + + $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); + + // label = false + $expectedValue = ''; + $this->activeField->label(false); + + $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); + + // $label = 'Label Name' + $label = 'Label Name'; + $expectedValue = <<{$label} +EOT; + $this->activeField->label($label); + + $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); + } + + + public function testError() + { + $expectedValue = ''; + $this->activeField->label(); + + $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); + + // label = false + $expectedValue = ''; + $this->activeField->label(false); + + $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); + + // $label = 'Label Name' + $label = 'Label Name'; + $expectedValue = <<{$label} +EOT; + $this->activeField->label($label); + + $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); + } + + public function testHint() + { + $expectedValue = '
        Hint Content
        '; + $this->activeField->hint('Hint Content'); + + $this->assertEquals($expectedValue, $this->activeField->parts['{hint}']); + } + + public function testInput() + { + $expectedValue = << +EOD; + $this->activeField->input("password"); + + $this->assertEquals($expectedValue, $this->activeField->parts['{input}']); + + // with options + $expectedValue = << +EOD; + $this->activeField->input("password", ['weird' => 'value']); + + $this->assertEquals($expectedValue, $this->activeField->parts['{input}']); + } + + public function testTextInput() + { + $expectedValue = << +EOD; + $this->activeField->textInput(); + $this->assertEquals($expectedValue, $this->activeField->parts['{input}']); + } + + public function testHiddenInput() + { + $expectedValue = << +EOD; + $this->activeField->hiddenInput(); + $this->assertEquals($expectedValue, $this->activeField->parts['{input}']); + } + + public function testListBox() + { + $expectedValue = << +EOD; + $this->activeField->listBox(["1" => "Item One", "2" => "Item 2"]); + $this->assertEqualsWithoutLE($expectedValue, $this->activeField->parts['{input}']); + } + + + + public function testGetClientOptionsReturnEmpty() + { + // setup: we want the real deal here! + $this->activeField->setClientOptionsEmpty(false); + + // expected empty + $actualValue = $this->activeField->getClientOptions(); + $this->assertTrue(empty($actualValue) === true); + } + + public function testGetClientOptionsWithActiveAttributeInScenario() + { + $this->activeField->setClientOptionsEmpty(false); + + $this->activeField->model->addRule($this->attributeName, 'yiiunit\framework\widgets\TestValidator'); + $this->activeField->form->enableClientValidation = false; + + // expected empty + $actualValue = $this->activeField->getClientOptions(); + $this->assertTrue(empty($actualValue) === true); + + } + + public function testGetClientOptionsClientValidation() + { + $this->activeField->setClientOptionsEmpty(false); + + $this->activeField->model->addRule($this->attributeName, 'yiiunit\framework\widgets\TestValidator'); + $this->activeField->enableClientValidation = true; + $actualValue = $this->activeField->getClientOptions(); + $expectedJsExpression = "function (attribute, value, messages, deferred, \$form) {return true;}"; + $this->assertEquals($expectedJsExpression, $actualValue['validate']); + + $this->assertTrue(!isset($actualValue['validateOnChange'])); + $this->assertTrue(!isset($actualValue['validateOnBlur'])); + $this->assertTrue(!isset($actualValue['validateOnType'])); + $this->assertTrue(!isset($actualValue['validationDelay'])); + $this->assertTrue(!isset($actualValue['enableAjaxValidation'])); + + $this->activeField->validateOnChange = $expectedValidateOnChange = false; + $this->activeField->validateOnBlur = $expectedValidateOnBlur = false; + $this->activeField->validateOnType = $expectedValidateOnType = true; + $this->activeField->validationDelay = $expectedValidationDelay = 100; + $this->activeField->enableAjaxValidation = $expectedEnableAjaxValidation = true; + + $actualValue = $this->activeField->getClientOptions(); + + $this->assertTrue($expectedValidateOnChange === $actualValue['validateOnChange']); + $this->assertTrue($expectedValidateOnBlur === $actualValue['validateOnBlur']); + $this->assertTrue($expectedValidateOnType === $actualValue['validateOnType']); + $this->assertTrue($expectedValidationDelay === $actualValue['validationDelay']); + $this->assertTrue($expectedEnableAjaxValidation === $actualValue['enableAjaxValidation']); + } + + public function testGetClientOptionsValidatorWhenClientSet() + { + $this->activeField->setClientOptionsEmpty(false); + $this->activeField->enableAjaxValidation = true; + $this->activeField->model->addRule($this->attributeName, 'yiiunit\framework\widgets\TestValidator'); + + foreach($this->activeField->model->validators as $validator) { + $validator->whenClient = "function (attribute, value) { return 'yii2' == 'yii2'; }"; // js + } + + $actualValue = $this->activeField->getClientOptions(); + $expectedJsExpression = "function (attribute, value, messages, deferred, \$form) {if ((function (attribute, value) " + . "{ return 'yii2' == 'yii2'; })(attribute, value)) { return true; }}"; + + $this->assertEquals($expectedJsExpression, $actualValue['validate']->expression); + } + + /** + * Helper methods + */ + protected function getView() + { + $view = new View(); + $view->setAssetManager(new AssetManager([ + 'basePath' => '@testWebRoot/assets', + 'baseUrl' => '@testWeb/assets', + ])); + + return $view; + } + +} + +/** + * Helper Classes + */ +class ActiveFieldExtend extends ActiveField +{ + private $getClientOptionsEmpty; + + public function __construct($getClientOptionsEmpty = true) + { + $this->getClientOptionsEmpty = $getClientOptionsEmpty; + } + + public function setClientOptionsEmpty($value) + { + $this->getClientOptionsEmpty = (bool) $value; + } + + /** + * Useful to test other methods from ActiveField, that call ActiveField::getClientOptions() + * but it's return value is not relevant for the test being run. + */ + public function getClientOptions() + { + return ($this->getClientOptionsEmpty) ? [] : parent::getClientOptions(); + } +} + +class TestValidator extends \yii\validators\Validator +{ + + public function clientValidateAttribute($object, $attribute, $view) + { + return "return true;"; + } + + public function setWhenClient($js) + { + $this->whenClient = $js; + } +} diff --git a/tests/framework/widgets/ActiveFormTest.php b/tests/framework/widgets/ActiveFormTest.php new file mode 100644 index 0000000..ac3a4f2 --- /dev/null +++ b/tests/framework/widgets/ActiveFormTest.php @@ -0,0 +1,77 @@ + + */ + +namespace yiiunit\framework\widgets; + +use yii\base\DynamicModel; +use yii\widgets\ActiveForm; + +/** + * @group widgets + */ +class ActiveFormTest extends \yiiunit\TestCase +{ + protected function setUp() + { + parent::setUp(); + $this->mockApplication(); + } + + public function testBooleanAttributes() + { + $o = ['template' => '{input}']; + + $model = new DynamicModel(['name']); + ob_start(); + $form = new ActiveForm(['action' => '/something']); + ob_end_clean(); + + $this->assertEqualsWithoutLE(<< + +
        +EOF +, (string) $form->field($model, 'name', $o)->input('email', ['required' => true])); + + $this->assertEqualsWithoutLE(<< + +
        +EOF + , (string) $form->field($model, 'name', $o)->input('email', ['required' => false])); + + + $this->assertEqualsWithoutLE(<< + + +EOF + , (string) $form->field($model, 'name', $o)->input('email', ['required' => 'test'])); + + } + + public function testIssue5356() + { + $o = ['template' => '{input}']; + + $model = new DynamicModel(['categories']); + $model->categories = 1; + ob_start(); + $form = new ActiveForm(['action' => '/something']); + ob_end_clean(); + + // https://github.com/yiisoft/yii2/issues/5356 + $this->assertEqualsWithoutLE(<< + + +EOF + , (string) $form->field($model, 'categories', $o)->listBox(['apple', 'banana', 'avocado'], ['multiple' => true])); + } +} diff --git a/tests/framework/widgets/BreadcrumbsTest.php b/tests/framework/widgets/BreadcrumbsTest.php new file mode 100644 index 0000000..6997e5c --- /dev/null +++ b/tests/framework/widgets/BreadcrumbsTest.php @@ -0,0 +1,175 @@ + + * + * @group widgets + */ +class BreadcrumbsTest extends \yiiunit\TestCase +{ + private $breadcrumbs; + + protected function setUp() + { + parent::setUp(); + // dirty way to have Request object not throwing exception when running testHomeLinkNull() + $_SERVER['SCRIPT_FILENAME'] = "/index.php"; + $_SERVER['SCRIPT_NAME'] = "/index.php"; + + $this->mockWebApplication(); + $this->breadcrumbs = new Breadcrumbs(); + } + + public function testHomeLinkNull() + { + $this->breadcrumbs->homeLink = null; + $this->breadcrumbs->links = ['label' => 'My Home Page', 'url' => 'http://my.example.com/yii2/link/page']; + + $expectedHtml = "
        • Home
        • \n" + . "
        • My Home Page
        • \n" + . "
        • http://my.example.com/yii2/link/page
        • \n" + . "
        "; + + ob_start(); + $this->breadcrumbs->run(); + $actualHtml = ob_get_contents(); + ob_end_clean(); + + $this->assertEquals($expectedHtml, $actualHtml); + } + + public function testEmptyLinks() + { + $this->assertNull($this->breadcrumbs->run()); + } + + public function testHomeLinkFalse() + { + $this->breadcrumbs->homeLink = false; + $this->breadcrumbs->links = ['label' => 'My Home Page', 'url' => 'http://my.example.com/yii2/link/page']; + + $expectedHtml = "
        • My Home Page
        • \n" + . "
        • http://my.example.com/yii2/link/page
        • \n" + . "
        "; + + ob_start(); + $this->breadcrumbs->run(); + $actualHtml = ob_get_contents(); + ob_end_clean(); + + $this->assertEquals($expectedHtml, $actualHtml); + } + + + public function testHomeLink() + { + $this->breadcrumbs->homeLink = ['label' => 'home-link']; + $this->breadcrumbs->links = ['label' => 'My Home Page', 'url' => 'http://my.example.com/yii2/link/page']; + + $expectedHtml = "
        • home-link
        • \n" + . "
        • My Home Page
        • \n" + . "
        • http://my.example.com/yii2/link/page
        • \n" + . "
        "; + + ob_start(); + $this->breadcrumbs->run(); + $actualHtml = ob_get_contents(); + ob_end_clean(); + + $this->assertEquals($expectedHtml, $actualHtml); + } + + public function testRenderItemException() + { + $link = ['url' => 'http://localhost/yii2']; + $method = $this->reflectMethod(); + $this->setExpectedException('yii\base\InvalidConfigException'); + $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); + } + + public function testRenderItemLabelOnly() + { + $link = ['label' => 'My-
        Test-Label']; + $method = $this->reflectMethod(); + $encodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); + + $this->assertEquals("
      1. My-<br>Test-Label
      2. \n", $encodedValue); + + //without encodeLabels + $this->breadcrumbs->encodeLabels = false; + $unencodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); + + $this->assertEquals("
      3. My-
        Test-Label
      4. \n", $unencodedValue); + } + + public function testEncodeOverride() + { + $link = ['label' => 'My-
        Test-Label', 'encode' => false]; + $method = $this->reflectMethod(); + $result = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); + + $this->assertEquals("
      5. My-
        Test-Label
      6. \n", $result); + + //without encodeLabels + $this->breadcrumbs->encodeLabels = false; + $unencodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); + + $this->assertEquals("
      7. My-
        Test-Label
      8. \n", $unencodedValue); + } + + public function testRenderItemWithLabelAndUrl() + { + $link = ['label' => 'My-
        Test-Label', 'url' => 'http://localhost/yii2']; + $method = $this->reflectMethod(); + $encodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); + + $this->assertEquals("
      9. My-<br>Test-Label
      10. \n", $encodedValue); + + // without encodeLabels + $this->breadcrumbs->encodeLabels = false; + $unencodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); + $this->assertEquals("
      11. My-
        Test-Label
      12. \n", $unencodedValue); + } + + public function testRenderItemTemplate() + { + $link = ['label' => 'My-
        Test-Label', 'url' => 'http://localhost/yii2', 'template' => "{link}\n"]; + $method = $this->reflectMethod(); + $encodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); + + $this->assertEquals("My-<br>Test-Label\n", $encodedValue); + + // without encodeLabels + $this->breadcrumbs->encodeLabels = false; + $unencodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); + $this->assertEquals("My-
        Test-Label
        \n", $unencodedValue); + } + + public function testExtraOptions() + { + $link = [ + 'label' => 'demo', + 'url' => 'http://example.com', + 'class' => 'external', + ]; + $method = $this->reflectMethod(); + $result = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); + $this->assertEquals('
      13. demo
      14. ' . "\n", $result); + } + + /** + * Helper methods + */ + protected function reflectMethod($class = '\yii\widgets\Breadcrumbs', $method = 'renderItem') + { + $value = new \ReflectionMethod($class, $method); + $value->setAccessible(true); + + return $value; + } +} diff --git a/tests/framework/widgets/LinkSorterTest.php b/tests/framework/widgets/LinkSorterTest.php new file mode 100644 index 0000000..01dc32e --- /dev/null +++ b/tests/framework/widgets/LinkSorterTest.php @@ -0,0 +1,76 @@ +getConnection(); + $this->mockWebApplication(); + $this->breadcrumbs = new Breadcrumbs(); + } + + public function testLabelsSimple() + { + $dataProvider = new ActiveDataProvider([ + 'query' => Order::find(), + 'models' => [new Order()], + 'totalCount' => 1, + 'sort' => [ + 'route' => 'site/index', + ], + ]); + + ob_start(); + echo ListView::widget([ + 'dataProvider' => $dataProvider, + 'layout' => "{sorter}", + ]); + $actualHtml = ob_get_clean(); + + $this->assertTrue(strpos($actualHtml, 'Customer') !== false); + $this->assertTrue(strpos($actualHtml, 'Invoice Total') !== false); + } + + public function testLabelsExplicit() + { + $dataProvider = new ActiveDataProvider([ + 'query' => Order::find(), + 'models' => [new Order()], + 'totalCount' => 1, + 'sort' => [ + 'attributes' => ['total'], + 'route' => 'site/index', + ], + ]); + + ob_start(); + echo ListView::widget([ + 'dataProvider' => $dataProvider, + 'layout' => "{sorter}", + ]); + $actualHtml = ob_get_clean(); + + $this->assertFalse(strpos($actualHtml, 'Customer') !== false); + $this->assertTrue(strpos($actualHtml, 'Invoice Total') !== false); + } + +} diff --git a/tests/framework/widgets/MenuTest.php b/tests/framework/widgets/MenuTest.php new file mode 100644 index 0000000..2b57898 --- /dev/null +++ b/tests/framework/widgets/MenuTest.php @@ -0,0 +1,104 @@ +mockApplication(); + } + + public function testEncodeLabel() + { + $output = Menu::widget([ + 'route' => 'test/test', + 'params' => [], + 'encodeLabels' => true, + 'items' => [ + [ + 'encode' => false, + 'label' => ' Users', + 'url' => '#', + ], + [ + 'encode' => true, + 'label' => 'Authors & Publications', + 'url' => '#', + ], + ] + ]); + + $this->assertEqualsWithoutLE(<<
      15. Users
      16. +
      17. Authors & Publications
      18. +HTML + , $output); + + $output = Menu::widget([ + 'route' => 'test/test', + 'params' => [], + 'encodeLabels' => false, + 'items' => [ + [ + 'encode' => false, + 'label' => ' Users', + 'url' => '#', + ], + [ + 'encode' => true, + 'label' => 'Authors & Publications', + 'url' => '#', + ], + ] + ]); + + $this->assertEqualsWithoutLE(<<
      19. Users
      20. +
      21. Authors & Publications
      22. +HTML + , $output); + + } + + /** + * @see https://github.com/yiisoft/yii2/issues/8064 + */ + public function testTagOption() + { + $output = Menu::widget([ + 'route' => 'test/test', + 'params' => [], + 'encodeLabels' => true, + 'options' => [ + 'tag' => false, + ], + 'items' => [ + [ + 'label' => 'item1', + 'url' => '#', + 'options' => ['tag' => 'div'], + ], + [ + 'label' => 'item2', + 'url' => '#', + 'options' => ['tag' => false], + ], + ] + ]); + + $this->assertEqualsWithoutLE(<<item1 +item2 +HTML + , $output); + } + + +} diff --git a/tests/framework/widgets/SpacelessTest.php b/tests/framework/widgets/SpacelessTest.php new file mode 100644 index 0000000..ae41b4c --- /dev/null +++ b/tests/framework/widgets/SpacelessTest.php @@ -0,0 +1,41 @@ +\n"; + + Spaceless::begin(); + echo "\t
        \n"; + + Spaceless::begin(); + echo "\t\t
        \n"; + echo "\t\t\t

        This is a left bar!

        \n"; + echo "\t\t
        \n\n"; + echo "\t\t
        \n"; + echo "\t\t\t

        This is a right bar!

        \n"; + echo "\t\t
        \n"; + Spaceless::end(); + + echo "\t
        \n"; + Spaceless::end(); + + echo "\t

        Bye!

        \n"; + echo "\n"; + + $expected = "\n

        This is a left bar!

        ". + "

        This is a right bar!

        \t

        Bye!

        \n\n"; + $this->assertEquals($expected, ob_get_clean()); + } +} diff --git a/tests/runtime/.gitignore b/tests/runtime/.gitignore new file mode 100644 index 0000000..5e31724 --- /dev/null +++ b/tests/runtime/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!/coveralls/.gitkeep diff --git a/tests/unit/.gitignore b/tests/unit/.gitignore deleted file mode 100644 index f5f5f83..0000000 --- a/tests/unit/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/runtime/cache/* -/data/config.local.php \ No newline at end of file diff --git a/tests/unit/TestCase.php b/tests/unit/TestCase.php deleted file mode 100644 index f4f8e2d..0000000 --- a/tests/unit/TestCase.php +++ /dev/null @@ -1,100 +0,0 @@ -destroyApplication(); - } - - /** - * Returns a test configuration param from /data/config.php - * @param string $name params name - * @param mixed $default default value to use when param is not set. - * @return mixed the value of the configuration param - */ - public static function getParam($name, $default = null) - { - if (static::$params === null) { - static::$params = require(__DIR__ . '/data/config.php'); - } - - return isset(static::$params[$name]) ? static::$params[$name] : $default; - } - - /** - * Populates Yii::$app with a new application - * The application will be destroyed on tearDown() automatically. - * @param array $config The application configuration, if needed - * @param string $appClass name of the application class to create - */ - protected function mockApplication($config = [], $appClass = '\yii\console\Application') - { - new $appClass(ArrayHelper::merge([ - 'id' => 'testapp', - 'basePath' => __DIR__, - 'vendorPath' => $this->getVendorPath(), - ], $config)); - } - - protected function mockWebApplication($config = [], $appClass = '\yii\web\Application') - { - new $appClass(ArrayHelper::merge([ - 'id' => 'testapp', - 'basePath' => __DIR__, - 'vendorPath' => $this->getVendorPath(), - 'components' => [ - 'request' => [ - 'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq', - 'scriptFile' => __DIR__ .'/index.php', - 'scriptUrl' => '/index.php', - ], - ] - ], $config)); - } - - protected function getVendorPath() - { - $vendor = dirname(dirname(__DIR__)) . '/vendor'; - if (!is_dir($vendor)) { - $vendor = dirname(dirname(dirname(dirname(__DIR__)))); - } - return $vendor; - } - - /** - * Destroys application in Yii::$app by setting it to null. - */ - protected function destroyApplication() - { - \Yii::$app = null; - } - - /** - * Asserting two strings equality ignoring line endings - * - * @param string $expected - * @param string $actual - */ - public function assertEqualsWithoutLE($expected, $actual) - { - $expected = str_replace("\r\n", "\n", $expected); - $actual = str_replace("\r\n", "\n", $actual); - - $this->assertEquals($expected, $actual); - } -} diff --git a/tests/unit/assets/.gitignore b/tests/unit/assets/.gitignore deleted file mode 100644 index 5e31724..0000000 --- a/tests/unit/assets/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* -!.gitignore -!/coveralls/.gitkeep diff --git a/tests/unit/bootstrap.php b/tests/unit/bootstrap.php deleted file mode 100644 index 39a7c59..0000000 --- a/tests/unit/bootstrap.php +++ /dev/null @@ -1,22 +0,0 @@ - - * @since 2.0 - */ -class ActiveRecord extends \yii\db\ActiveRecord -{ - public static $db; - - public static function getDb() - { - return self::$db; - } -} diff --git a/tests/unit/data/ar/Animal.php b/tests/unit/data/ar/Animal.php deleted file mode 100644 index 129588f..0000000 --- a/tests/unit/data/ar/Animal.php +++ /dev/null @@ -1,50 +0,0 @@ - - * @property integer $id - * @property string $type - */ -class Animal extends ActiveRecord -{ - - public $does; - - public static function tableName() - { - return 'animal'; - } - - public function init() - { - parent::init(); - $this->type = get_called_class(); - } - - public function getDoes() - { - return $this->does; - } - - /** - * - * @param type $row - * @return \yiiunit\data\ar\Animal - */ - public static function instantiate($row) - { - $class = $row['type']; - return new $class; - } - -} diff --git a/tests/unit/data/ar/Cat.php b/tests/unit/data/ar/Cat.php deleted file mode 100644 index 831cb8d..0000000 --- a/tests/unit/data/ar/Cat.php +++ /dev/null @@ -1,32 +0,0 @@ - - * @since 2.0 - */ -class Cat extends Animal -{ - - /** - * - * @param self $record - * @param array $row - */ - public static function populateRecord($record, $row) - { - parent::populateRecord($record, $row); - - $record->does = 'meow'; - } - -} diff --git a/tests/unit/data/ar/Category.php b/tests/unit/data/ar/Category.php deleted file mode 100644 index aa19326..0000000 --- a/tests/unit/data/ar/Category.php +++ /dev/null @@ -1,43 +0,0 @@ -hasMany(Item::className(), ['category_id' => 'id']); - } - - public function getLimitedItems() - { - return $this->hasMany(Item::className(), ['category_id' => 'id']) - ->onCondition(['item.id' => [1, 2, 3]]); - } - - public function getOrderItems() - { - return $this->hasMany(OrderItem::className(), ['item_id' => 'id'])->via('items'); - } - - public function getOrders() - { - return $this->hasMany(Order::className(), ['id' => 'order_id'])->via('orderItems'); - } -} diff --git a/tests/unit/data/ar/Customer.php b/tests/unit/data/ar/Customer.php deleted file mode 100644 index 65125c3..0000000 --- a/tests/unit/data/ar/Customer.php +++ /dev/null @@ -1,87 +0,0 @@ -hasOne(Profile::className(), ['id' => 'profile_id']); - } - - public function getOrders() - { - return $this->hasMany(Order::className(), ['customer_id' => 'id'])->orderBy('id'); - } - - public function getExpensiveOrders() - { - return $this->hasMany(Order::className(), ['customer_id' => 'id'])->andWhere('[[total]] > 50')->orderBy('id'); - } - - public function getExpensiveOrdersWithNullFK() - { - return $this->hasMany(OrderWithNullFK::className(), ['customer_id' => 'id'])->andWhere('[[total]] > 50')->orderBy('id'); - } - - public function getOrdersWithNullFK() - { - return $this->hasMany(OrderWithNullFK::className(), ['customer_id' => 'id'])->orderBy('id'); - } - - public function getOrders2() - { - return $this->hasMany(Order::className(), ['customer_id' => 'id'])->inverseOf('customer2')->orderBy('id'); - } - - // deeply nested table relation - public function getOrderItems() - { - /* @var $rel ActiveQuery */ - $rel = $this->hasMany(Item::className(), ['id' => 'item_id']); - - return $rel->viaTable('order_item', ['order_id' => 'id'], function ($q) { - /* @var $q ActiveQuery */ - $q->viaTable('order', ['customer_id' => 'id']); - })->orderBy('id'); - } - - public function afterSave($insert, $changedAttributes) - { - ActiveRecordTest::$afterSaveInsert = $insert; - ActiveRecordTest::$afterSaveNewRecord = $this->isNewRecord; - parent::afterSave($insert, $changedAttributes); - } - - /** - * @inheritdoc - * @return CustomerQuery - */ - public static function find() - { - return new CustomerQuery(get_called_class()); - } -} diff --git a/tests/unit/data/ar/CustomerQuery.php b/tests/unit/data/ar/CustomerQuery.php deleted file mode 100644 index 80b2b01..0000000 --- a/tests/unit/data/ar/CustomerQuery.php +++ /dev/null @@ -1,18 +0,0 @@ -andWhere('[[status]]=1'); - - return $this; - } -} diff --git a/tests/unit/data/ar/Dog.php b/tests/unit/data/ar/Dog.php deleted file mode 100644 index 9422cc5..0000000 --- a/tests/unit/data/ar/Dog.php +++ /dev/null @@ -1,32 +0,0 @@ - - * @since 2.0 - */ -class Dog extends Animal -{ - - /** - * - * @param self $record - * @param array $row - */ - public static function populateRecord($record, $row) - { - parent::populateRecord($record, $row); - - $record->does = 'bark'; - } - -} diff --git a/tests/unit/data/ar/Item.php b/tests/unit/data/ar/Item.php deleted file mode 100644 index 6567567..0000000 --- a/tests/unit/data/ar/Item.php +++ /dev/null @@ -1,23 +0,0 @@ -hasOne(Category::className(), ['id' => 'category_id']); - } -} diff --git a/tests/unit/data/ar/NullValues.php b/tests/unit/data/ar/NullValues.php deleted file mode 100644 index ad22899..0000000 --- a/tests/unit/data/ar/NullValues.php +++ /dev/null @@ -1,20 +0,0 @@ -hasOne(Customer::className(), ['id' => 'customer_id']); - } - - public function getCustomer2() - { - return $this->hasOne(Customer::className(), ['id' => 'customer_id'])->inverseOf('orders2'); - } - - public function getOrderItems() - { - return $this->hasMany(OrderItem::className(), ['order_id' => 'id']); - } - - public function getOrderItemsWithNullFK() - { - return $this->hasMany(OrderItemWithNullFK::className(), ['order_id' => 'id']); - } - - public function getItems() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function ($q) { - // additional query configuration - })->orderBy('item.id'); - } - - public function getItemsIndexed() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems')->indexBy('id'); - } - - public function getItemsWithNullFK() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->viaTable('order_item_with_null_fk', ['order_id' => 'id']); - } - - public function getItemsInOrder1() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function ($q) { - $q->orderBy(['subtotal' => SORT_ASC]); - })->orderBy('name'); - } - - public function getItemsInOrder2() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems', function ($q) { - $q->orderBy(['subtotal' => SORT_DESC]); - })->orderBy('name'); - } - - public function getBooks() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItems') - ->where(['category_id' => 1]); - } - - public function getBooksWithNullFK() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->via('orderItemsWithNullFK') - ->where(['category_id' => 1]); - } - - public function getBooksViaTable() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->viaTable('order_item', ['order_id' => 'id']) - ->where(['category_id' => 1]); - } - - public function getBooksWithNullFKViaTable() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->viaTable('order_item_with_null_fk', ['order_id' => 'id']) - ->where(['category_id' => 1]); - } - - public function getBooks2() - { - return $this->hasMany(Item::className(), ['id' => 'item_id']) - ->onCondition(['category_id' => 1]) - ->viaTable('order_item', ['order_id' => 'id']); - } - - public function beforeSave($insert) - { - if (parent::beforeSave($insert)) { - $this->created_at = time(); - - return true; - } else { - return false; - } - } - - public function attributeLabels() - { - return [ - 'customer_id' => 'Customer', - 'total' => 'Invoice Total', - ]; - } -} diff --git a/tests/unit/data/ar/OrderItem.php b/tests/unit/data/ar/OrderItem.php deleted file mode 100644 index 4c45f88..0000000 --- a/tests/unit/data/ar/OrderItem.php +++ /dev/null @@ -1,29 +0,0 @@ -hasOne(Order::className(), ['id' => 'order_id']); - } - - public function getItem() - { - return $this->hasOne(Item::className(), ['id' => 'item_id']); - } -} diff --git a/tests/unit/data/ar/OrderItemWithNullFK.php b/tests/unit/data/ar/OrderItemWithNullFK.php deleted file mode 100644 index 63e6551..0000000 --- a/tests/unit/data/ar/OrderItemWithNullFK.php +++ /dev/null @@ -1,20 +0,0 @@ - - */ - -namespace yiiunit\data\ar; - -/** - * Class Profile - * - * @property integer $id - * @property string $description - * - */ -class Profile extends ActiveRecord -{ - public static function tableName() - { - return 'profile'; - } -} diff --git a/tests/unit/data/ar/Type.php b/tests/unit/data/ar/Type.php deleted file mode 100644 index 7922ba5..0000000 --- a/tests/unit/data/ar/Type.php +++ /dev/null @@ -1,32 +0,0 @@ - 'Lennon'], - [['lastName'], 'required'], - [['underscore_style'], 'yii\captcha\CaptchaValidator'], - [['test'], 'required', 'when' => function($model) { return $model->firstName === 'cebe'; }], - ]; - } -} diff --git a/tests/unit/data/base/Speaker.php b/tests/unit/data/base/Speaker.php deleted file mode 100644 index 5e80111..0000000 --- a/tests/unit/data/base/Speaker.php +++ /dev/null @@ -1,45 +0,0 @@ - 'This is the custom label', - ]; - } - - public function rules() - { - return []; - } - - public function scenarios() - { - return [ - 'test' => ['firstName', 'lastName', '!underscore_style'], - ]; - } -} diff --git a/tests/unit/data/config.php b/tests/unit/data/config.php deleted file mode 100644 index 5003da5..0000000 --- a/tests/unit/data/config.php +++ /dev/null @@ -1,53 +0,0 @@ - [ - 'cubrid' => [ - 'dsn' => 'cubrid:dbname=demodb;host=localhost;port=33000', - 'username' => 'dba', - 'password' => '', - 'fixture' => __DIR__ . '/cubrid.sql', - ], - 'mysql' => [ - 'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest', - 'username' => 'travis', - 'password' => '', - 'fixture' => __DIR__ . '/mysql.sql', - ], - 'sqlite' => [ - 'dsn' => 'sqlite::memory:', - 'fixture' => __DIR__ . '/sqlite.sql', - ], - 'sqlsrv' => [ - 'dsn' => 'sqlsrv:Server=localhost;Database=test', - 'username' => '', - 'password' => '', - 'fixture' => __DIR__ . '/mssql.sql', - ], - 'pgsql' => [ - 'dsn' => 'pgsql:host=localhost;dbname=yiitest;port=5432;', - 'username' => 'postgres', - 'password' => 'postgres', - 'fixture' => __DIR__ . '/postgres.sql', - ], - ], -]; - -if (is_file(__DIR__ . '/config.local.php')) { - include(__DIR__ . '/config.local.php'); -} - -return $config; \ No newline at end of file diff --git a/tests/unit/data/console/controllers/fixtures/FirstFixture.php b/tests/unit/data/console/controllers/fixtures/FirstFixture.php deleted file mode 100644 index d97b542..0000000 --- a/tests/unit/data/console/controllers/fixtures/FirstFixture.php +++ /dev/null @@ -1,19 +0,0 @@ - 'Der Hund rennt schnell.', - 'His speed is about {n} km/h.' => 'Seine Geschwindigkeit beträgt {n} km/h.', - 'His name is {name} and his speed is about {n, number} km/h.' => 'Er heißt {name} und ist {n, number} km/h schnell.', -]; diff --git a/tests/unit/data/i18n/messages/de/test.php b/tests/unit/data/i18n/messages/de/test.php deleted file mode 100644 index 6d7b903..0000000 --- a/tests/unit/data/i18n/messages/de/test.php +++ /dev/null @@ -1,7 +0,0 @@ - 'Hallo Welt!', -]; diff --git a/tests/unit/data/i18n/messages/en-US/test.php b/tests/unit/data/i18n/messages/en-US/test.php deleted file mode 100644 index d14d9ca..0000000 --- a/tests/unit/data/i18n/messages/en-US/test.php +++ /dev/null @@ -1,7 +0,0 @@ - 'Der Hund rennt schell.', -]; diff --git a/tests/unit/data/i18n/messages/ru/test.php b/tests/unit/data/i18n/messages/ru/test.php deleted file mode 100644 index fd6c6c7..0000000 --- a/tests/unit/data/i18n/messages/ru/test.php +++ /dev/null @@ -1,8 +0,0 @@ - 'Собака бегает быстро.', - 'There {n, plural, =0{no cats} =1{one cat} other{are # cats}} on lying on the sofa!' => 'На диване {n, plural, =0{нет кошек} =1{лежит одна кошка} one{лежит # кошка} few{лежит # кошки} many{лежит # кошек} other{лежит # кошки}}!', -]; diff --git a/tests/unit/data/i18n/test.mo b/tests/unit/data/i18n/test.mo deleted file mode 100644 index d5f94f14a3b52a4ef0b2ddaeeb6bcff474f67594..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1426 zcma)5!EO{s5FL^wht2_sD?t=@X23>B$b=+_kjTQoDlCWtIkab+bw@KjOHYqUq#SIb zzySeL6fPVH+{n#YJg^vhIB-Vl`GNdF{vog0Ya0m;j8t1y-PQG8z3%;YZ|6aT?=#pJ zusPW0uwP;PJ%zo6{SCVdyRj>Z_QCJ|B#QRKADsBF;r~PaBm5iGoc%P42>G7fQFH+Q z2t4QAiN6kyvZwB~v*%^;ULOVT3$ zO3X=|jnA00z^fU|&~d0PuEgI%WV|b;)GZW0gQ?_La!f@2k$>gK?JZxoH~q*r?UJwk zh9CQyeB)OUHhv9@E7(SykpC-`thUQoS;3K4;lM_F$G@bIthLKHzvi15LG9O3wSn4k zdmA9j*cfvq7Gc2lFQ~oGeeeqs=zCxI*W9E19pGHC;h&*k93bCqvrc|Qs042Sp=pDJ z8IOE@h&Up^*XYA&K=SKc-hjy_>&;Pd@bv^~l~It@?Gik;G4LNDza1plJO*_H4tz+R z$AEglq=CUqY6{|UPoAam&x2e+-w`zX2bEBlCkM6m9`Cc%n{s{(`6TiW!@V^)HxV}s z03a4-6$MYA>k{HMzY=5#sw@#E82J_K|A}#bgUF44DFk0#xUm{Hk6Xq+2Ay$r?M?hy NwnF~HY{f^T{{g1ziG%\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.5.5\n" - -msgctxt "context1" -msgid "" -"Aliquam tempus elit vel purus molestie placerat. In sollicitudin tincidunt\n" -"aliquet. Integer tincidunt gravida tempor. In convallis blandit dui vel " -"malesuada.\n" -"Nunc vel sapien nunc, a pretium nulla." -msgstr "" -"Олицетворение однократно. Представленный лексико-семантический анализ " -"является\n" -"психолингвистическим в своей основе, но механизм сочленений полидисперсен. " -"Впечатление\n" -"однократно. Различное расположение выбирает сюжетный механизм сочленений." - -msgctxt "context1" -msgid "String number two." -msgstr "Строка номер два." - -msgctxt "context2" -msgid "" -"The other\n" -"\n" -"context.\n" -msgstr "" -"Другой\n" -"\n" -"контекст.\n" - -msgctxt "context1" -msgid "" -"Missing\n" -"\r\t\"translation." -msgstr "" - -msgctxt "context1" -msgid "" -"Nunc vel sapien nunc, a pretium nulla.\n" -"Pellentesque habitant morbi tristique senectus et netus et malesuada fames " -"ac turpis egestas." -msgstr "Короткий перевод." - -msgid "contextless" -msgstr "" - -msgctxt "context2" -msgid "" -"test1\\ntest2\n" -"\\\n" -"test3" -msgstr "" -"тест1\\nтест2\n" -"\\\n" -"тест3" diff --git a/tests/unit/data/mssql.sql b/tests/unit/data/mssql.sql deleted file mode 100644 index 544f480..0000000 --- a/tests/unit/data/mssql.sql +++ /dev/null @@ -1,159 +0,0 @@ -IF OBJECT_ID('[dbo].[order_item]', 'U') IS NOT NULL DROP TABLE [dbo].[order_item]; -IF OBJECT_ID('[dbo].[order_item_with_null_fk]', 'U') IS NOT NULL DROP TABLE [dbo].[order_item_with_null_fk]; -IF OBJECT_ID('[dbo].[item]', 'U') IS NOT NULL DROP TABLE [dbo].[item]; -IF OBJECT_ID('[dbo].[order]', 'U') IS NOT NULL DROP TABLE [dbo].[order]; -IF OBJECT_ID('[dbo].[order_with_null_fk]', 'U') IS NOT NULL DROP TABLE [dbo].[order_with_null_fk]; -IF OBJECT_ID('[dbo].[category]', 'U') IS NOT NULL DROP TABLE [dbo].[category]; -IF OBJECT_ID('[dbo].[customer]', 'U') IS NOT NULL DROP TABLE [dbo].[customer]; -IF OBJECT_ID('[dbo].[profile]', 'U') IS NOT NULL DROP TABLE [dbo].[profile]; -IF OBJECT_ID('[dbo].[type]', 'U') IS NOT NULL DROP TABLE [dbo].[type]; -IF OBJECT_ID('[dbo].[null_values]', 'U') IS NOT NULL DROP TABLE [dbo].[null_values]; -IF OBJECT_ID('[dbo].[animal]', 'U') IS NOT NULL DROP TABLE [dbo].[animal]; -IF OBJECT_ID('[dbo].[animal_view]', 'V') IS NOT NULL DROP VIEW [dbo].[animal_view]; - -CREATE TABLE [dbo].[profile] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [description] [varchar](128) NOT NULL, - CONSTRAINT [PK_customer] PRIMARY KEY CLUSTERED ( - [id] ASC - ) ON [PRIMARY] -); - -CREATE TABLE [dbo].[customer] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [email] [varchar](128) NOT NULL, - [name] [varchar](128), - [address] [text], - [status] [int] DEFAULT 0, - [profile_id] [int], - CONSTRAINT [PK_customer] PRIMARY KEY CLUSTERED ( - [id] ASC - ) ON [PRIMARY] -); - -CREATE TABLE [dbo].[category] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [name] [varchar](128) NOT NULL, - CONSTRAINT [PK_category] PRIMARY KEY CLUSTERED ( - [id] ASC - ) ON [PRIMARY] -); - -CREATE TABLE [dbo].[item] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [name] [varchar](128) NOT NULL, - [category_id] [int] NOT NULL, - CONSTRAINT [PK_item] PRIMARY KEY CLUSTERED ( - [id] ASC - ) ON [PRIMARY] -); - -CREATE TABLE [dbo].[order] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [customer_id] [int] NOT NULL, - [created_at] [int] NOT NULL, - [total] [decimal](10,0) NOT NULL, - CONSTRAINT [PK_order] PRIMARY KEY CLUSTERED ( - [id] ASC - ) ON [PRIMARY] -); - -CREATE TABLE [dbo].[order_with_null_fk] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [customer_id] [int] , - [created_at] [int] NOT NULL, - [total] [decimal](10,0) NOT NULL -); - -CREATE TABLE [dbo].[order_item] ( - [order_id] [int] NOT NULL, - [item_id] [int] NOT NULL, - [quantity] [int] NOT NULL, - [subtotal] [decimal](10,0) NOT NULL, - CONSTRAINT [PK_order_item] PRIMARY KEY CLUSTERED ( - [order_id] ASC, - [item_id] ASC - ) ON [PRIMARY] - -);CREATE TABLE [dbo].[order_item_with_null_fk] ( - [order_id] [int], - [item_id] [int], - [quantity] [int] NOT NULL, - [subtotal] [decimal](10,0) NOT NULL -); - -CREATE TABLE [dbo].[null_values] ( - id [int] UNSIGNED NOT NULL, - var1 [int] UNSIGNED NULL, - var2 [int] NULL, - var3 [int] DEFAULT NULL, - stringcol [varchar](32) DEFAULT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE [dbo].[type] ( - [int_col] [int] NOT NULL, - [int_col2] [int] DEFAULT '1', - [smallint_col] [smallint] DEFAULT '1', - [char_col] [char](100) NOT NULL, - [char_col2] [varchar](100) DEFAULT 'something', - [char_col3] [text], - [float_col] [decimal](4,3) NOT NULL, - [float_col2] [float] DEFAULT '1.23', - [blob_col] [varbinary](MAX), - [numeric_col] [decimal](5,2) DEFAULT '33.22', - [time] [datetime] NOT NULL DEFAULT '2002-01-01 00:00:00', - [bool_col] [tinyint] NOT NULL, - [bool_col2] [tinyint] DEFAULT '1' -); - -CREATE TABLE [dbo].[animal] ( - [id] [int] IDENTITY(1,1) NOT NULL, - [type] [varchar](255) NOT NULL, - CONSTRAINT [PK_animal] PRIMARY KEY CLUSTERED ( - [id] ASC - ) ON [PRIMARY] -); - -CREATE VIEW [dbo].[animal_view] AS SELECT * FROM [dbo].[animal]; - -INSERT INTO [dbo].[animal] (type) VALUES ('yiiunit\data\ar\Cat'); -INSERT INTO [dbo].[animal] (type) VALUES ('yiiunit\data\ar\Dog'); - -INSERT INTO [dbo].[profile] ([description]) VALUES ('profile customer 1'); -INSERT INTO [dbo].[profile] ([description]) VALUES ('profile customer 3'); - -INSERT INTO [dbo].[customer] ([email], [name], [address], [status], [profile_id]) VALUES ('user1@example.com', 'user1', 'address1', 1, 1); -INSERT INTO [dbo].[customer] ([email], [name], [address], [status]) VALUES ('user2@example.com', 'user2', 'address2', 1); -INSERT INTO [dbo].[customer] ([email], [name], [address], [status], [profile_id]) VALUES ('user3@example.com', 'user3', 'address3', 2, 2); - -INSERT INTO [dbo].[category] ([name]) VALUES ('Books'); -INSERT INTO [dbo].[category] ([name]) VALUES ('Movies'); - -INSERT INTO [dbo].[item] ([name], [category_id]) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); -INSERT INTO [dbo].[item] ([name], [category_id]) VALUES ('Yii 1.1 Application Development Cookbook', 1); -INSERT INTO [dbo].[item] ([name], [category_id]) VALUES ('Ice Age', 2); -INSERT INTO [dbo].[item] ([name], [category_id]) VALUES ('Toy Story', 2); -INSERT INTO [dbo].[item] ([name], [category_id]) VALUES ('Cars', 2); - -INSERT INTO [dbo].[order] ([customer_id], [created_at], [total]) VALUES (1, 1325282384, 110.0); -INSERT INTO [dbo].[order] ([customer_id], [created_at], [total]) VALUES (2, 1325334482, 33.0); -INSERT INTO [dbo].[order] ([customer_id], [created_at], [total]) VALUES (2, 1325502201, 40.0); - -INSERT INTO [dbo].[order_with_null_fk] ([customer_id], [created_at], [total]) VALUES (1, 1325282384, 110.0); -INSERT INTO [dbo].[order_with_null_fk] ([customer_id], [created_at], [total]) VALUES (2, 1325334482, 33.0); -INSERT INTO [dbo].[order_with_null_fk] ([customer_id], [created_at], [total]) VALUES (2, 1325502201, 40.0); - -INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 1, 1, 30.0); -INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 2, 2, 40.0); -INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 4, 1, 10.0); -INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 5, 1, 15.0); -INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 3, 1, 8.0); -INSERT INTO [dbo].[order_item] ([order_id], [item_id], [quantity], [subtotal]) VALUES (3, 2, 1, 40.0); - -INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 1, 1, 30.0); -INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 2, 2, 40.0); -INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 4, 1, 10.0); -INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 5, 1, 15.0); -INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 3, 1, 8.0); -INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (3, 2, 1, 40.0); diff --git a/tests/unit/data/mysql.sql b/tests/unit/data/mysql.sql deleted file mode 100644 index 27bb20a..0000000 --- a/tests/unit/data/mysql.sql +++ /dev/null @@ -1,210 +0,0 @@ -/** - * This is the database schema for testing MySQL support of Yii DAO and Active Record. - * The database setup in config.php is required to perform then relevant tests: - */ - -DROP TABLE IF EXISTS `composite_fk` CASCADE; -DROP TABLE IF EXISTS `order_item` CASCADE; -DROP TABLE IF EXISTS `order_item_with_null_fk` CASCADE; -DROP TABLE IF EXISTS `item` CASCADE; -DROP TABLE IF EXISTS `order` CASCADE; -DROP TABLE IF EXISTS `order_with_null_fk` CASCADE; -DROP TABLE IF EXISTS `category` CASCADE; -DROP TABLE IF EXISTS `customer` CASCADE; -DROP TABLE IF EXISTS `profile` CASCADE; -DROP TABLE IF EXISTS `null_values` CASCADE; -DROP TABLE IF EXISTS `type` CASCADE; -DROP TABLE IF EXISTS `constraints` CASCADE; -DROP TABLE IF EXISTS `animal` CASCADE; -DROP VIEW IF EXISTS `animal_view`; - -CREATE TABLE `constraints` -( - `id` integer not null, - `field1` varchar(255) -); - - -CREATE TABLE `profile` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `description` varchar(128) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `customer` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `email` varchar(128) NOT NULL, - `name` varchar(128), - `address` text, - `status` int (11) DEFAULT 0, - `profile_id` int(11), - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `category` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(128) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `item` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(128) NOT NULL, - `category_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `FK_item_category_id` (`category_id`), - CONSTRAINT `FK_item_category_id` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `order` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `customer_id` int(11) NOT NULL, - `created_at` int(11) NOT NULL, - `total` decimal(10,0) NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `FK_order_customer_id` FOREIGN KEY (`customer_id`) REFERENCES `customer` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `order_with_null_fk` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `customer_id` int(11), - `created_at` int(11) NOT NULL, - `total` decimal(10,0) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `order_item` ( - `order_id` int(11) NOT NULL, - `item_id` int(11) NOT NULL, - `quantity` int(11) NOT NULL, - `subtotal` decimal(10,0) NOT NULL, - PRIMARY KEY (`order_id`,`item_id`), - KEY `FK_order_item_item_id` (`item_id`), - CONSTRAINT `FK_order_item_order_id` FOREIGN KEY (`order_id`) REFERENCES `order` (`id`) ON DELETE CASCADE, - CONSTRAINT `FK_order_item_item_id` FOREIGN KEY (`item_id`) REFERENCES `item` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -CREATE TABLE `order_item_with_null_fk` ( - `order_id` int(11), - `item_id` int(11), - `quantity` int(11) NOT NULL, - `subtotal` decimal(10,0) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `composite_fk` ( - `id` int(11) NOT NULL, - `order_id` int(11) NOT NULL, - `item_id` int(11) NOT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `order_item` (`order_id`,`item_id`) ON DELETE CASCADE -); - -CREATE TABLE null_values ( - `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, - `var1` INT UNSIGNED NULL, - `var2` INT NULL, - `var3` INT DEFAULT NULL, - `stringcol` VARCHAR (32) DEFAULT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE `type` ( - `int_col` integer NOT NULL, - `int_col2` integer DEFAULT '1', - `smallint_col` smallint(1) DEFAULT '1', - `char_col` char(100) NOT NULL, - `char_col2` varchar(100) DEFAULT 'something', - `char_col3` text, - `enum_col` enum('a', 'B'), - `float_col` double(4,3) NOT NULL, - `float_col2` double DEFAULT '1.23', - `blob_col` blob, - `numeric_col` decimal(5,2) DEFAULT '33.22', - `time` timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', - `bool_col` tinyint(1) NOT NULL, - `bool_col2` tinyint(1) DEFAULT '1', - `ts_default` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - `bit_col` BIT(8) NOT NULL DEFAULT b'10000010' -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `animal` ( - `id` INT NOT NULL AUTO_INCREMENT, - `type` VARCHAR(255) NOT NULL, - PRIMARY KEY (id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE VIEW `animal_view` AS SELECT * FROM `animal`; - -INSERT INTO `animal` (`type`) VALUES ('yiiunit\data\ar\Cat'); -INSERT INTO `animal` (`type`) VALUES ('yiiunit\data\ar\Dog'); - -INSERT INTO `profile` (description) VALUES ('profile customer 1'); -INSERT INTO `profile` (description) VALUES ('profile customer 3'); - -INSERT INTO `customer` (email, name, address, status, profile_id) VALUES ('user1@example.com', 'user1', 'address1', 1, 1); -INSERT INTO `customer` (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); -INSERT INTO `customer` (email, name, address, status, profile_id) VALUES ('user3@example.com', 'user3', 'address3', 2, 2); - -INSERT INTO `category` (name) VALUES ('Books'); -INSERT INTO `category` (name) VALUES ('Movies'); - -INSERT INTO `item` (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); -INSERT INTO `item` (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); -INSERT INTO `item` (name, category_id) VALUES ('Ice Age', 2); -INSERT INTO `item` (name, category_id) VALUES ('Toy Story', 2); -INSERT INTO `item` (name, category_id) VALUES ('Cars', 2); - -INSERT INTO `order` (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); -INSERT INTO `order` (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); -INSERT INTO `order` (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); - -INSERT INTO `order_with_null_fk` (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); -INSERT INTO `order_with_null_fk` (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); -INSERT INTO `order_with_null_fk` (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); - -INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); -INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); -INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); -INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO `order_item` (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); - -INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); -INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); -INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); -INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); - - -/** - * (MySQL-)Database Schema for validator tests - */ - -DROP TABLE IF EXISTS `validator_main` CASCADE; -DROP TABLE IF EXISTS `validator_ref` CASCADE; - -CREATE TABLE `validator_main` ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `field1` VARCHAR(255), - PRIMARY KEY (`id`) -) ENGINE =InnoDB DEFAULT CHARSET =utf8; - -CREATE TABLE `validator_ref` ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `a_field` VARCHAR(255), - `ref` INT(11), - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -INSERT INTO `validator_main` (id, field1) VALUES (1, 'just a string1'); -INSERT INTO `validator_main` (id, field1) VALUES (2, 'just a string2'); -INSERT INTO `validator_main` (id, field1) VALUES (3, 'just a string3'); -INSERT INTO `validator_main` (id, field1) VALUES (4, 'just a string4'); -INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_2', 2); -INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_2', 2); -INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_3', 3); -INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_4', 4); -INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_4', 4); -INSERT INTO `validator_ref` (a_field, ref) VALUES ('ref_to_5', 5); diff --git a/tests/unit/data/oci.sql b/tests/unit/data/oci.sql deleted file mode 100644 index cf8736f..0000000 --- a/tests/unit/data/oci.sql +++ /dev/null @@ -1,280 +0,0 @@ -/** - * This is the database schema for testing PostgreSQL support of yii Active Record. - * To test this feature, you need to create a database named 'yiitest' on 'localhost' - * and create an account 'postgres/postgres' which owns this test database. - */ - -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "composite_fk"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "order_item"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "item"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "order_item_with_null_fk"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "order"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "order_with_null_fk"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "category"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "customer"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "profile"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "type"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "null_values"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "constraints"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "bool_values"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "animal"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP VIEW "animal_view"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "validator_main"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP TABLE "validator_ref"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;-- - -BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "profile_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "customer_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "category_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "item_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "order_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "order_with_null_fk_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "bool_values_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- -BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE "animal_SEQ"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;-- - -/* STATEMENTS */ - -CREATE TABLE "constraints" -( - "id" integer not null, - "field1" varchar2(255) -); - -CREATE TABLE "profile" ( - "id" integer not null, - "description" varchar2(128) NOT NULL, - CONSTRAINT "profile_PK" PRIMARY KEY ("id") ENABLE -); - -CREATE SEQUENCE "profile_SEQ"; - -CREATE TABLE "customer" ( - "id" integer not null, - "email" varchar2(128) NOT NULL, - "name" varchar2(128), - "address" varchar(4000), - "status" integer DEFAULT 0, - "bool_status" char DEFAULT 0 check ("bool_status" in (0,1)), - "profile_id" integer, - CONSTRAINT "customer_PK" PRIMARY KEY ("id") ENABLE -); -CREATE SEQUENCE "customer_SEQ"; - -comment on column "customer"."email" is 'someone@example.com'; - -CREATE TABLE "category" ( - "id" integer not null, - "name" varchar2(128) NOT NULL, - CONSTRAINT "category_PK" PRIMARY KEY ("id") ENABLE -); -CREATE SEQUENCE "category_SEQ"; - -CREATE TABLE "item" ( - "id" integer not null, - "name" varchar2(128) NOT NULL, - "category_id" integer NOT NULL references "category"("id") on DELETE CASCADE, - CONSTRAINT "item_PK" PRIMARY KEY ("id") ENABLE -); -CREATE SEQUENCE "item_SEQ"; - -CREATE TABLE "order" ( - "id" integer not null, - "customer_id" integer NOT NULL references "customer"("id") on DELETE CASCADE, - "created_at" integer NOT NULL, - "total" decimal(10,0) NOT NULL, - CONSTRAINT "order_PK" PRIMARY KEY ("id") ENABLE -); -CREATE SEQUENCE "order_SEQ"; - -CREATE TABLE "order_with_null_fk" ( - "id" integer not null, - "customer_id" integer, - "created_at" integer NOT NULL, - "total" decimal(10,0) NOT NULL, - CONSTRAINT "order_with_null_fk_PK" PRIMARY KEY ("id") ENABLE -); -CREATE SEQUENCE "order_with_null_fk_SEQ"; - -CREATE TABLE "order_item" ( - "order_id" integer NOT NULL references "order"("id") on DELETE CASCADE, - "item_id" integer NOT NULL references "item"("id") on DELETE CASCADE, - "quantity" integer NOT NULL, - "subtotal" decimal(10,0) NOT NULL, - CONSTRAINT "order_item_PK" PRIMARY KEY ("order_id", "item_id") ENABLE -); - -CREATE TABLE "order_item_with_null_fk" ( - "order_id" integer, - "item_id" integer, - "quantity" integer NOT NULL, - "subtotal" decimal(10,0) NOT NULL -); - -CREATE TABLE "composite_fk" ( - "id" integer NOT NULL, - "order_id" integer NOT NULL, - "item_id" integer NOT NULL, - CONSTRAINT "composite_fk_PK" PRIMARY KEY ("id") ENABLE, - CONSTRAINT FK_composite_fk_order_item FOREIGN KEY ("order_id", "item_id") - REFERENCES "order_item" ("order_id", "item_id") ON DELETE CASCADE -); - -CREATE TABLE "null_values" ( - "id" INT NOT NULL, - "var1" INT NULL, - "var2" INT NULL, - "var3" INT DEFAULT NULL, - "stringcol" varchar2(32) DEFAULT NULL, - CONSTRAINT "null_values_PK" PRIMARY KEY ("id") ENABLE -); - -CREATE TABLE "type" ( - "int_col" integer NOT NULL, - "int_col2" integer DEFAULT 1, - "smallint_col" smallint DEFAULT 1, - "char_col" char(100) NOT NULL, - "char_col2" varchar2(100) DEFAULT 'something', - "char_col3" varchar2(4000), - "float_col" double precision NOT NULL, - "float_col2" double precision DEFAULT 1.23, - "blob_col" blob, - "numeric_col" decimal(5,2) DEFAULT 33.22, - "time" timestamp DEFAULT to_timestamp('2002-01-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss') NOT NULL, - "bool_col" char NOT NULL check ("bool_col" in (0,1)), - "bool_col2" char DEFAULT 1 check("bool_col2" in (0,1)), - "ts_default" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, - "bit_col" char(3) DEFAULT 130 NOT NULL -); - -CREATE TABLE "bool_values" ( - "id" integer not null, - "bool_col" char check ("bool_col" in (0,1)), - "default_true" char default 1 not null check ("default_true" in (0,1)), - "default_false" char default 0 not null check ("default_false" in (0,1)), - CONSTRAINT "bool_values_PK" PRIMARY KEY ("id") ENABLE -); -CREATE SEQUENCE "bool_values_SEQ"; - - -CREATE TABLE "animal" ( - "id" integer, - "type" varchar2(255) not null, - CONSTRAINT "animal_PK" PRIMARY KEY ("id") ENABLE -); -CREATE SEQUENCE "animal_SEQ"; - -CREATE VIEW "animal_view" AS SELECT * FROM "animal"; - -/** - * (Postgres-)Database Schema for validator tests - */ - -CREATE TABLE "validator_main" ( - "id" integer not null, - "field1" varchar2(255), - CONSTRAINT "validator_main_PK" PRIMARY KEY ("id") ENABLE -); - -CREATE TABLE "validator_ref" ( - "id" integer not null, - "a_field" varchar2(255), - "ref" integer, - CONSTRAINT "validator_ref_PK" PRIMARY KEY ("id") ENABLE -); - -/* TRIGGERS */ - -CREATE TRIGGER "profile_TRG" BEFORE INSERT ON "profile" FOR EACH ROW BEGIN <> BEGIN - IF INSERTING AND :NEW."id" IS NULL THEN SELECT "profile_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; -END COLUMN_SEQUENCES; -END; -/ -CREATE TRIGGER "customer_TRG" BEFORE INSERT ON "customer" FOR EACH ROW BEGIN <> BEGIN - IF INSERTING AND :NEW."id" IS NULL THEN SELECT "customer_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; -END COLUMN_SEQUENCES; -END; -/ -CREATE TRIGGER "category_TRG" BEFORE INSERT ON "category" FOR EACH ROW BEGIN <> BEGIN - IF INSERTING AND :NEW."id" IS NULL THEN SELECT "category_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; -END COLUMN_SEQUENCES; -END; -/ -CREATE TRIGGER "item_TRG" BEFORE INSERT ON "item" FOR EACH ROW BEGIN <> BEGIN - IF INSERTING AND :NEW."id" IS NULL THEN SELECT "item_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; -END COLUMN_SEQUENCES; -END; -/ -CREATE TRIGGER "order_TRG" BEFORE INSERT ON "order" FOR EACH ROW BEGIN <> BEGIN - IF INSERTING AND :NEW."id" IS NULL THEN SELECT "order_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; -END COLUMN_SEQUENCES; -END; -/ -CREATE TRIGGER "order_with_null_fk_TRG" BEFORE INSERT ON "order_with_null_fk" FOR EACH ROW BEGIN <> BEGIN - IF INSERTING AND :NEW."id" IS NULL THEN SELECT "order_with_null_fk_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; -END COLUMN_SEQUENCES; -END; -/ -CREATE TRIGGER "bool_values_TRG" BEFORE INSERT ON "bool_values" FOR EACH ROW BEGIN <> BEGIN - IF INSERTING AND :NEW."id" IS NULL THEN SELECT "bool_values_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; -END COLUMN_SEQUENCES; -END; -/ -CREATE TRIGGER "animal_TRG" BEFORE INSERT ON "animal" FOR EACH ROW BEGIN <> BEGIN - IF INSERTING AND :NEW."id" IS NULL THEN SELECT "animal_SEQ".NEXTVAL INTO :NEW."id" FROM SYS.DUAL; END IF; -END COLUMN_SEQUENCES; -END; -/ - -/* TRIGGERS */ - -INSERT INTO "animal" ("type") VALUES ('yiiunit\data\ar\Cat'); -INSERT INTO "animal" ("type") VALUES ('yiiunit\data\ar\Dog'); - - -INSERT INTO "profile" ("description") VALUES ('profile customer 1'); -INSERT INTO "profile" ("description") VALUES ('profile customer 3'); - -INSERT INTO "customer" ("email", "name", "address", "status", "bool_status", "profile_id") VALUES ('user1@example.com', 'user1', 'address1', 1, 1, 1); -INSERT INTO "customer" ("email", "name", "address", "status", "bool_status") VALUES ('user2@example.com', 'user2', 'address2', 1, 1); -INSERT INTO "customer" ("email", "name", "address", "status", "bool_status", "profile_id") VALUES ('user3@example.com', 'user3', 'address3', 2, 0, 2); - -INSERT INTO "category" ("name") VALUES ('Books'); -INSERT INTO "category" ("name") VALUES ('Movies'); - -INSERT INTO "item" ("name", "category_id") VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); -INSERT INTO "item" ("name", "category_id") VALUES ('Yii 1.1 Application Development Cookbook', 1); -INSERT INTO "item" ("name", "category_id") VALUES ('Ice Age', 2); -INSERT INTO "item" ("name", "category_id") VALUES ('Toy Story', 2); -INSERT INTO "item" ("name", "category_id") VALUES ('Cars', 2); - -INSERT INTO "order" ("customer_id", "created_at", "total") VALUES (1, 1325282384, 110.0); -INSERT INTO "order" ("customer_id", "created_at", "total") VALUES (2, 1325334482, 33.0); -INSERT INTO "order" ("customer_id", "created_at", "total") VALUES (2, 1325502201, 40.0); - -INSERT INTO "order_with_null_fk" ("customer_id", "created_at", "total") VALUES (1, 1325282384, 110.0); -INSERT INTO "order_with_null_fk" ("customer_id", "created_at", "total") VALUES (2, 1325334482, 33.0); -INSERT INTO "order_with_null_fk" ("customer_id", "created_at", "total") VALUES (2, 1325502201, 40.0); - -INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (1, 1, 1, 30.0); -INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (1, 2, 2, 40.0); -INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 4, 1, 10.0); -INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 5, 1, 15.0); -INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 3, 1, 8.0); -INSERT INTO "order_item" ("order_id", "item_id", "quantity", "subtotal") VALUES (3, 2, 1, 40.0); - -INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (1, 1, 1, 30.0); -INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (1, 2, 2, 40.0); -INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 4, 1, 10.0); -INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 5, 1, 15.0); -INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 3, 1, 8.0); -INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (3, 2, 1, 40.0); - -INSERT INTO "validator_main" ("id", "field1") VALUES (1, 'just a string1'); -INSERT INTO "validator_main" ("id", "field1") VALUES (2, 'just a string2'); -INSERT INTO "validator_main" ("id", "field1") VALUES (3, 'just a string3'); -INSERT INTO "validator_main" ("id", "field1") VALUES (4, 'just a string4'); -INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (1, 'ref_to_2', 2); -INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (2, 'ref_to_2', 2); -INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (3, 'ref_to_3', 3); -INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (4, 'ref_to_4', 4); -INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (5, 'ref_to_4', 4); -INSERT INTO "validator_ref" ("id", "a_field", "ref") VALUES (6, 'ref_to_5', 5); diff --git a/tests/unit/data/postgres.sql b/tests/unit/data/postgres.sql deleted file mode 100644 index bbb8aba..0000000 --- a/tests/unit/data/postgres.sql +++ /dev/null @@ -1,210 +0,0 @@ -/** - * This is the database schema for testing PostgreSQL support of yii Active Record. - * To test this feature, you need to create a database named 'yiitest' on 'localhost' - * and create an account 'postgres/postgres' which owns this test database. - */ - -DROP TABLE IF EXISTS "composite_fk" CASCADE; -DROP TABLE IF EXISTS "order_item" CASCADE; -DROP TABLE IF EXISTS "item" CASCADE; -DROP TABLE IF EXISTS "order_item_with_null_fk" CASCADE; -DROP TABLE IF EXISTS "order" CASCADE; -DROP TABLE IF EXISTS "order_with_null_fk" CASCADE; -DROP TABLE IF EXISTS "category" CASCADE; -DROP TABLE IF EXISTS "customer" CASCADE; -DROP TABLE IF EXISTS "profile" CASCADE; -DROP TABLE IF EXISTS "type" CASCADE; -DROP TABLE IF EXISTS "null_values" CASCADE; -DROP TABLE IF EXISTS "constraints" CASCADE; -DROP TABLE IF EXISTS "bool_values" CASCADE; -DROP TABLE IF EXISTS "animal" CASCADE; -DROP VIEW IF EXISTS "animal_view"; -DROP SCHEMA IF EXISTS "schema1" CASCADE; -DROP SCHEMA IF EXISTS "schema2" CASCADE; - -CREATE SCHEMA "schema1"; -CREATE SCHEMA "schema2"; - -CREATE TABLE "constraints" -( - id integer not null, - field1 varchar(255) -); - -CREATE TABLE "profile" ( - id serial not null primary key, - description varchar(128) NOT NULL -); - -CREATE TABLE "customer" ( - id serial not null primary key, - email varchar(128) NOT NULL, - name varchar(128), - address text, - status integer DEFAULT 0, - bool_status boolean DEFAULT FALSE, - profile_id integer -); - -comment on column public.customer.email is 'someone@example.com'; - -CREATE TABLE "category" ( - id serial not null primary key, - name varchar(128) NOT NULL -); - -CREATE TABLE "item" ( - id serial not null primary key, - name varchar(128) NOT NULL, - category_id integer NOT NULL references "category"(id) on UPDATE CASCADE on DELETE CASCADE -); - -CREATE TABLE "order" ( - id serial not null primary key, - customer_id integer NOT NULL references "customer"(id) on UPDATE CASCADE on DELETE CASCADE, - created_at integer NOT NULL, - total decimal(10,0) NOT NULL -); - -CREATE TABLE "order_with_null_fk" ( - id serial not null primary key, - customer_id integer, - created_at integer NOT NULL, - total decimal(10,0) NOT NULL -); - -CREATE TABLE "order_item" ( - order_id integer NOT NULL references "order"(id) on UPDATE CASCADE on DELETE CASCADE, - item_id integer NOT NULL references "item"(id) on UPDATE CASCADE on DELETE CASCADE, - quantity integer NOT NULL, - subtotal decimal(10,0) NOT NULL, - PRIMARY KEY (order_id,item_id) -); - -CREATE TABLE "order_item_with_null_fk" ( - order_id integer, - item_id integer, - quantity integer NOT NULL, - subtotal decimal(10,0) NOT NULL -); - -CREATE TABLE "composite_fk" ( - id integer NOT NULL, - order_id integer NOT NULL, - item_id integer NOT NULL, - PRIMARY KEY (id), - CONSTRAINT FK_composite_fk_order_item FOREIGN KEY (order_id, item_id) REFERENCES "order_item" (order_id, item_id) ON DELETE CASCADE -); - -CREATE TABLE "null_values" ( - id INT NOT NULL, - var1 INT NULL, - var2 INT NULL, - var3 INT DEFAULT NULL, - stringcol VARCHAR(32) DEFAULT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE "type" ( - int_col integer NOT NULL, - int_col2 integer DEFAULT '1', - smallint_col smallint DEFAULT '1', - char_col char(100) NOT NULL, - char_col2 varchar(100) DEFAULT 'something', - char_col3 text, - float_col double precision NOT NULL, - float_col2 double precision DEFAULT '1.23', - blob_col bytea, - numeric_col decimal(5,2) DEFAULT '33.22', - time timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', - bool_col boolean NOT NULL, - bool_col2 boolean DEFAULT TRUE, - ts_default TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - bit_col BIT(8) NOT NULL DEFAULT B'10000010' -); - -CREATE TABLE "bool_values" ( - id serial not null primary key, - bool_col bool, - default_true bool not null default true, - default_false boolean not null default false -); - - -CREATE TABLE "animal" ( - id serial primary key, - type varchar(255) not null -); - -CREATE VIEW "animal_view" AS SELECT * FROM "animal"; - -INSERT INTO "animal" (type) VALUES ('yiiunit\data\ar\Cat'); -INSERT INTO "animal" (type) VALUES ('yiiunit\data\ar\Dog'); - - -INSERT INTO "profile" (description) VALUES ('profile customer 1'); -INSERT INTO "profile" (description) VALUES ('profile customer 3'); - -INSERT INTO "customer" (email, name, address, status, bool_status, profile_id) VALUES ('user1@example.com', 'user1', 'address1', 1, true, 1); -INSERT INTO "customer" (email, name, address, status, bool_status) VALUES ('user2@example.com', 'user2', 'address2', 1, true); -INSERT INTO "customer" (email, name, address, status, bool_status, profile_id) VALUES ('user3@example.com', 'user3', 'address3', 2, false, 2); - -INSERT INTO "category" (name) VALUES ('Books'); -INSERT INTO "category" (name) VALUES ('Movies'); - -INSERT INTO "item" (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); -INSERT INTO "item" (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); -INSERT INTO "item" (name, category_id) VALUES ('Ice Age', 2); -INSERT INTO "item" (name, category_id) VALUES ('Toy Story', 2); -INSERT INTO "item" (name, category_id) VALUES ('Cars', 2); - -INSERT INTO "order" (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); -INSERT INTO "order" (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); -INSERT INTO "order" (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); - -INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); -INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); -INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); - -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); - -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); - -/** - * (Postgres-)Database Schema for validator tests - */ - -DROP TABLE IF EXISTS "validator_main" CASCADE; -DROP TABLE IF EXISTS "validator_ref" CASCADE; - -CREATE TABLE "validator_main" ( - id integer not null primary key, - field1 VARCHAR(255) -); - -CREATE TABLE "validator_ref" ( - id integer not null primary key, - a_field VARCHAR(255), - ref integer -); - -INSERT INTO "validator_main" (id, field1) VALUES (1, 'just a string1'); -INSERT INTO "validator_main" (id, field1) VALUES (2, 'just a string2'); -INSERT INTO "validator_main" (id, field1) VALUES (3, 'just a string3'); -INSERT INTO "validator_main" (id, field1) VALUES (4, 'just a string4'); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (1, 'ref_to_2', 2); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (2, 'ref_to_2', 2); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (3, 'ref_to_3', 3); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (4, 'ref_to_4', 4); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (5, 'ref_to_4', 4); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (6, 'ref_to_5', 5); diff --git a/tests/unit/data/sqlite.sql b/tests/unit/data/sqlite.sql deleted file mode 100644 index 2c2d590..0000000 --- a/tests/unit/data/sqlite.sql +++ /dev/null @@ -1,189 +0,0 @@ -/** - * This is the database schema for testing Sqlite support of Yii DAO and Active Record. - * The database setup in config.php is required to perform then relevant tests: - */ - -DROP TABLE IF EXISTS "composite_fk"; -DROP TABLE IF EXISTS "order_item"; -DROP TABLE IF EXISTS "order_item_with_null_fk"; -DROP TABLE IF EXISTS "item"; -DROP TABLE IF EXISTS "order"; -DROP TABLE IF EXISTS "order_with_null_fk"; -DROP TABLE IF EXISTS "category"; -DROP TABLE IF EXISTS "customer"; -DROP TABLE IF EXISTS "profile"; -DROP TABLE IF EXISTS "type"; -DROP TABLE IF EXISTS "null_values"; -DROP TABLE IF EXISTS "animal"; -DROP VIEW IF EXISTS "animal_view"; - -CREATE TABLE "profile" ( - id INTEGER NOT NULL, - description varchar(128) NOT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE "customer" ( - id INTEGER NOT NULL, - email varchar(128) NOT NULL, - name varchar(128), - address text, - status INTEGER DEFAULT 0, - profile_id INTEGER, - PRIMARY KEY (id) -); - -CREATE TABLE "category" ( - id INTEGER NOT NULL, - name varchar(128) NOT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE "item" ( - id INTEGER NOT NULL, - name varchar(128) NOT NULL, - category_id INTEGER NOT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE "order" ( - id INTEGER NOT NULL, - customer_id INTEGER NOT NULL, - created_at INTEGER NOT NULL, - total decimal(10,0) NOT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE "order_with_null_fk" ( - id INTEGER NOT NULL, - customer_id INTEGER, - created_at INTEGER NOT NULL, - total decimal(10,0) NOT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE "order_item" ( - order_id INTEGER NOT NULL, - item_id INTEGER NOT NULL, - quantity INTEGER NOT NULL, - subtotal decimal(10,0) NOT NULL, - PRIMARY KEY (order_id, item_id) -); - -CREATE TABLE "order_item_with_null_fk" ( - order_id INTEGER, - item_id INTEGER, - quantity INTEGER NOT NULL, - subtotal decimal(10,0) NOT NULL -); - -CREATE TABLE "composite_fk" ( - id int(11) NOT NULL, - order_id int(11) NOT NULL, - item_id int(11) NOT NULL, - PRIMARY KEY (id), - CONSTRAINT FK_composite_fk_order_item FOREIGN KEY (order_id, item_id) REFERENCES "order_item" (order_id, item_id) ON DELETE CASCADE -); - -CREATE TABLE "null_values" ( - id INTEGER UNSIGNED PRIMARY KEY NOT NULL, - var1 INTEGER UNSIGNED, - var2 INTEGER, - var3 INTEGER DEFAULT NULL, - stringcol VARCHAR(32) DEFAULT NULL -); - -CREATE TABLE "type" ( - int_col INTEGER NOT NULL, - int_col2 INTEGER DEFAULT '1', - smallint_col SMALLINT(1) DEFAULT '1', - char_col char(100) NOT NULL, - char_col2 varchar(100) DEFAULT 'something', - char_col3 text, - float_col double(4,3) NOT NULL, - float_col2 double DEFAULT '1.23', - blob_col blob, - numeric_col decimal(5,2) DEFAULT '33.22', - time timestamp NOT NULL DEFAULT '2002-01-01 00:00:00', - bool_col tinyint(1) NOT NULL, - bool_col2 tinyint(1) DEFAULT '1', - ts_default TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP -); - -CREATE TABLE "animal" ( - id INTEGER NOT NULL, - type VARCHAR(255) NOT NULL, - PRIMARY KEY (id) -); - -CREATE VIEW "animal_view" AS SELECT * FROM "animal"; - -INSERT INTO "animal" ("type") VALUES ('yiiunit\data\ar\Cat'); -INSERT INTO "animal" ("type") VALUES ('yiiunit\data\ar\Dog'); - -INSERT INTO "profile" (description) VALUES ('profile customer 1'); -INSERT INTO "profile" (description) VALUES ('profile customer 3'); - -INSERT INTO "customer" (email, name, address, status, profile_id) VALUES ('user1@example.com', 'user1', 'address1', 1, 1); -INSERT INTO "customer" (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1); -INSERT INTO "customer" (email, name, address, status, profile_id) VALUES ('user3@example.com', 'user3', 'address3', 2, 2); - -INSERT INTO "category" (name) VALUES ('Books'); -INSERT INTO "category" (name) VALUES ('Movies'); - -INSERT INTO "item" (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1); -INSERT INTO "item" (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1); -INSERT INTO "item" (name, category_id) VALUES ('Ice Age', 2); -INSERT INTO "item" (name, category_id) VALUES ('Toy Story', 2); -INSERT INTO "item" (name, category_id) VALUES ('Cars', 2); - -INSERT INTO "order" (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); -INSERT INTO "order" (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); -INSERT INTO "order" (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); - -INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (1, 1325282384, 110.0); -INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (2, 1325334482, 33.0); -INSERT INTO "order_with_null_fk" (customer_id, created_at, total) VALUES (2, 1325502201, 40.0); - -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO "order_item" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); - -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); - -/** - * (SqLite-)Database Schema for validator tests - */ - -DROP TABLE IF EXISTS "validator_main"; -DROP TABLE IF EXISTS "validator_ref"; - -CREATE TABLE "validator_main" ( - id INTEGER PRIMARY KEY , - field1 VARCHAR(255) -); - -CREATE TABLE "validator_ref" ( - id INTEGER PRIMARY KEY , - a_field VARCHAR(255), - ref INT(11) -); - -INSERT INTO "validator_main" (id, field1) VALUES (1, 'just a string1'); -INSERT INTO "validator_main" (id, field1) VALUES (2, 'just a string2'); -INSERT INTO "validator_main" (id, field1) VALUES (3, 'just a string3'); -INSERT INTO "validator_main" (id, field1) VALUES (4, 'just a string4'); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (1, 'ref_to_2', 2); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (2, 'ref_to_2', 2); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (3, 'ref_to_3', 3); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (4, 'ref_to_4', 4); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (5, 'ref_to_4', 4); -INSERT INTO "validator_ref" (id, a_field, ref) VALUES (6, 'ref_to_5', 5); diff --git a/tests/unit/data/travis/README.md b/tests/unit/data/travis/README.md deleted file mode 100644 index a01c37f..0000000 --- a/tests/unit/data/travis/README.md +++ /dev/null @@ -1,12 +0,0 @@ -This directory contains scripts for automated test runs via the [Travis CI](http://travis-ci.org) build service. They are used for the preparation of worker instances by setting up needed extensions and configuring database access. - -These scripts might be used to configure your own system for test runs. But since their primary purpose remains to support Travis in running the test cases, you would be best advised to stick to the setup notes in the tests themselves. - -The scripts are: - - - [`apc-setup.sh`](apc-setup.sh) - Installs and configures the [apc pecl extension](http://pecl.php.net/package/apc) - - [`cubrid-setup.sh`](cubrid-setup.sh) - Prepares the [CUBRID](http://www.cubrid.org/) server instance by installing the server and PHP PDO driver - - [`memcache-setup.sh`](memcache-setup.sh) - Compiles and installs the [memcache pecl extension](http://pecl.php.net/package/memcache) diff --git a/tests/unit/data/travis/apc-setup.sh b/tests/unit/data/travis/apc-setup.sh deleted file mode 100755 index d64e8a5..0000000 --- a/tests/unit/data/travis/apc-setup.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -e - -if [ "$(expr "$TRAVIS_PHP_VERSION" "<" "5.5")" -eq 1 ]; then - echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "apc.enable_cli = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini -else - echo "Not installing APC as it is not available in PHP 5.5 anymore." -fi \ No newline at end of file diff --git a/tests/unit/data/travis/cubrid-setup.sh b/tests/unit/data/travis/cubrid-setup.sh deleted file mode 100755 index 81f4087..0000000 --- a/tests/unit/data/travis/cubrid-setup.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh -e -# -# install CUBRID DBMS - -if (php --version | grep -i HipHop > /dev/null); then - echo "Skipping CUBRID on HHVM" - exit 0 -fi - -CWD=$(pwd) - -# cubrid dbms -mkdir -p cubrid/$CUBRID_VERSION -cd cubrid -if (test -f $CUBRID_VERSION-linux.x86_64.tar.gz); then - echo "CUBRID is already downloaded" -else - wget http://ftp.cubrid.org/CUBRID_Engine/$CUBRID_VERSION-linux.x86_64.tar.gz -O $CUBRID_VERSION-linux.x86_64.tar.gz - cd $CUBRID_VERSION - tar xzf ../../$CUBRID_VERSION-linux.x86_64.tar.gz - cd ../.. -fi - -echo "setting cubrid env" -CUBRID=$CWD/cubrid/$CUBRID_VERSION/CUBRID -CUBRID_DATABASES=$CUBRID/databases -CUBRID_LANG=en_US - -ld_lib_path=`printenv LD_LIBRARY_PATH` || echo "LD_LIBRARY_PATH is empty" -if [ "$ld_lib_path" = "" ] -then - LD_LIBRARY_PATH=$CUBRID/lib -else - LD_LIBRARY_PATH=$CUBRID/lib:$LD_LIBRARY_PATH -fi - -SHLIB_PATH=$LD_LIBRARY_PATH -LIBPATH=$LD_LIBRARY_PATH -PATH=$CUBRID/bin:$CUBRID/cubridmanager:$PATH - -export CUBRID -export CUBRID_DATABASES -export CUBRID_LANG -export LD_LIBRARY_PATH -export SHLIB_PATH -export LIBPATH -export PATH - -# start cubrid -echo "starting cubrid..." -cubrid service start || echo "starting CUBRID services failed with exit code $?" -# create and start the demo db -$CUBRID/demo/make_cubrid_demo.sh || echo "setting up CUBRID demodb failed with exit code $?" -cubrid server start demodb || (echo "starting CUBRID demodb failed with exit code $?" && cat demodb_loaddb.log) - -echo "" -echo "Installed CUBRID $CUBRID_VERSION" -echo "" - -# cubrid pdo -install_pdo_cubrid() { - if (test "! (-f PDO_CUBRID-$CUBRID_PDO_VERSION.tgz)"); then - wget "http://pecl.php.net/get/PDO_CUBRID-$CUBRID_PDO_VERSION.tgz" -O PDO_CUBRID-$CUBRID_PDO_VERSION.tgz - fi - tar -zxf "PDO_CUBRID-$CUBRID_PDO_VERSION.tgz" - sh -c "cd PDO_CUBRID-$CUBRID_PDO_VERSION && phpize && ./configure --prefix=$CWD/cubrid/PDO_CUBRID-$CUBRID_PDO_VERSION && make" - - echo "extension=$CWD/cubrid/PDO_CUBRID-$CUBRID_PDO_VERSION/modules/pdo_cubrid.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - return $? -} - -install_pdo_cubrid > ~/pdo_cubrid.log || ( echo "=== PDO CUBRID BUILD FAILED ==="; cat ~/pdo_cubrid.log; exit 1 ) - -echo "" -echo "Installed CUBRID PDO $CUBRID_PDO_VERSION" -echo "" - -cd .. diff --git a/tests/unit/data/travis/cubrid-solo.rb b/tests/unit/data/travis/cubrid-solo.rb deleted file mode 100644 index f5f0004..0000000 --- a/tests/unit/data/travis/cubrid-solo.rb +++ /dev/null @@ -1,5 +0,0 @@ -file_cache_path "/tmp/chef-solo" -data_bag_path "/tmp/chef-solo/data_bags" -encrypted_data_bag_secret "/tmp/chef-solo/data_bag_key" -cookbook_path [ "/tmp/chef-solo/cookbooks" ] -role_path "/tmp/chef-solo/roles" \ No newline at end of file diff --git a/tests/unit/data/travis/memcache-setup.sh b/tests/unit/data/travis/memcache-setup.sh deleted file mode 100755 index e8b99e7..0000000 --- a/tests/unit/data/travis/memcache-setup.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -e - -if (php --version | grep -i HipHop > /dev/null); then - echo "skipping memcache on HHVM" -else - mkdir -p ~/.phpenv/versions/$(phpenv version-name)/etc - echo "extension=memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini -fi diff --git a/tests/unit/data/validators/TestValidator.php b/tests/unit/data/validators/TestValidator.php deleted file mode 100644 index b26a589..0000000 --- a/tests/unit/data/validators/TestValidator.php +++ /dev/null @@ -1,43 +0,0 @@ -markAttributeValidated($attribute); - if ($this->_setErrorOnValidateAttribute == true) { - $this->addError($object, $attribute, sprintf('%s##%s', $attribute, get_class($object))); - } - } - - protected function markAttributeValidated($attr, $increaseBy = 1) - { - if (!isset($this->_validatedAttributes[$attr])) { - $this->_validatedAttributes[$attr] = 1; - } else { - $this->_validatedAttributes[$attr] = $this->_validatedAttributes[$attr] + $increaseBy; - } - } - - public function countAttributeValidations($attr) - { - return isset($this->_validatedAttributes[$attr]) ? $this->_validatedAttributes[$attr] : 0; - } - - public function isAttributeValidated($attr) - { - return isset($this->_validatedAttributes[$attr]); - } - - public function enableErrorOnValidateAttribute() - { - $this->_setErrorOnValidateAttribute = true; - } -} diff --git a/tests/unit/data/validators/models/FakedValidationModel.php b/tests/unit/data/validators/models/FakedValidationModel.php deleted file mode 100644 index 6da3aa2..0000000 --- a/tests/unit/data/validators/models/FakedValidationModel.php +++ /dev/null @@ -1,66 +0,0 @@ - $value) { - $m->$attribute = $value; - } - - return $m; - } - - public function rules() - { - return [ - [['val_attr_a', 'val_attr_b'], 'required', 'on' => 'reqTest'], - ['val_attr_c', 'integer'], - ['attr_images', 'file', 'maxFiles' => 3, 'extensions' => ['png'], 'on' => 'validateMultipleFiles', 'checkExtensionByMimeType' => false], - ['attr_image', 'file', 'extensions' => ['png'], 'on' => 'validateFile', 'checkExtensionByMimeType' => false] - ]; - } - - public function inlineVal($attribute, $params = []) - { - return true; - } - - public function __get($name) - { - if (stripos($name, 'attr') === 0) { - return isset($this->attr[$name]) ? $this->attr[$name] : null; - } - - return parent::__get($name); - } - - public function __set($name, $value) - { - if (stripos($name, 'attr') === 0) { - $this->attr[$name] = $value; - } else { - parent::__set($name, $value); - } - } - - public function getAttributeLabel($attr) - { - return $attr; - } -} diff --git a/tests/unit/data/validators/models/ValidatorTestMainModel.php b/tests/unit/data/validators/models/ValidatorTestMainModel.php deleted file mode 100644 index 7031e3f..0000000 --- a/tests/unit/data/validators/models/ValidatorTestMainModel.php +++ /dev/null @@ -1,20 +0,0 @@ -hasMany(ValidatorTestRefModel::className(), ['ref' => 'id']); - } -} diff --git a/tests/unit/data/validators/models/ValidatorTestRefModel.php b/tests/unit/data/validators/models/ValidatorTestRefModel.php deleted file mode 100644 index bf0ebe5..0000000 --- a/tests/unit/data/validators/models/ValidatorTestRefModel.php +++ /dev/null @@ -1,22 +0,0 @@ -hasOne(ValidatorTestMainModel::className(), ['id' => 'ref']); - } -} diff --git a/tests/unit/data/views/layout.php b/tests/unit/data/views/layout.php deleted file mode 100644 index 321819b..0000000 --- a/tests/unit/data/views/layout.php +++ /dev/null @@ -1,20 +0,0 @@ - -beginPage(); ?> - - - - Test - head(); ?> - - -beginBody(); ?> - - - -endBody(); ?> - - -endPage(); ?> diff --git a/tests/unit/data/views/rawlayout.php b/tests/unit/data/views/rawlayout.php deleted file mode 100644 index 0d4f3e0..0000000 --- a/tests/unit/data/views/rawlayout.php +++ /dev/null @@ -1,3 +0,0 @@ -beginPage(); ?>1head(); ?>2beginBody(); ?>3endBody(); ?>4endPage(); ?> diff --git a/tests/unit/data/views/simple.php b/tests/unit/data/views/simple.php deleted file mode 100644 index 2533486..0000000 --- a/tests/unit/data/views/simple.php +++ /dev/null @@ -1 +0,0 @@ -This is a damn simple view file. diff --git a/tests/unit/data/web/assets/.gitignore b/tests/unit/data/web/assets/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/tests/unit/data/web/assets/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/tests/unit/data/web/data.txt b/tests/unit/data/web/data.txt deleted file mode 100644 index 8e58281..0000000 --- a/tests/unit/data/web/data.txt +++ /dev/null @@ -1 +0,0 @@ -12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=? \ No newline at end of file diff --git a/tests/unit/framework/BaseYiiTest.php b/tests/unit/framework/BaseYiiTest.php deleted file mode 100644 index 4168382..0000000 --- a/tests/unit/framework/BaseYiiTest.php +++ /dev/null @@ -1,63 +0,0 @@ -aliases = Yii::$aliases; - } - - protected function tearDown() - { - parent::tearDown(); - Yii::$aliases = $this->aliases; - } - - public function testAlias() - { - $this->assertEquals(YII2_PATH, Yii::getAlias('@yii')); - - Yii::$aliases = []; - $this->assertFalse(Yii::getAlias('@yii', false)); - - Yii::setAlias('@yii', '/yii/framework'); - $this->assertEquals('/yii/framework', Yii::getAlias('@yii')); - $this->assertEquals('/yii/framework/test/file', Yii::getAlias('@yii/test/file')); - Yii::setAlias('@yii/gii', '/yii/gii'); - $this->assertEquals('/yii/framework', Yii::getAlias('@yii')); - $this->assertEquals('/yii/framework/test/file', Yii::getAlias('@yii/test/file')); - $this->assertEquals('/yii/gii', Yii::getAlias('@yii/gii')); - $this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file')); - - Yii::setAlias('@tii', '@yii/test'); - $this->assertEquals('/yii/framework/test', Yii::getAlias('@tii')); - - Yii::setAlias('@yii', null); - $this->assertFalse(Yii::getAlias('@yii', false)); - $this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file')); - - Yii::setAlias('@some/alias', '/www'); - $this->assertEquals('/www', Yii::getAlias('@some/alias')); - } - - public function testGetVersion() - { - $this->assertTrue((boolean) preg_match('~\d+\.\d+(?:\.\d+)?(?:-\w+)?~', \Yii::getVersion())); - } - - public function testPowered() - { - $this->assertTrue(is_string(Yii::powered())); - } -} diff --git a/tests/unit/framework/ar/ActiveRecordTestTrait.php b/tests/unit/framework/ar/ActiveRecordTestTrait.php deleted file mode 100644 index 8ecb615..0000000 --- a/tests/unit/framework/ar/ActiveRecordTestTrait.php +++ /dev/null @@ -1,1144 +0,0 @@ - - */ - -namespace yiiunit\framework\ar; - -use yii\base\Event; -use yii\db\ActiveQueryInterface; -use yii\db\BaseActiveRecord; -use yiiunit\TestCase; -use yiiunit\data\ar\Customer; -use yiiunit\data\ar\Order; - -/** - * This trait provides unit tests shared by the different AR implementations - */ -trait ActiveRecordTestTrait -{ - /* @var $this TestCase */ - /** - * This method should return the classname of Customer class - * @return string - */ - abstract public function getCustomerClass(); - - /** - * This method should return the classname of Order class - * @return string - */ - abstract public function getOrderClass(); - - /** - * This method should return the classname of OrderItem class - * @return string - */ - abstract public function getOrderItemClass(); - - /** - * This method should return the classname of Item class - * @return string - */ - abstract public function getItemClass(); - - abstract public function getOrderWithNullFKClass(); - - abstract public function getOrderItemWithNullFKmClass(); - - /** - * can be overridden to do things after save() - */ - public function afterSave() - { - } - - public function testFind() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - // find one - $result = $customerClass::find(); - $this->assertTrue($result instanceof ActiveQueryInterface); - $customer = $result->one(); - $this->assertTrue($customer instanceof $customerClass); - - // find all - $customers = $customerClass::find()->all(); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers[0] instanceof $customerClass); - $this->assertTrue($customers[1] instanceof $customerClass); - $this->assertTrue($customers[2] instanceof $customerClass); - - // find by a single primary key - $customer = $customerClass::findOne(2); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals('user2', $customer->name); - $customer = $customerClass::findOne(5); - $this->assertNull($customer); - $customer = $customerClass::findOne(['id' => [5, 6, 1]]); - $this->assertEquals(1, count($customer)); - $customer = $customerClass::find()->where(['id' => [5, 6, 1]])->one(); - $this->assertNotNull($customer); - - // find by column values - $customer = $customerClass::findOne(['id' => 2, 'name' => 'user2']); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals('user2', $customer->name); - $customer = $customerClass::findOne(['id' => 2, 'name' => 'user1']); - $this->assertNull($customer); - $customer = $customerClass::findOne(['id' => 5]); - $this->assertNull($customer); - $customer = $customerClass::findOne(['name' => 'user5']); - $this->assertNull($customer); - - // find by attributes - $customer = $customerClass::find()->where(['name' => 'user2'])->one(); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals(2, $customer->id); - - // scope - $this->assertEquals(2, count($customerClass::find()->active()->all())); - $this->assertEquals(2, $customerClass::find()->active()->count()); - } - - public function testFindAsArray() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - // asArray - $customer = $customerClass::find()->where(['id' => 2])->asArray()->one(); - $this->assertEquals([ - 'id' => 2, - 'email' => 'user2@example.com', - 'name' => 'user2', - 'address' => 'address2', - 'status' => 1, - 'profile_id' => null, - ], $customer); - - // find all asArray - $customers = $customerClass::find()->asArray()->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers[0]); - $this->assertArrayHasKey('name', $customers[0]); - $this->assertArrayHasKey('email', $customers[0]); - $this->assertArrayHasKey('address', $customers[0]); - $this->assertArrayHasKey('status', $customers[0]); - $this->assertArrayHasKey('id', $customers[1]); - $this->assertArrayHasKey('name', $customers[1]); - $this->assertArrayHasKey('email', $customers[1]); - $this->assertArrayHasKey('address', $customers[1]); - $this->assertArrayHasKey('status', $customers[1]); - $this->assertArrayHasKey('id', $customers[2]); - $this->assertArrayHasKey('name', $customers[2]); - $this->assertArrayHasKey('email', $customers[2]); - $this->assertArrayHasKey('address', $customers[2]); - $this->assertArrayHasKey('status', $customers[2]); - } - - public function testFindScalar() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - // query scalar - $customerName = $customerClass::find()->where(['id' => 2])->scalar('name'); - $this->assertEquals('user2', $customerName); - $customerName = $customerClass::find()->where(['status' => 2])->scalar('name'); - $this->assertEquals('user3', $customerName); - $customerName = $customerClass::find()->where(['status' => 2])->scalar('noname'); - $this->assertNull($customerName); - $customerId = $customerClass::find()->where(['status' => 2])->scalar('id'); - $this->assertEquals(3, $customerId); - } - - public function testFindColumn() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - $this->assertEquals(['user1', 'user2', 'user3'], $customerClass::find()->orderBy(['name' => SORT_ASC])->column('name')); - $this->assertEquals(['user3', 'user2', 'user1'], $customerClass::find()->orderBy(['name' => SORT_DESC])->column('name')); - } - - public function testFindIndexBy() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - // indexBy - $customers = $customerClass::find()->indexBy('name')->orderBy('id')->all(); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers['user1'] instanceof $customerClass); - $this->assertTrue($customers['user2'] instanceof $customerClass); - $this->assertTrue($customers['user3'] instanceof $customerClass); - - // indexBy callable - $customers = $customerClass::find()->indexBy(function ($customer) { - return $customer->id . '-' . $customer->name; - })->orderBy('id')->all(); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers['1-user1'] instanceof $customerClass); - $this->assertTrue($customers['2-user2'] instanceof $customerClass); - $this->assertTrue($customers['3-user3'] instanceof $customerClass); - } - - public function testFindIndexByAsArray() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - // indexBy + asArray - $customers = $customerClass::find()->asArray()->indexBy('name')->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers['user1']); - $this->assertArrayHasKey('name', $customers['user1']); - $this->assertArrayHasKey('email', $customers['user1']); - $this->assertArrayHasKey('address', $customers['user1']); - $this->assertArrayHasKey('status', $customers['user1']); - $this->assertArrayHasKey('id', $customers['user2']); - $this->assertArrayHasKey('name', $customers['user2']); - $this->assertArrayHasKey('email', $customers['user2']); - $this->assertArrayHasKey('address', $customers['user2']); - $this->assertArrayHasKey('status', $customers['user2']); - $this->assertArrayHasKey('id', $customers['user3']); - $this->assertArrayHasKey('name', $customers['user3']); - $this->assertArrayHasKey('email', $customers['user3']); - $this->assertArrayHasKey('address', $customers['user3']); - $this->assertArrayHasKey('status', $customers['user3']); - - // indexBy callable + asArray - $customers = $customerClass::find()->indexBy(function ($customer) { - return $customer['id'] . '-' . $customer['name']; - })->asArray()->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers['1-user1']); - $this->assertArrayHasKey('name', $customers['1-user1']); - $this->assertArrayHasKey('email', $customers['1-user1']); - $this->assertArrayHasKey('address', $customers['1-user1']); - $this->assertArrayHasKey('status', $customers['1-user1']); - $this->assertArrayHasKey('id', $customers['2-user2']); - $this->assertArrayHasKey('name', $customers['2-user2']); - $this->assertArrayHasKey('email', $customers['2-user2']); - $this->assertArrayHasKey('address', $customers['2-user2']); - $this->assertArrayHasKey('status', $customers['2-user2']); - $this->assertArrayHasKey('id', $customers['3-user3']); - $this->assertArrayHasKey('name', $customers['3-user3']); - $this->assertArrayHasKey('email', $customers['3-user3']); - $this->assertArrayHasKey('address', $customers['3-user3']); - $this->assertArrayHasKey('status', $customers['3-user3']); - } - - public function testRefresh() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - $customer = new $customerClass(); - $this->assertFalse($customer->refresh()); - - $customer = $customerClass::findOne(1); - $customer->name = 'to be refreshed'; - $this->assertTrue($customer->refresh()); - $this->assertEquals('user1', $customer->name); - } - - public function testEquals() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $itemClass \yii\db\ActiveRecordInterface */ - $itemClass = $this->getItemClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - $customerA = new $customerClass(); - $customerB = new $customerClass(); - $this->assertFalse($customerA->equals($customerB)); - - $customerA = new $customerClass(); - $customerB = new $itemClass(); - $this->assertFalse($customerA->equals($customerB)); - - $customerA = $customerClass::findOne(1); - $customerB = $customerClass::findOne(2); - $this->assertFalse($customerA->equals($customerB)); - - $customerB = $customerClass::findOne(1); - $this->assertTrue($customerA->equals($customerB)); - - $customerA = $customerClass::findOne(1); - $customerB = $itemClass::findOne(1); - $this->assertFalse($customerA->equals($customerB)); - } - - public function testFindCount() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - $this->assertEquals(3, $customerClass::find()->count()); - - $this->assertEquals(1, $customerClass::find()->where(['id' => 1])->count()); - $this->assertEquals(2, $customerClass::find()->where(['id' => [1, 2]])->count()); - $this->assertEquals(2, $customerClass::find()->where(['id' => [1, 2]])->offset(1)->count()); - $this->assertEquals(2, $customerClass::find()->where(['id' => [1, 2]])->offset(2)->count()); - - // limit should have no effect on count() - $this->assertEquals(3, $customerClass::find()->limit(1)->count()); - $this->assertEquals(3, $customerClass::find()->limit(2)->count()); - $this->assertEquals(3, $customerClass::find()->limit(10)->count()); - $this->assertEquals(3, $customerClass::find()->offset(2)->limit(2)->count()); - } - - public function testFindLimit() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - // all() - $customers = $customerClass::find()->all(); - $this->assertEquals(3, count($customers)); - - $customers = $customerClass::find()->orderBy('id')->limit(1)->all(); - $this->assertEquals(1, count($customers)); - $this->assertEquals('user1', $customers[0]->name); - - $customers = $customerClass::find()->orderBy('id')->limit(1)->offset(1)->all(); - $this->assertEquals(1, count($customers)); - $this->assertEquals('user2', $customers[0]->name); - - $customers = $customerClass::find()->orderBy('id')->limit(1)->offset(2)->all(); - $this->assertEquals(1, count($customers)); - $this->assertEquals('user3', $customers[0]->name); - - $customers = $customerClass::find()->orderBy('id')->limit(2)->offset(1)->all(); - $this->assertEquals(2, count($customers)); - $this->assertEquals('user2', $customers[0]->name); - $this->assertEquals('user3', $customers[1]->name); - - $customers = $customerClass::find()->limit(2)->offset(3)->all(); - $this->assertEquals(0, count($customers)); - - // one() - $customer = $customerClass::find()->orderBy('id')->one(); - $this->assertEquals('user1', $customer->name); - - $customer = $customerClass::find()->orderBy('id')->offset(0)->one(); - $this->assertEquals('user1', $customer->name); - - $customer = $customerClass::find()->orderBy('id')->offset(1)->one(); - $this->assertEquals('user2', $customer->name); - - $customer = $customerClass::find()->orderBy('id')->offset(2)->one(); - $this->assertEquals('user3', $customer->name); - - $customer = $customerClass::find()->offset(3)->one(); - $this->assertNull($customer); - - } - - public function testFindComplexCondition() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - $this->assertEquals(2, $customerClass::find()->where(['OR', ['name' => 'user1'], ['name' => 'user2']])->count()); - $this->assertEquals(2, count($customerClass::find()->where(['OR', ['name' => 'user1'], ['name' => 'user2']])->all())); - - $this->assertEquals(2, $customerClass::find()->where(['name' => ['user1', 'user2']])->count()); - $this->assertEquals(2, count($customerClass::find()->where(['name' => ['user1', 'user2']])->all())); - - $this->assertEquals(1, $customerClass::find()->where(['AND', ['name' => ['user2', 'user3']], ['BETWEEN', 'status', 2, 4]])->count()); - $this->assertEquals(1, count($customerClass::find()->where(['AND', ['name' => ['user2', 'user3']], ['BETWEEN', 'status', 2, 4]])->all())); - } - - public function testFindNullValues() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - $customer = $customerClass::findOne(2); - $customer->name = null; - $customer->save(false); - $this->afterSave(); - - $result = $customerClass::find()->where(['name' => null])->all(); - $this->assertEquals(1, count($result)); - $this->assertEquals(2, reset($result)->primaryKey); - } - - public function testExists() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - $this->assertTrue($customerClass::find()->where(['id' => 2])->exists()); - $this->assertFalse($customerClass::find()->where(['id' => 5])->exists()); - $this->assertTrue($customerClass::find()->where(['name' => 'user1'])->exists()); - $this->assertFalse($customerClass::find()->where(['name' => 'user5'])->exists()); - - $this->assertTrue($customerClass::find()->where(['id' => [2, 3]])->exists()); - $this->assertTrue($customerClass::find()->where(['id' => [2, 3]])->offset(1)->exists()); - $this->assertFalse($customerClass::find()->where(['id' => [2, 3]])->offset(2)->exists()); - } - - public function testFindLazy() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - $customer = $customerClass::findOne(2); - $this->assertFalse($customer->isRelationPopulated('orders')); - $orders = $customer->orders; - $this->assertTrue($customer->isRelationPopulated('orders')); - $this->assertEquals(2, count($orders)); - $this->assertEquals(1, count($customer->relatedRecords)); - - // unset - unset($customer['orders']); - $this->assertFalse($customer->isRelationPopulated('orders')); - - /* @var $customer Customer */ - $customer = $customerClass::findOne(2); - $this->assertFalse($customer->isRelationPopulated('orders')); - $orders = $customer->getOrders()->where(['id' => 3])->all(); - $this->assertFalse($customer->isRelationPopulated('orders')); - $this->assertEquals(0, count($customer->relatedRecords)); - - $this->assertEquals(1, count($orders)); - $this->assertEquals(3, $orders[0]->id); - } - - public function testFindEager() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $orderClass \yii\db\ActiveRecordInterface */ - $orderClass = $this->getOrderClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - $customers = $customerClass::find()->with('orders')->indexBy('id')->all(); - ksort($customers); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers[1]->isRelationPopulated('orders')); - $this->assertTrue($customers[2]->isRelationPopulated('orders')); - $this->assertTrue($customers[3]->isRelationPopulated('orders')); - $this->assertEquals(1, count($customers[1]->orders)); - $this->assertEquals(2, count($customers[2]->orders)); - $this->assertEquals(0, count($customers[3]->orders)); - // unset - unset($customers[1]->orders); - $this->assertFalse($customers[1]->isRelationPopulated('orders')); - - $customer = $customerClass::find()->where(['id' => 1])->with('orders')->one(); - $this->assertTrue($customer->isRelationPopulated('orders')); - $this->assertEquals(1, count($customer->orders)); - $this->assertEquals(1, count($customer->relatedRecords)); - - // multiple with() calls - $orders = $orderClass::find()->with('customer', 'items')->all(); - $this->assertEquals(3, count($orders)); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[0]->isRelationPopulated('items')); - $orders = $orderClass::find()->with('customer')->with('items')->all(); - $this->assertEquals(3, count($orders)); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[0]->isRelationPopulated('items')); - } - - public function testFindLazyVia() - { - /* @var $orderClass \yii\db\ActiveRecordInterface */ - $orderClass = $this->getOrderClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - /* @var $order Order */ - $order = $orderClass::findOne(1); - $this->assertEquals(1, $order->id); - $this->assertEquals(2, count($order->items)); - $this->assertEquals(1, $order->items[0]->id); - $this->assertEquals(2, $order->items[1]->id); - } - - public function testFindLazyVia2() - { - /* @var $orderClass \yii\db\ActiveRecordInterface */ - $orderClass = $this->getOrderClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - /* @var $order Order */ - $order = $orderClass::findOne(1); - $order->id = 100; - $this->assertEquals([], $order->items); - } - - public function testFindEagerViaRelation() - { - /* @var $orderClass \yii\db\ActiveRecordInterface */ - $orderClass = $this->getOrderClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - $orders = $orderClass::find()->with('items')->orderBy('id')->all(); - $this->assertEquals(3, count($orders)); - $order = $orders[0]; - $this->assertEquals(1, $order->id); - $this->assertTrue($order->isRelationPopulated('items')); - $this->assertEquals(2, count($order->items)); - $this->assertEquals(1, $order->items[0]->id); - $this->assertEquals(2, $order->items[1]->id); - } - - public function testFindNestedRelation() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - $customers = $customerClass::find()->with('orders', 'orders.items')->indexBy('id')->all(); - ksort($customers); - $this->assertEquals(3, count($customers)); - $this->assertTrue($customers[1]->isRelationPopulated('orders')); - $this->assertTrue($customers[2]->isRelationPopulated('orders')); - $this->assertTrue($customers[3]->isRelationPopulated('orders')); - $this->assertEquals(1, count($customers[1]->orders)); - $this->assertEquals(2, count($customers[2]->orders)); - $this->assertEquals(0, count($customers[3]->orders)); - $this->assertTrue($customers[1]->orders[0]->isRelationPopulated('items')); - $this->assertTrue($customers[2]->orders[0]->isRelationPopulated('items')); - $this->assertTrue($customers[2]->orders[1]->isRelationPopulated('items')); - $this->assertEquals(2, count($customers[1]->orders[0]->items)); - $this->assertEquals(3, count($customers[2]->orders[0]->items)); - $this->assertEquals(1, count($customers[2]->orders[1]->items)); - } - - /** - * Ensure ActiveRelationTrait does preserve order of items on find via() - * https://github.com/yiisoft/yii2/issues/1310 - */ - public function testFindEagerViaRelationPreserveOrder() - { - /* @var $orderClass \yii\db\ActiveRecordInterface */ - $orderClass = $this->getOrderClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - - /* - Item (name, category_id) - Order (customer_id, created_at, total) - OrderItem (order_id, item_id, quantity, subtotal) - - Result should be the following: - - Order 1: 1, 1325282384, 110.0 - - orderItems: - OrderItem: 1, 1, 1, 30.0 - OrderItem: 1, 2, 2, 40.0 - - itemsInOrder: - Item 1: 'Agile Web Application Development with Yii1.1 and PHP5', 1 - Item 2: 'Yii 1.1 Application Development Cookbook', 1 - - Order 2: 2, 1325334482, 33.0 - - orderItems: - OrderItem: 2, 3, 1, 8.0 - OrderItem: 2, 4, 1, 10.0 - OrderItem: 2, 5, 1, 15.0 - - itemsInOrder: - Item 5: 'Cars', 2 - Item 3: 'Ice Age', 2 - Item 4: 'Toy Story', 2 - Order 3: 2, 1325502201, 40.0 - - orderItems: - OrderItem: 3, 2, 1, 40.0 - - itemsInOrder: - Item 3: 'Ice Age', 2 - */ - $orders = $orderClass::find()->with('itemsInOrder1')->orderBy('created_at')->all(); - $this->assertEquals(3, count($orders)); - - $order = $orders[0]; - $this->assertEquals(1, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder1')); - $this->assertEquals(2, count($order->itemsInOrder1)); - $this->assertEquals(1, $order->itemsInOrder1[0]->id); - $this->assertEquals(2, $order->itemsInOrder1[1]->id); - - $order = $orders[1]; - $this->assertEquals(2, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder1')); - $this->assertEquals(3, count($order->itemsInOrder1)); - $this->assertEquals(5, $order->itemsInOrder1[0]->id); - $this->assertEquals(3, $order->itemsInOrder1[1]->id); - $this->assertEquals(4, $order->itemsInOrder1[2]->id); - - $order = $orders[2]; - $this->assertEquals(3, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder1')); - $this->assertEquals(1, count($order->itemsInOrder1)); - $this->assertEquals(2, $order->itemsInOrder1[0]->id); - } - - // different order in via table - public function testFindEagerViaRelationPreserveOrderB() - { - /* @var $orderClass \yii\db\ActiveRecordInterface */ - $orderClass = $this->getOrderClass(); - - $orders = $orderClass::find()->with('itemsInOrder2')->orderBy('created_at')->all(); - $this->assertEquals(3, count($orders)); - - $order = $orders[0]; - $this->assertEquals(1, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder2')); - $this->assertEquals(2, count($order->itemsInOrder2)); - $this->assertEquals(1, $order->itemsInOrder2[0]->id); - $this->assertEquals(2, $order->itemsInOrder2[1]->id); - - $order = $orders[1]; - $this->assertEquals(2, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder2')); - $this->assertEquals(3, count($order->itemsInOrder2)); - $this->assertEquals(5, $order->itemsInOrder2[0]->id); - $this->assertEquals(3, $order->itemsInOrder2[1]->id); - $this->assertEquals(4, $order->itemsInOrder2[2]->id); - - $order = $orders[2]; - $this->assertEquals(3, $order->id); - $this->assertTrue($order->isRelationPopulated('itemsInOrder2')); - $this->assertEquals(1, count($order->itemsInOrder2)); - $this->assertEquals(2, $order->itemsInOrder2[0]->id); - } - - public function testLink() - { - /* @var $orderClass \yii\db\ActiveRecordInterface */ - /* @var $itemClass \yii\db\ActiveRecordInterface */ - /* @var $orderItemClass \yii\db\ActiveRecordInterface */ - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - $orderClass = $this->getOrderClass(); - $orderItemClass = $this->getOrderItemClass(); - $itemClass = $this->getItemClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - $customer = $customerClass::findOne(2); - $this->assertEquals(2, count($customer->orders)); - - // has many - $order = new $orderClass; - $order->total = 100; - $this->assertTrue($order->isNewRecord); - $customer->link('orders', $order); - $this->afterSave(); - $this->assertEquals(3, count($customer->orders)); - $this->assertFalse($order->isNewRecord); - $this->assertEquals(3, count($customer->getOrders()->all())); - $this->assertEquals(2, $order->customer_id); - - // belongs to - $order = new $orderClass; - $order->total = 100; - $this->assertTrue($order->isNewRecord); - $customer = $customerClass::findOne(1); - $this->assertNull($order->customer); - $order->link('customer', $customer); - $this->assertFalse($order->isNewRecord); - $this->assertEquals(1, $order->customer_id); - $this->assertEquals(1, $order->customer->primaryKey); - - // via model - $order = $orderClass::findOne(1); - $this->assertEquals(2, count($order->items)); - $this->assertEquals(2, count($order->orderItems)); - $orderItem = $orderItemClass::findOne(['order_id' => 1, 'item_id' => 3]); - $this->assertNull($orderItem); - $item = $itemClass::findOne(3); - $order->link('items', $item, ['quantity' => 10, 'subtotal' => 100]); - $this->afterSave(); - $this->assertEquals(3, count($order->items)); - $this->assertEquals(3, count($order->orderItems)); - $orderItem = $orderItemClass::findOne(['order_id' => 1, 'item_id' => 3]); - $this->assertTrue($orderItem instanceof $orderItemClass); - $this->assertEquals(10, $orderItem->quantity); - $this->assertEquals(100, $orderItem->subtotal); - } - - public function testUnlink() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $orderClass \yii\db\ActiveRecordInterface */ - $orderClass = $this->getOrderClass(); - /* @var $orderWithNullFKClass \yii\db\ActiveRecordInterface */ - $orderWithNullFKClass = $this->getOrderWithNullFKClass(); - /* @var $orderItemsWithNullFKClass \yii\db\ActiveRecordInterface */ - $orderItemsWithNullFKClass = $this->getOrderItemWithNullFKmClass(); - - - - /* @var $this TestCase|ActiveRecordTestTrait */ - // has many without delete - $customer = $customerClass::findOne(2); - $this->assertEquals(2, count($customer->ordersWithNullFK)); - $customer->unlink('ordersWithNullFK', $customer->ordersWithNullFK[1], false); - - $this->assertEquals(1, count($customer->ordersWithNullFK)); - $orderWithNullFK = $orderWithNullFKClass::findOne(3); - - $this->assertEquals(3,$orderWithNullFK->id); - $this->assertNull($orderWithNullFK->customer_id); - - // has many with delete - $customer = $customerClass::findOne(2); - $this->assertEquals(2, count($customer->orders)); - $customer->unlink('orders', $customer->orders[1], true); - $this->afterSave(); - - $this->assertEquals(1, count($customer->orders)); - $this->assertNull($orderClass::findOne(3)); - - // via model with delete - $order = $orderClass::findOne(2); - $this->assertEquals(3, count($order->items)); - $this->assertEquals(3, count($order->orderItems)); - $order->unlink('items', $order->items[2], true); - $this->afterSave(); - - $this->assertEquals(2, count($order->items)); - $this->assertEquals(2, count($order->orderItems)); - - // via model without delete - $this->assertEquals(3, count($order->itemsWithNullFK)); - $order->unlink('itemsWithNullFK', $order->itemsWithNullFK[2], false); - $this->afterSave(); - - $this->assertEquals(2, count($order->itemsWithNullFK)); - $this->assertEquals(2, count($order->orderItems)); - } - - public function testUnlinkAll() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $orderClass \yii\db\ActiveRecordInterface */ - $orderClass = $this->getOrderClass(); - /* @var $orderItemClass \yii\db\ActiveRecordInterface */ - $orderItemClass = $this->getOrderItemClass(); - /* @var $itemClass \yii\db\ActiveRecordInterface */ - $itemClass = $this->getItemClass(); - /* @var $orderWithNullFKClass \yii\db\ActiveRecordInterface */ - $orderWithNullFKClass = $this->getOrderWithNullFKClass(); - /* @var $orderItemsWithNullFKClass \yii\db\ActiveRecordInterface */ - $orderItemsWithNullFKClass = $this->getOrderItemWithNullFKmClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ - // has many with delete - $customer = $customerClass::findOne(2); - $this->assertEquals(2, count($customer->orders)); - $this->assertEquals(3, $orderClass::find()->count()); - $customer->unlinkAll('orders', true); - $this->afterSave(); - $this->assertEquals(1, $orderClass::find()->count()); - $this->assertEquals(0, count($customer->orders)); - - $this->assertNull($orderClass::findOne(2)); - $this->assertNull($orderClass::findOne(3)); - - - // has many without delete - $customer = $customerClass::findOne(2); - $this->assertEquals(2, count($customer->ordersWithNullFK)); - $this->assertEquals(3, $orderWithNullFKClass::find()->count()); - $customer->unlinkAll('ordersWithNullFK', false); - $this->afterSave(); - $this->assertEquals(0, count($customer->ordersWithNullFK)); - $this->assertEquals(3, $orderWithNullFKClass::find()->count()); - $this->assertEquals(2, $orderWithNullFKClass::find()->where(['AND', ['id' => [2, 3]], ['customer_id' => null]])->count()); - - - // via model with delete - /* @var $order Order */ - $order = $orderClass::findOne(1); - $this->assertEquals(2, count($order->books)); - $orderItemCount = $orderItemClass::find()->count(); - $this->assertEquals(5, $itemClass::find()->count()); - $order->unlinkAll('books', true); - $this->afterSave(); - $this->assertEquals(5, $itemClass::find()->count()); - $this->assertEquals($orderItemCount - 2, $orderItemClass::find()->count()); - $this->assertEquals(0, count($order->books)); - - // via model without delete - $this->assertEquals(2, count($order->booksWithNullFK)); - $orderItemCount = $orderItemsWithNullFKClass::find()->count(); - $this->assertEquals(5, $itemClass::find()->count()); - $order->unlinkAll('booksWithNullFK',false); - $this->afterSave(); - $this->assertEquals(0, count($order->booksWithNullFK)); - $this->assertEquals(2, $orderItemsWithNullFKClass::find()->where(['AND', ['item_id' => [1, 2]], ['order_id' => null]])->count()); - $this->assertEquals($orderItemCount, $orderItemsWithNullFKClass::find()->count()); - $this->assertEquals(5, $itemClass::find()->count()); - - // via table is covered in \yiiunit\framework\db\ActiveRecordTest::testUnlinkAllViaTable() - } - - public function testUnlinkAllAndConditionSetNull() - { - /* @var $this TestCase|ActiveRecordTestTrait */ - - /* @var $customerClass \yii\db\BaseActiveRecord */ - $customerClass = $this->getCustomerClass(); - /* @var $orderClass \yii\db\BaseActiveRecord */ - $orderClass = $this->getOrderWithNullFKClass(); - - // in this test all orders are owned by customer 1 - $orderClass::updateAll(['customer_id' => 1]); - $this->afterSave(); - - $customer = $customerClass::findOne(1); - $this->assertEquals(3, count($customer->ordersWithNullFK)); - $this->assertEquals(1, count($customer->expensiveOrdersWithNullFK)); - $this->assertEquals(3, $orderClass::find()->count()); - $customer->unlinkAll('expensiveOrdersWithNullFK'); - $this->assertEquals(3, count($customer->ordersWithNullFK)); - $this->assertEquals(0, count($customer->expensiveOrdersWithNullFK)); - $this->assertEquals(3, $orderClass::find()->count()); - $customer = $customerClass::findOne(1); - $this->assertEquals(2, count($customer->ordersWithNullFK)); - $this->assertEquals(0, count($customer->expensiveOrdersWithNullFK)); - } - - public function testUnlinkAllAndConditionDelete() - { - /* @var $this TestCase|ActiveRecordTestTrait */ - - /* @var $customerClass \yii\db\BaseActiveRecord */ - $customerClass = $this->getCustomerClass(); - /* @var $orderClass \yii\db\BaseActiveRecord */ - $orderClass = $this->getOrderClass(); - - // in this test all orders are owned by customer 1 - $orderClass::updateAll(['customer_id' => 1]); - $this->afterSave(); - - $customer = $customerClass::findOne(1); - $this->assertEquals(3, count($customer->orders)); - $this->assertEquals(1, count($customer->expensiveOrders)); - $this->assertEquals(3, $orderClass::find()->count()); - $customer->unlinkAll('expensiveOrders', true); - $this->assertEquals(3, count($customer->orders)); - $this->assertEquals(0, count($customer->expensiveOrders)); - $this->assertEquals(2, $orderClass::find()->count()); - $customer = $customerClass::findOne(1); - $this->assertEquals(2, count($customer->orders)); - $this->assertEquals(0, count($customer->expensiveOrders)); - } - - public static $afterSaveNewRecord; - public static $afterSaveInsert; - - public function testInsert() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - $customer = new $customerClass; - $customer->email = 'user4@example.com'; - $customer->name = 'user4'; - $customer->address = 'address4'; - - $this->assertNull($customer->id); - $this->assertTrue($customer->isNewRecord); - static::$afterSaveNewRecord = null; - static::$afterSaveInsert = null; - - $customer->save(); - $this->afterSave(); - - $this->assertNotNull($customer->id); - $this->assertFalse(static::$afterSaveNewRecord); - $this->assertTrue(static::$afterSaveInsert); - $this->assertFalse($customer->isNewRecord); - } - - public function testUpdate() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - // save - /* @var $customer Customer */ - $customer = $customerClass::findOne(2); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals('user2', $customer->name); - $this->assertFalse($customer->isNewRecord); - static::$afterSaveNewRecord = null; - static::$afterSaveInsert = null; - $this->assertEmpty($customer->dirtyAttributes); - - $customer->name = 'user2x'; - $customer->save(); - $this->afterSave(); - $this->assertEquals('user2x', $customer->name); - $this->assertFalse($customer->isNewRecord); - $this->assertFalse(static::$afterSaveNewRecord); - $this->assertFalse(static::$afterSaveInsert); - $customer2 = $customerClass::findOne(2); - $this->assertEquals('user2x', $customer2->name); - - // updateAll - $customer = $customerClass::findOne(3); - $this->assertEquals('user3', $customer->name); - $ret = $customerClass::updateAll(['name' => 'temp'], ['id' => 3]); - $this->afterSave(); - $this->assertEquals(1, $ret); - $customer = $customerClass::findOne(3); - $this->assertEquals('temp', $customer->name); - - $ret = $customerClass::updateAll(['name' => 'tempX']); - $this->afterSave(); - $this->assertEquals(3, $ret); - - $ret = $customerClass::updateAll(['name' => 'temp'], ['name' => 'user6']); - $this->afterSave(); - $this->assertEquals(0, $ret); - } - - public function testUpdateAttributes() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - /* @var $customer Customer */ - $customer = $customerClass::findOne(2); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals('user2', $customer->name); - $this->assertFalse($customer->isNewRecord); - static::$afterSaveNewRecord = null; - static::$afterSaveInsert = null; - - $customer->updateAttributes(['name' => 'user2x']); - $this->afterSave(); - $this->assertEquals('user2x', $customer->name); - $this->assertFalse($customer->isNewRecord); - $this->assertNull(static::$afterSaveNewRecord); - $this->assertNull(static::$afterSaveInsert); - $customer2 = $customerClass::findOne(2); - $this->assertEquals('user2x', $customer2->name); - - $customer = $customerClass::findOne(1); - $this->assertEquals('user1', $customer->name); - $this->assertEquals(1, $customer->status); - $customer->name = 'user1x'; - $customer->status = 2; - $customer->updateAttributes(['name']); - $this->assertEquals('user1x', $customer->name); - $this->assertEquals(2, $customer->status); - $customer = $customerClass::findOne(1); - $this->assertEquals('user1x', $customer->name); - $this->assertEquals(1, $customer->status); - } - - public function testUpdateCounters() - { - /* @var $orderItemClass \yii\db\ActiveRecordInterface */ - $orderItemClass = $this->getOrderItemClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - // updateCounters - $pk = ['order_id' => 2, 'item_id' => 4]; - $orderItem = $orderItemClass::findOne($pk); - $this->assertEquals(1, $orderItem->quantity); - $ret = $orderItem->updateCounters(['quantity' => -1]); - $this->afterSave(); - $this->assertEquals(1, $ret); - $this->assertEquals(0, $orderItem->quantity); - $orderItem = $orderItemClass::findOne($pk); - $this->assertEquals(0, $orderItem->quantity); - - // updateAllCounters - $pk = ['order_id' => 1, 'item_id' => 2]; - $orderItem = $orderItemClass::findOne($pk); - $this->assertEquals(2, $orderItem->quantity); - $ret = $orderItemClass::updateAllCounters([ - 'quantity' => 3, - 'subtotal' => -10, - ], $pk); - $this->afterSave(); - $this->assertEquals(1, $ret); - $orderItem = $orderItemClass::findOne($pk); - $this->assertEquals(5, $orderItem->quantity); - $this->assertEquals(30, $orderItem->subtotal); - } - - public function testDelete() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - // delete - $customer = $customerClass::findOne(2); - $this->assertTrue($customer instanceof $customerClass); - $this->assertEquals('user2', $customer->name); - $customer->delete(); - $this->afterSave(); - $customer = $customerClass::findOne(2); - $this->assertNull($customer); - - // deleteAll - $customers = $customerClass::find()->all(); - $this->assertEquals(2, count($customers)); - $ret = $customerClass::deleteAll(); - $this->afterSave(); - $this->assertEquals(2, $ret); - $customers = $customerClass::find()->all(); - $this->assertEquals(0, count($customers)); - - $ret = $customerClass::deleteAll(); - $this->afterSave(); - $this->assertEquals(0, $ret); - } - - /** - * Some PDO implementations(e.g. cubrid) do not support boolean values. - * Make sure this does not affect AR layer. - */ - public function testBooleanAttribute() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - $customer = new $customerClass(); - $customer->name = 'boolean customer'; - $customer->email = 'mail@example.com'; - $customer->status = true; - $customer->save(false); - - $customer->refresh(); - $this->assertEquals(1, $customer->status); - - $customer->status = false; - $customer->save(false); - - $customer->refresh(); - $this->assertEquals(0, $customer->status); - - $customers = $customerClass::find()->where(['status' => true])->all(); - $this->assertEquals(2, count($customers)); - - $customers = $customerClass::find()->where(['status' => false])->all(); - $this->assertEquals(1, count($customers)); - } - - public function testAfterFind() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $orderClass BaseActiveRecord */ - $orderClass = $this->getOrderClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - - $afterFindCalls = []; - Event::on(BaseActiveRecord::className(), BaseActiveRecord::EVENT_AFTER_FIND, function ($event) use (&$afterFindCalls) { - /* @var $ar BaseActiveRecord */ - $ar = $event->sender; - $afterFindCalls[] = [get_class($ar), $ar->getIsNewRecord(), $ar->getPrimaryKey(), $ar->isRelationPopulated('orders')]; - }); - - $customer = $customerClass::findOne(1); - $this->assertNotNull($customer); - $this->assertEquals([[$customerClass, false, 1, false]], $afterFindCalls); - $afterFindCalls = []; - - $customer = $customerClass::find()->where(['id' => 1])->one(); - $this->assertNotNull($customer); - $this->assertEquals([[$customerClass, false, 1, false]], $afterFindCalls); - $afterFindCalls = []; - - $customer = $customerClass::find()->where(['id' => 1])->all(); - $this->assertNotNull($customer); - $this->assertEquals([[$customerClass, false, 1, false]], $afterFindCalls); - $afterFindCalls = []; - - $customer = $customerClass::find()->where(['id' => 1])->with('orders')->all(); - $this->assertNotNull($customer); - $this->assertEquals([ - [$this->getOrderClass(), false, 1, false], - [$customerClass, false, 1, true], - ], $afterFindCalls); - $afterFindCalls = []; - - if ($this instanceof \yiiunit\extensions\redis\ActiveRecordTest) { // TODO redis does not support orderBy() yet - $customer = $customerClass::find()->where(['id' => [1, 2]])->with('orders')->all(); - } else { - // orderBy is needed to avoid random test failure - $customer = $customerClass::find()->where(['id' => [1, 2]])->with('orders')->orderBy('name')->all(); - } - $this->assertNotNull($customer); - $this->assertEquals([ - [$orderClass, false, 1, false], - [$orderClass, false, 2, false], - [$orderClass, false, 3, false], - [$customerClass, false, 1, true], - [$customerClass, false, 2, true], - ], $afterFindCalls); - $afterFindCalls = []; - - Event::off(BaseActiveRecord::className(), BaseActiveRecord::EVENT_AFTER_FIND); - } - - public function testFindEmptyInCondition() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - - $customers = $customerClass::find()->where(['id' => [1]])->all(); - $this->assertEquals(1, count($customers)); - - $customers = $customerClass::find()->where(['id' => []])->all(); - $this->assertEquals(0, count($customers)); - - $customers = $customerClass::find()->where(['IN', 'id', [1]])->all(); - $this->assertEquals(1, count($customers)); - - $customers = $customerClass::find()->where(['IN', 'id', []])->all(); - $this->assertEquals(0, count($customers)); - } - - public function testFindEagerIndexBy() - { - /* @var $this TestCase|ActiveRecordTestTrait */ - - /* @var $orderClass \yii\db\ActiveRecordInterface */ - $orderClass = $this->getOrderClass(); - - /* @var $order Order */ - $order = $orderClass::find()->with('itemsIndexed')->where(['id' => 1])->one(); - $this->assertTrue($order->isRelationPopulated('itemsIndexed')); - $items = $order->itemsIndexed; - $this->assertEquals(2, count($items)); - $this->assertTrue(isset($items[1])); - $this->assertTrue(isset($items[2])); - - /* @var $order Order */ - $order = $orderClass::find()->with('itemsIndexed')->where(['id' => 2])->one(); - $this->assertTrue($order->isRelationPopulated('itemsIndexed')); - $items = $order->itemsIndexed; - $this->assertEquals(3, count($items)); - $this->assertTrue(isset($items[3])); - $this->assertTrue(isset($items[4])); - $this->assertTrue(isset($items[5])); - } -} diff --git a/tests/unit/framework/base/ActionFilterTest.php b/tests/unit/framework/base/ActionFilterTest.php deleted file mode 100644 index 01820cc..0000000 --- a/tests/unit/framework/base/ActionFilterTest.php +++ /dev/null @@ -1,164 +0,0 @@ -mockApplication(); - } - - public function testFilter() - { - // no filters - $controller = new FakeController('fake', Yii::$app); - $this->assertNull($controller->result); - $result = $controller->runAction('test'); - $this->assertEquals('x', $result); - $this->assertNull($controller->result); - - // all filters pass - $controller = new FakeController('fake', Yii::$app, [ - 'behaviors' => [ - 'filter1' => Filter1::className(), - 'filter3' => Filter3::className(), - ], - ]); - $this->assertNull($controller->result); - $result = $controller->runAction('test'); - $this->assertEquals('x-3-1', $result); - $this->assertEquals([1, 3], $controller->result); - - // a filter stops in the middle - $controller = new FakeController('fake', Yii::$app, [ - 'behaviors' => [ - 'filter1' => Filter1::className(), - 'filter2' => Filter2::className(), - 'filter3' => Filter3::className(), - ], - ]); - $this->assertNull($controller->result); - $result = $controller->runAction('test'); - $this->assertNull($result); - $this->assertEquals([1, 2], $controller->result); - - // the first filter stops - $controller = new FakeController('fake', Yii::$app, [ - 'behaviors' => [ - 'filter2' => Filter2::className(), - 'filter1' => Filter1::className(), - 'filter3' => Filter3::className(), - ], - ]); - $this->assertNull($controller->result); - $result = $controller->runAction('test'); - $this->assertNull($result); - $this->assertEquals([2], $controller->result); - - // the last filter stops - $controller = new FakeController('fake', Yii::$app, [ - 'behaviors' => [ - 'filter1' => Filter1::className(), - 'filter3' => Filter3::className(), - 'filter2' => Filter2::className(), - ], - ]); - $this->assertNull($controller->result); - $result = $controller->runAction('test'); - $this->assertNull($result); - $this->assertEquals([1, 3, 2], $controller->result); - } -} - -class FakeController extends Controller -{ - public $result; - public $behaviors = []; - - public function behaviors() - { - return $this->behaviors; - } - - public function actionTest() - { - return 'x'; - } -} - -class Filter1 extends ActionFilter -{ - /** - * @inheritdoc - */ - public function beforeAction($action) - { - $action->controller->result[] = 1; - return true; - } - - /** - * @inheritdoc - */ - public function afterAction($action, $result) - { - return $result . '-1'; - } -} - -class Filter2 extends ActionFilter -{ - /** - * @inheritdoc - */ - public function beforeAction($action) - { - $action->controller->result[] = 2; - return false; - } - - /** - * @inheritdoc - */ - public function afterAction($action, $result) - { - return $result . '-2'; - } -} - -class Filter3 extends ActionFilter -{ - /** - * @inheritdoc - */ - public function beforeAction($action) - { - $action->controller->result[] = 3; - return true; - } - - /** - * @inheritdoc - */ - public function afterAction($action, $result) - { - return $result . '-3'; - } -} - diff --git a/tests/unit/framework/base/BehaviorTest.php b/tests/unit/framework/base/BehaviorTest.php deleted file mode 100644 index 9a950f6..0000000 --- a/tests/unit/framework/base/BehaviorTest.php +++ /dev/null @@ -1,107 +0,0 @@ - __NAMESPACE__ . '\BarBehavior', - ]; - } -} - -class BarBehavior extends Behavior -{ - public $behaviorProperty = 'behavior property'; - - public function behaviorMethod() - { - return 'behavior method'; - } - - public function __call($name, $params) - { - if ($name == 'magicBehaviorMethod') { - return 'Magic Behavior Method Result!'; - } - - return parent::__call($name, $params); - } - - public function hasMethod($name) - { - if ($name == 'magicBehaviorMethod') { - return true; - } - - return parent::hasMethod($name); - } -} - -/** - * @group base - */ -class BehaviorTest extends TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - public function testAttachAndAccessing() - { - $bar = new BarClass(); - $behavior = new BarBehavior(); - $bar->attachBehavior('bar', $behavior); - $this->assertEquals('behavior property', $bar->behaviorProperty); - $this->assertEquals('behavior method', $bar->behaviorMethod()); - $this->assertEquals('behavior property', $bar->getBehavior('bar')->behaviorProperty); - $this->assertEquals('behavior method', $bar->getBehavior('bar')->behaviorMethod()); - - $behavior = new BarBehavior(['behaviorProperty' => 'reattached']); - $bar->attachBehavior('bar', $behavior); - $this->assertEquals('reattached', $bar->behaviorProperty); - } - - public function testAutomaticAttach() - { - $foo = new FooClass(); - $this->assertEquals('behavior property', $foo->behaviorProperty); - $this->assertEquals('behavior method', $foo->behaviorMethod()); - } - - public function testMagicMethods() - { - $bar = new BarClass(); - $behavior = new BarBehavior(); - - $this->assertFalse($bar->hasMethod('magicBehaviorMethod')); - $bar->attachBehavior('bar', $behavior); - $this->assertFalse($bar->hasMethod('magicBehaviorMethod', false)); - $this->assertTrue($bar->hasMethod('magicBehaviorMethod')); - - $this->assertEquals('Magic Behavior Method Result!', $bar->magicBehaviorMethod()); - } - - public function testCallUnknownMethod() - { - $bar = new BarClass(); - $behavior = new BarBehavior(); - $this->setExpectedException('yii\base\UnknownMethodException'); - - $this->assertFalse($bar->hasMethod('nomagicBehaviorMethod')); - $bar->attachBehavior('bar', $behavior); - $bar->nomagicBehaviorMethod(); - } -} diff --git a/tests/unit/framework/base/ComponentTest.php b/tests/unit/framework/base/ComponentTest.php deleted file mode 100644 index e95d387..0000000 --- a/tests/unit/framework/base/ComponentTest.php +++ /dev/null @@ -1,451 +0,0 @@ -sender->eventHandled = true; -} - -function globalEventHandler2($event) -{ - $event->sender->eventHandled = true; - $event->handled = true; -} - -/** - * @group base - */ -class ComponentTest extends TestCase -{ - /** - * @var NewComponent - */ - protected $component; - - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - $this->component = new NewComponent(); - } - - protected function tearDown() - { - parent::tearDown(); - $this->component = null; - } - - public function testClone() - { - $component = new NewComponent(); - $behavior = new NewBehavior(); - $component->attachBehavior('a', $behavior); - $this->assertSame($behavior, $component->getBehavior('a')); - $component->on('test', 'fake'); - $this->assertTrue($component->hasEventHandlers('test')); - - $clone = clone $component; - $this->assertNotSame($component, $clone); - $this->assertNull($clone->getBehavior('a')); - $this->assertFalse($clone->hasEventHandlers('test')); - } - - public function testHasProperty() - { - $this->assertTrue($this->component->hasProperty('Text')); - $this->assertTrue($this->component->hasProperty('text')); - $this->assertFalse($this->component->hasProperty('Caption')); - $this->assertTrue($this->component->hasProperty('content')); - $this->assertFalse($this->component->hasProperty('content', false)); - $this->assertFalse($this->component->hasProperty('Content')); - } - - public function testCanGetProperty() - { - $this->assertTrue($this->component->canGetProperty('Text')); - $this->assertTrue($this->component->canGetProperty('text')); - $this->assertFalse($this->component->canGetProperty('Caption')); - $this->assertTrue($this->component->canGetProperty('content')); - $this->assertFalse($this->component->canGetProperty('content', false)); - $this->assertFalse($this->component->canGetProperty('Content')); - } - - public function testCanSetProperty() - { - $this->assertTrue($this->component->canSetProperty('Text')); - $this->assertTrue($this->component->canSetProperty('text')); - $this->assertFalse($this->component->canSetProperty('Object')); - $this->assertFalse($this->component->canSetProperty('Caption')); - $this->assertTrue($this->component->canSetProperty('content')); - $this->assertFalse($this->component->canSetProperty('content', false)); - $this->assertFalse($this->component->canSetProperty('Content')); - - // behavior - $this->assertFalse($this->component->canSetProperty('p2')); - $behavior = new NewBehavior(); - $this->component->attachBehavior('a', $behavior); - $this->assertTrue($this->component->canSetProperty('p2')); - $this->component->detachBehavior('a'); - } - - public function testGetProperty() - { - $this->assertTrue('default' === $this->component->Text); - $this->setExpectedException('yii\base\UnknownPropertyException'); - $value2 = $this->component->Caption; - } - - public function testSetProperty() - { - $value = 'new value'; - $this->component->Text = $value; - $this->assertEquals($value, $this->component->Text); - $this->setExpectedException('yii\base\UnknownPropertyException'); - $this->component->NewMember = $value; - } - - public function testIsset() - { - $this->assertTrue(isset($this->component->Text)); - $this->assertFalse(empty($this->component->Text)); - - $this->component->Text = ''; - $this->assertTrue(isset($this->component->Text)); - $this->assertTrue(empty($this->component->Text)); - - $this->component->Text = null; - $this->assertFalse(isset($this->component->Text)); - $this->assertTrue(empty($this->component->Text)); - - $this->assertFalse(isset($this->component->p2)); - $this->component->attachBehavior('a', new NewBehavior()); - $this->component->setP2('test'); - $this->assertTrue(isset($this->component->p2)); - } - - public function testCallUnknownMethod() - { - $this->setExpectedException('yii\base\UnknownMethodException'); - $this->component->unknownMethod(); - } - - public function testUnset() - { - unset($this->component->Text); - $this->assertFalse(isset($this->component->Text)); - $this->assertTrue(empty($this->component->Text)); - - $this->component->attachBehavior('a', new NewBehavior()); - $this->component->setP2('test'); - $this->assertEquals('test', $this->component->getP2()); - - unset($this->component->p2); - $this->assertNull($this->component->getP2()); - } - - public function testUnsetReadonly() - { - $this->setExpectedException('yii\base\InvalidCallException'); - unset($this->component->object); - } - - public function testOn() - { - $this->assertFalse($this->component->hasEventHandlers('click')); - $this->component->on('click', 'foo'); - $this->assertTrue($this->component->hasEventHandlers('click')); - - $this->assertFalse($this->component->hasEventHandlers('click2')); - $p = 'on click2'; - $this->component->$p = 'foo2'; - $this->assertTrue($this->component->hasEventHandlers('click2')); - } - - public function testOff() - { - $this->assertFalse($this->component->hasEventHandlers('click')); - $this->component->on('click', 'foo'); - $this->assertTrue($this->component->hasEventHandlers('click')); - $this->component->off('click', 'foo'); - $this->assertFalse($this->component->hasEventHandlers('click')); - - $this->component->on('click2', 'foo'); - $this->component->on('click2', 'foo2'); - $this->component->on('click2', 'foo3'); - $this->assertTrue($this->component->hasEventHandlers('click2')); - $this->component->off('click2', 'foo3'); - $this->assertTrue($this->component->hasEventHandlers('click2')); - $this->component->off('click2'); - $this->assertFalse($this->component->hasEventHandlers('click2')); - } - - public function testTrigger() - { - $this->component->on('click', [$this->component, 'myEventHandler']); - $this->assertFalse($this->component->eventHandled); - $this->assertNull($this->component->event); - $this->component->raiseEvent(); - $this->assertTrue($this->component->eventHandled); - $this->assertEquals('click', $this->component->event->name); - $this->assertEquals($this->component, $this->component->event->sender); - $this->assertFalse($this->component->event->handled); - - $eventRaised = false; - $this->component->on('click', function ($event) use (&$eventRaised) { - $eventRaised = true; - }); - $this->component->raiseEvent(); - $this->assertTrue($eventRaised); - - // raise event w/o parameters - $eventRaised = false; - $this->component->on('test', function ($event) use (&$eventRaised) { - $eventRaised = true; - }); - $this->component->trigger('test'); - $this->assertTrue($eventRaised); - } - - public function testHasEventHandlers() - { - $this->assertFalse($this->component->hasEventHandlers('click')); - $this->component->on('click', 'foo'); - $this->assertTrue($this->component->hasEventHandlers('click')); - } - - public function testStopEvent() - { - $component = new NewComponent; - $component->on('click', 'yiiunit\framework\base\globalEventHandler2'); - $component->on('click', [$this->component, 'myEventHandler']); - $component->raiseEvent(); - $this->assertTrue($component->eventHandled); - $this->assertFalse($this->component->eventHandled); - } - - public function testAttachBehavior() - { - $component = new NewComponent; - $this->assertFalse($component->hasProperty('p')); - $this->assertFalse($component->behaviorCalled); - $this->assertNull($component->getBehavior('a')); - - $behavior = new NewBehavior; - $component->attachBehavior('a', $behavior); - $this->assertSame($behavior, $component->getBehavior('a')); - $this->assertTrue($component->hasProperty('p')); - $component->test(); - $this->assertTrue($component->behaviorCalled); - - $this->assertSame($behavior, $component->detachBehavior('a')); - $this->assertFalse($component->hasProperty('p')); - $this->setExpectedException('yii\base\UnknownMethodException'); - $component->test(); - - $p = 'as b'; - $component = new NewComponent; - $component->$p = ['class' => 'NewBehavior']; - $this->assertSame($behavior, $component->getBehavior('a')); - $this->assertTrue($component->hasProperty('p')); - $component->test(); - $this->assertTrue($component->behaviorCalled); - } - - public function testAttachBehaviors() - { - $component = new NewComponent; - $this->assertNull($component->getBehavior('a')); - $this->assertNull($component->getBehavior('b')); - - $behavior = new NewBehavior; - - $component->attachBehaviors([ - 'a' => $behavior, - 'b' => $behavior, - ]); - - $this->assertSame(['a' => $behavior, 'b' => $behavior], $component->getBehaviors()); - } - - public function testDetachBehavior() - { - $component = new NewComponent; - $behavior = new NewBehavior; - - $component->attachBehavior('a', $behavior); - $this->assertSame($behavior, $component->getBehavior('a')); - - $detachedBehavior = $component->detachBehavior('a'); - $this->assertSame($detachedBehavior, $behavior); - $this->assertNull($component->getBehavior('a')); - - $detachedBehavior = $component->detachBehavior('z'); - $this->assertNull($detachedBehavior); - } - - public function testDetachBehaviors() - { - $component = new NewComponent; - $behavior = new NewBehavior; - - $component->attachBehavior('a', $behavior); - $this->assertSame($behavior, $component->getBehavior('a')); - $component->attachBehavior('b', $behavior); - $this->assertSame($behavior, $component->getBehavior('b')); - - $component->detachBehaviors(); - $this->assertNull($component->getBehavior('a')); - $this->assertNull($component->getBehavior('b')); - } - - public function testSetReadOnlyProperty() - { - $this->setExpectedException( - '\yii\base\InvalidCallException', - 'Setting read-only property: yiiunit\framework\base\NewComponent::object' - ); - $this->component->object = 'z'; - } - - public function testSetPropertyOfBehavior() - { - $this->assertNull($this->component->getBehavior('a')); - - $behavior = new NewBehavior; - $this->component->attachBehaviors([ - 'a' => $behavior, - ]); - $this->component->p = 'Yii is cool.'; - - $this->assertSame('Yii is cool.', $this->component->getBehavior('a')->p); - } - - public function testSettingBehaviorWithSetter() - { - $behaviorName = 'foo'; - $this->assertNull($this->component->getBehavior($behaviorName)); - $p = 'as ' . $behaviorName; - $this->component->$p = __NAMESPACE__ . '\NewBehavior'; - $this->assertSame(__NAMESPACE__ . '\NewBehavior', get_class($this->component->getBehavior($behaviorName))); - } - - public function testWriteOnlyProperty() - { - $this->setExpectedException( - '\yii\base\InvalidCallException', - 'Getting write-only property: yiiunit\framework\base\NewComponent::writeOnly' - ); - $this->component->writeOnly; - } - - public function testSuccessfulMethodCheck() - { - $this->assertTrue($this->component->hasMethod('hasProperty')); - } - - public function testTurningOffNonExistingBehavior() - { - $this->assertFalse($this->component->hasEventHandlers('foo')); - $this->assertFalse($this->component->off('foo')); - } -} - -class NewComponent extends Component -{ - private $_object = null; - private $_text = 'default'; - private $_items = []; - public $content; - - public function getText() - { - return $this->_text; - } - - public function setText($value) - { - $this->_text = $value; - } - - public function getObject() - { - if (!$this->_object) { - $this->_object = new self; - $this->_object->_text = 'object text'; - } - - return $this->_object; - } - - public function getExecute() - { - return function ($param) { - return $param * 2; - }; - } - - public function getItems() - { - return $this->_items; - } - - public $eventHandled = false; - public $event; - public $behaviorCalled = false; - - public function myEventHandler($event) - { - $this->eventHandled = true; - $this->event = $event; - } - - public function raiseEvent() - { - $this->trigger('click', new Event); - } - - public function setWriteOnly() - { - } -} - -class NewBehavior extends Behavior -{ - public $p; - private $p2; - - public function getP2() - { - return $this->p2; - } - - public function setP2($value) - { - $this->p2 = $value; - } - - public function test() - { - $this->owner->behaviorCalled = true; - - return 2; - } -} - -class NewComponent2 extends Component -{ - public $a; - public $b; - public $c; - - public function __construct($b, $c) - { - $this->b = $b; - $this->c = $c; - } -} diff --git a/tests/unit/framework/base/DynamicModelTest.php b/tests/unit/framework/base/DynamicModelTest.php deleted file mode 100644 index 534f372..0000000 --- a/tests/unit/framework/base/DynamicModelTest.php +++ /dev/null @@ -1,80 +0,0 @@ - - * @since 2.0 - */ -class DynamicModelTest extends TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - public function testValidateData() - { - $email = 'invalid'; - $name = 'long name'; - $age = ''; - $model = DynamicModel::validateData(compact('name', 'email', 'age'), [ - [['email', 'name', 'age'], 'required'], - ['email', 'email'], - ['name', 'string', 'max' => 3], - ]); - $this->assertTrue($model->hasErrors()); - $this->assertTrue($model->hasErrors('email')); - $this->assertTrue($model->hasErrors('name')); - $this->assertTrue($model->hasErrors('age')); - } - - public function testAddRule() - { - $model = new DynamicModel(); - $this->assertEquals(0, $model->getValidators()->count()); - $model->addRule('name', 'string', ['min' => 12]); - $this->assertEquals(1, $model->getValidators()->count()); - $model->addRule('email', 'email'); - $this->assertEquals(2, $model->getValidators()->count()); - $model->addRule(['name', 'email'], 'required'); - $this->assertEquals(3, $model->getValidators()->count()); - } - - public function testValidateWithAddRule() - { - $email = 'invalid'; - $name = 'long name'; - $age = ''; - $model = new DynamicModel(compact('name', 'email', 'age')); - $model->addRule(['email', 'name', 'age'], 'required') - ->addRule('email', 'email') - ->addRule('name', 'string', ['max' => 3]) - ->validate(); - $this->assertTrue($model->hasErrors()); - $this->assertTrue($model->hasErrors('email')); - $this->assertTrue($model->hasErrors('name')); - $this->assertTrue($model->hasErrors('age')); - } - - public function testDynamicProperty() - { - $email = 'invalid'; - $name = 'long name'; - $model = new DynamicModel(compact('name', 'email')); - $this->assertEquals($email, $model->email); - $this->assertEquals($name, $model->name); - $this->setExpectedException('yii\base\UnknownPropertyException'); - $age = $model->age; - } -} diff --git a/tests/unit/framework/base/EventTest.php b/tests/unit/framework/base/EventTest.php deleted file mode 100644 index 8fda502..0000000 --- a/tests/unit/framework/base/EventTest.php +++ /dev/null @@ -1,92 +0,0 @@ - - * @since 2.0 - */ -class EventTest extends TestCase -{ - public $counter; - - public function setUp() - { - $this->counter = 0; - Event::off(ActiveRecord::className(), 'save'); - Event::off(Post::className(), 'save'); - Event::off(User::className(), 'save'); - } - - public function testOn() - { - Event::on(Post::className(), 'save', function ($event) { - $this->counter += 1; - }); - Event::on(ActiveRecord::className(), 'save', function ($event) { - $this->counter += 3; - }); - $this->assertEquals(0, $this->counter); - $post = new Post; - $post->save(); - $this->assertEquals(4, $this->counter); - $user = new User; - $user->save(); - $this->assertEquals(7, $this->counter); - } - - public function testOff() - { - $handler = function ($event) { - $this->counter ++; - }; - $this->assertFalse(Event::hasHandlers(Post::className(), 'save')); - Event::on(Post::className(), 'save', $handler); - $this->assertTrue(Event::hasHandlers(Post::className(), 'save')); - Event::off(Post::className(), 'save', $handler); - $this->assertFalse(Event::hasHandlers(Post::className(), 'save')); - } - - public function testHasHandlers() - { - $this->assertFalse(Event::hasHandlers(Post::className(), 'save')); - $this->assertFalse(Event::hasHandlers(ActiveRecord::className(), 'save')); - Event::on(Post::className(), 'save', function ($event) { - $this->counter += 1; - }); - $this->assertTrue(Event::hasHandlers(Post::className(), 'save')); - $this->assertFalse(Event::hasHandlers(ActiveRecord::className(), 'save')); - - $this->assertFalse(Event::hasHandlers(User::className(), 'save')); - Event::on(ActiveRecord::className(), 'save', function ($event) { - $this->counter += 1; - }); - $this->assertTrue(Event::hasHandlers(User::className(), 'save')); - $this->assertTrue(Event::hasHandlers(ActiveRecord::className(), 'save')); - } -} - -class ActiveRecord extends Component -{ - public function save() - { - $this->trigger('save'); - } -} - -class Post extends ActiveRecord -{ -} - -class User extends ActiveRecord -{ -} diff --git a/tests/unit/framework/base/ExposedSecurity.php b/tests/unit/framework/base/ExposedSecurity.php deleted file mode 100644 index 431e123..0000000 --- a/tests/unit/framework/base/ExposedSecurity.php +++ /dev/null @@ -1,27 +0,0 @@ -mockApplication(); - } - - public function testGetAttributeLabel() - { - $speaker = new Speaker(); - $this->assertEquals('First Name', $speaker->getAttributeLabel('firstName')); - $this->assertEquals('This is the custom label', $speaker->getAttributeLabel('customLabel')); - $this->assertEquals('Underscore Style', $speaker->getAttributeLabel('underscore_style')); - } - - public function testGetAttributes() - { - $speaker = new Speaker(); - $speaker->firstName = 'Qiang'; - $speaker->lastName = 'Xue'; - - $this->assertEquals([ - 'firstName' => 'Qiang', - 'lastName' => 'Xue', - 'customLabel' => null, - 'underscore_style' => null, - ], $speaker->getAttributes()); - - $this->assertEquals([ - 'firstName' => 'Qiang', - 'lastName' => 'Xue', - ], $speaker->getAttributes(['firstName', 'lastName'])); - - $this->assertEquals([ - 'firstName' => 'Qiang', - 'lastName' => 'Xue', - ], $speaker->getAttributes(null, ['customLabel', 'underscore_style'])); - - $this->assertEquals([ - 'firstName' => 'Qiang', - ], $speaker->getAttributes(['firstName', 'lastName'], ['lastName', 'customLabel', 'underscore_style'])); - } - - public function testSetAttributes() - { - // by default mass assignment doesn't work at all - $speaker = new Speaker(); - $speaker->setAttributes(['firstName' => 'Qiang', 'underscore_style' => 'test']); - $this->assertNull($speaker->firstName); - $this->assertNull($speaker->underscore_style); - - // in the test scenario - $speaker = new Speaker(); - $speaker->setScenario('test'); - $speaker->setAttributes(['firstName' => 'Qiang', 'underscore_style' => 'test']); - $this->assertNull($speaker->underscore_style); - $this->assertEquals('Qiang', $speaker->firstName); - - $speaker->setAttributes(['firstName' => 'Qiang', 'underscore_style' => 'test'], false); - $this->assertEquals('test', $speaker->underscore_style); - $this->assertEquals('Qiang', $speaker->firstName); - } - - public function testLoad() - { - $singer = new Singer(); - $this->assertEquals('Singer', $singer->formName()); - - $post = ['firstName' => 'Qiang']; - - Speaker::$formName = ''; - $model = new Speaker(); - $model->setScenario('test'); - $this->assertTrue($model->load($post)); - $this->assertEquals('Qiang', $model->firstName); - - Speaker::$formName = 'Speaker'; - $model = new Speaker(); - $model->setScenario('test'); - $this->assertTrue($model->load(['Speaker' => $post])); - $this->assertEquals('Qiang', $model->firstName); - - Speaker::$formName = 'Speaker'; - $model = new Speaker(); - $model->setScenario('test'); - $this->assertFalse($model->load(['Example' => []])); - $this->assertEquals('', $model->firstName); - } - - public function testActiveAttributes() - { - // by default mass assignment doesn't work at all - $speaker = new Speaker(); - $this->assertEmpty($speaker->activeAttributes()); - - $speaker = new Speaker(); - $speaker->setScenario('test'); - $this->assertEquals(['firstName', 'lastName', 'underscore_style'], $speaker->activeAttributes()); - } - - public function testIsAttributeSafe() - { - // by default mass assignment doesn't work at all - $speaker = new Speaker(); - $this->assertFalse($speaker->isAttributeSafe('firstName')); - - $speaker = new Speaker(); - $speaker->setScenario('test'); - $this->assertTrue($speaker->isAttributeSafe('firstName')); - - } - - public function testErrors() - { - $speaker = new Speaker(); - - $this->assertEmpty($speaker->getErrors()); - $this->assertEmpty($speaker->getErrors('firstName')); - $this->assertEmpty($speaker->getFirstErrors()); - - $this->assertFalse($speaker->hasErrors()); - $this->assertFalse($speaker->hasErrors('firstName')); - - $speaker->addError('firstName', 'Something is wrong!'); - $this->assertEquals(['firstName' => ['Something is wrong!']], $speaker->getErrors()); - $this->assertEquals(['Something is wrong!'], $speaker->getErrors('firstName')); - - $speaker->addError('firstName', 'Totally wrong!'); - $this->assertEquals(['firstName' => ['Something is wrong!', 'Totally wrong!']], $speaker->getErrors()); - $this->assertEquals(['Something is wrong!', 'Totally wrong!'], $speaker->getErrors('firstName')); - - $this->assertTrue($speaker->hasErrors()); - $this->assertTrue($speaker->hasErrors('firstName')); - $this->assertFalse($speaker->hasErrors('lastName')); - - $this->assertEquals(['firstName' => 'Something is wrong!'], $speaker->getFirstErrors()); - $this->assertEquals('Something is wrong!', $speaker->getFirstError('firstName')); - $this->assertNull($speaker->getFirstError('lastName')); - - $speaker->addError('lastName', 'Another one!'); - $this->assertEquals([ - 'firstName' => [ - 'Something is wrong!', - 'Totally wrong!', - ], - 'lastName' => ['Another one!'], - ], $speaker->getErrors()); - - $speaker->clearErrors('firstName'); - $this->assertEquals([ - 'lastName' => ['Another one!'], - ], $speaker->getErrors()); - - $speaker->clearErrors(); - $this->assertEmpty($speaker->getErrors()); - $this->assertFalse($speaker->hasErrors()); - } - - public function testAddErrors() - { - $singer = new Singer(); - - $errors = ['firstName' => ['Something is wrong!']]; - $singer->addErrors($errors); - $this->assertEquals($singer->getErrors(), $errors); - - $singer->clearErrors(); - $singer->addErrors(['firstName' => 'Something is wrong!']); - $this->assertEquals($singer->getErrors(), ['firstName' => ['Something is wrong!']]); - - $singer->clearErrors(); - $errors = ['firstName' => ['Something is wrong!', 'Totally wrong!']]; - $singer->addErrors($errors); - $this->assertEquals($singer->getErrors(), $errors); - - $singer->clearErrors(); - $errors = [ - 'firstName' => ['Something is wrong!'], - 'lastName' => ['Another one!'] - ]; - $singer->addErrors($errors); - $this->assertEquals($singer->getErrors(), $errors); - - $singer->clearErrors(); - $errors = [ - 'firstName' => ['Something is wrong!', 'Totally wrong!'], - 'lastName' => ['Another one!'] - ]; - $singer->addErrors($errors); - $this->assertEquals($singer->getErrors(), $errors); - - $singer->clearErrors(); - $errors = [ - 'firstName' => ['Something is wrong!', 'Totally wrong!'], - 'lastName' => ['Another one!', 'Totally wrong!'] - ]; - $singer->addErrors($errors); - $this->assertEquals($singer->getErrors(), $errors); - } - - public function testArraySyntax() - { - $speaker = new Speaker(); - - // get - $this->assertNull($speaker['firstName']); - - // isset - $this->assertFalse(isset($speaker['firstName'])); - - // set - $speaker['firstName'] = 'Qiang'; - - $this->assertEquals('Qiang', $speaker['firstName']); - $this->assertTrue(isset($speaker['firstName'])); - - // iteration - $attributes = []; - foreach ($speaker as $key => $attribute) { - $attributes[$key] = $attribute; - } - $this->assertEquals([ - 'firstName' => 'Qiang', - 'lastName' => null, - 'customLabel' => null, - 'underscore_style' => null, - ], $attributes); - - // unset - unset($speaker['firstName']); - - // exception isn't expected here - $this->assertNull($speaker['firstName']); - $this->assertFalse(isset($speaker['firstName'])); - } - - public function testDefaults() - { - $singer = new Model(); - $this->assertEquals([], $singer->rules()); - $this->assertEquals([], $singer->attributeLabels()); - } - - public function testDefaultScenarios() - { - $singer = new Singer(); - $this->assertEquals(['default' => ['lastName', 'underscore_style', 'test']], $singer->scenarios()); - - $scenarios = [ - 'default' => ['id', 'name', 'description'], - 'administration' => ['name', 'description', 'is_disabled'], - ]; - $model = new ComplexModel1(); - $this->assertEquals($scenarios, $model->scenarios()); - $scenarios = [ - 'default' => ['id', 'name', 'description'], - 'suddenlyUnexpectedScenario' => ['name', 'description'], - 'administration' => ['id', 'name', 'description', 'is_disabled'], - ]; - $model = new ComplexModel2(); - $this->assertEquals($scenarios, $model->scenarios()); - } - - public function testIsAttributeRequired() - { - $singer = new Singer(); - $this->assertFalse($singer->isAttributeRequired('firstName')); - $this->assertTrue($singer->isAttributeRequired('lastName')); - - // attribute is not marked as required when a conditional validation is applied using `$when`. - // the condition should not be applied because this info may be retrieved before model is loaded with data - $singer->firstName = 'qiang'; - $this->assertFalse($singer->isAttributeRequired('test')); - $singer->firstName = 'cebe'; - $this->assertFalse($singer->isAttributeRequired('test')); - } - - public function testCreateValidators() - { - $this->setExpectedException('yii\base\InvalidConfigException', 'Invalid validation rule: a rule must specify both attribute names and validator type.'); - - $invalid = new InvalidRulesModel(); - $invalid->createValidators(); - } -} - -class ComplexModel1 extends Model -{ - public function rules() - { - return [ - [['id'], 'required', 'except' => 'administration'], - [['name', 'description'], 'filter', 'filter' => 'trim'], - [['is_disabled'], 'boolean', 'on' => 'administration'], - ]; - } -} - -class ComplexModel2 extends Model -{ - public function rules() - { - return [ - [['id'], 'required', 'except' => 'suddenlyUnexpectedScenario'], - [['name', 'description'], 'filter', 'filter' => 'trim'], - [['is_disabled'], 'boolean', 'on' => 'administration'], - ]; - } -} diff --git a/tests/unit/framework/base/ObjectTest.php b/tests/unit/framework/base/ObjectTest.php deleted file mode 100644 index 06968f0..0000000 --- a/tests/unit/framework/base/ObjectTest.php +++ /dev/null @@ -1,200 +0,0 @@ -mockApplication(); - $this->object = new NewObject; - } - - protected function tearDown() - { - parent::tearDown(); - $this->object = null; - } - - public function testHasProperty() - { - $this->assertTrue($this->object->hasProperty('Text')); - $this->assertTrue($this->object->hasProperty('text')); - $this->assertFalse($this->object->hasProperty('Caption')); - $this->assertTrue($this->object->hasProperty('content')); - $this->assertFalse($this->object->hasProperty('content', false)); - $this->assertFalse($this->object->hasProperty('Content')); - } - - public function testCanGetProperty() - { - $this->assertTrue($this->object->canGetProperty('Text')); - $this->assertTrue($this->object->canGetProperty('text')); - $this->assertFalse($this->object->canGetProperty('Caption')); - $this->assertTrue($this->object->canGetProperty('content')); - $this->assertFalse($this->object->canGetProperty('content', false)); - $this->assertFalse($this->object->canGetProperty('Content')); - } - - public function testCanSetProperty() - { - $this->assertTrue($this->object->canSetProperty('Text')); - $this->assertTrue($this->object->canSetProperty('text')); - $this->assertFalse($this->object->canSetProperty('Object')); - $this->assertFalse($this->object->canSetProperty('Caption')); - $this->assertTrue($this->object->canSetProperty('content')); - $this->assertFalse($this->object->canSetProperty('content', false)); - $this->assertFalse($this->object->canSetProperty('Content')); - } - - public function testGetProperty() - { - $this->assertTrue('default' === $this->object->Text); - $this->setExpectedException('yii\base\UnknownPropertyException'); - $value2 = $this->object->Caption; - } - - public function testSetProperty() - { - $value = 'new value'; - $this->object->Text = $value; - $this->assertEquals($value, $this->object->Text); - $this->setExpectedException('yii\base\UnknownPropertyException'); - $this->object->NewMember = $value; - } - - public function testSetReadOnlyProperty() - { - $this->setExpectedException('yii\base\InvalidCallException'); - $this->object->object = 'test'; - } - - public function testIsset() - { - $this->assertTrue(isset($this->object->Text)); - $this->assertFalse(empty($this->object->Text)); - - $this->object->Text = ''; - $this->assertTrue(isset($this->object->Text)); - $this->assertTrue(empty($this->object->Text)); - - $this->object->Text = null; - $this->assertFalse(isset($this->object->Text)); - $this->assertTrue(empty($this->object->Text)); - - $this->assertFalse(isset($this->object->unknownProperty)); - $this->assertTrue(empty($this->object->unknownProperty)); - } - - public function testUnset() - { - unset($this->object->Text); - $this->assertFalse(isset($this->object->Text)); - $this->assertTrue(empty($this->object->Text)); - } - - public function testUnsetReadOnlyProperty() - { - $this->setExpectedException('yii\base\InvalidCallException'); - unset($this->object->object); - } - - public function testCallUnknownMethod() - { - $this->setExpectedException('yii\base\UnknownMethodException'); - $this->object->unknownMethod(); - } - - public function testArrayProperty() - { - $this->assertEquals([], $this->object->items); - // the following won't work - /* - $this->object->items[] = 1; - $this->assertEquals([1], $this->object->items); - */ - } - - public function testObjectProperty() - { - $this->assertTrue($this->object->object instanceof NewObject); - $this->assertEquals('object text', $this->object->object->text); - $this->object->object->text = 'new text'; - $this->assertEquals('new text', $this->object->object->text); - } - - public function testConstruct() - { - $object = new NewObject(['text' => 'test text']); - $this->assertEquals('test text', $object->getText()); - } - - public function testGetClassName() - { - $object = $this->object; - $this->assertSame(get_class($object), $object::className()); - } - - public function testReadingWriteOnlyProperty() - { - $this->setExpectedException( - 'yii\base\InvalidCallException', - 'Getting write-only property: yiiunit\framework\base\NewObject::writeOnly' - ); - $this->object->writeOnly; - } -} - - -class NewObject extends Object -{ - private $_object = null; - private $_text = 'default'; - private $_items = []; - public $content; - - public function getText() - { - return $this->_text; - } - - public function setText($value) - { - $this->_text = $value; - } - - public function getObject() - { - if (!$this->_object) { - $this->_object = new self; - $this->_object->_text = 'object text'; - } - - return $this->_object; - } - - public function getExecute() - { - return function ($param) { - return $param * 2; - }; - } - - public function getItems() - { - return $this->_items; - } - - public function setWriteOnly() {} -} diff --git a/tests/unit/framework/base/SecurityTest.php b/tests/unit/framework/base/SecurityTest.php deleted file mode 100644 index 5af2830..0000000 --- a/tests/unit/framework/base/SecurityTest.php +++ /dev/null @@ -1,1062 +0,0 @@ -security = new ExposedSecurity(); - $this->security->derivationIterations = 1000; // speed up test running - } - - // Tests : - - public function testHashData() - { - $data = 'known data'; - $key = 'secret'; - $hashedData = $this->security->hashData($data, $key); - $this->assertFalse($data === $hashedData); - $this->assertEquals($data, $this->security->validateData($hashedData, $key)); - $hashedData[strlen($hashedData) - 1] = 'A'; - $this->assertFalse($this->security->validateData($hashedData, $key)); - } - - /** - * Data provider for [[testPasswordHash()]] - * @return array test data - */ - public function dataProviderPasswordHash() - { - return [ - [ - 'crypt', - false - ], - [ - 'password_hash', - !function_exists('password_hash') - ], - ]; - } - - /** - * @dataProvider dataProviderPasswordHash - * - * @param string $passwordHashStrategy - * @param boolean $isSkipped - */ - public function testPasswordHash($passwordHashStrategy, $isSkipped) - { - if ($isSkipped) { - $this->markTestSkipped("Unable to test '{$passwordHashStrategy}' password hash strategy"); - return; - } - $this->security->passwordHashStrategy = $passwordHashStrategy; - - $password = 'secret'; - $hash = $this->security->generatePasswordHash($password); - $this->assertTrue($this->security->validatePassword($password, $hash)); - $this->assertFalse($this->security->validatePassword('test', $hash)); - } - - public function testEncryptByPassword() - { - $data = 'known data'; - $key = 'secret'; - - $encryptedData = $this->security->encryptByPassword($data, $key); - $this->assertFalse($data === $encryptedData); - $decryptedData = $this->security->decryptByPassword($encryptedData, $key); - $this->assertEquals($data, $decryptedData); - - $tampered = $encryptedData; - $tampered[20] = ~$tampered[20]; - $decryptedData = $this->security->decryptByPassword($tampered, $key); - $this->assertTrue(false === $decryptedData); - } - - public function testEncryptByKey() - { - $data = 'known data'; - $key = $this->security->generateRandomKey(80); - - $encryptedData = $this->security->encryptByKey($data, $key); - $this->assertFalse($data === $encryptedData); - $decryptedData = $this->security->decryptByKey($encryptedData, $key); - $this->assertEquals($data, $decryptedData); - - $encryptedData = $this->security->encryptByKey($data, $key, $key); - $decryptedData = $this->security->decryptByKey($encryptedData, $key, $key); - $this->assertEquals($data, $decryptedData); - - $tampered = $encryptedData; - $tampered[20] = ~$tampered[20]; - $decryptedData = $this->security->decryptByKey($tampered, $key); - $this->assertTrue(false === $decryptedData); - - $decryptedData = $this->security->decryptByKey($encryptedData, $key, $key . "\0"); - $this->assertTrue(false === $decryptedData); - } - - /** - * Generates test vectors like this: - * [key/password, plaintext, ciphertext] - * The output can then be used for testing compatibility of data encrypted in one - * version of Yii and decrypted in another - */ - public function notestGenerateVectors() - { - $bin1024 = - 'badec0c7d9ca734e161a1df6ca4daa8cdbf6b3bbb60ec404b47a23226ec266b1 - 3837ffc969e9c23e2bbba72facb491a6a3271193a35026a9ebc93698d689bf7b - 84fc384f544cc5d71c2945c8c48ae6348c753322fcaf75171b7d8f1e178e8545 - 3d5c79f03bae6d9705cabbe7004ec81e188812a66313297fcf5d4c61a48614d2 - 1b5379fae60736f88bc737257bc1cfbef7016108dd1f3a537aaa681544f5bb20 - c2d352212d6a2e460311ab7b93b611218b30c7402709bff89ecf814310c2db97 - 81f4142a54d6d41f82c33208c188a023c70befd697b496efb7c7b8569474a9d5 - 025a8ea8311c831b3de2b81800f28589b6aef537f6ada2e3d92a1ddd39cfd6b4 - 8113c8b36be890b099ca4e08655db0e9b5c211e706af052b776924233321412c - b1b540f08d88acd664c55854b05e31a15d4b0dc93b4514f62a88c3d4a451fe34 - 74d2fbaee742f232959b5f6c2b71a8b6ad95a0d5362f39309aca710f37a4dae2 - 228e27d35f4d3fc87ee6ece4538587fad7835f9803f5ca64dfd856ae767a3482 - c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c04 - 0f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed9273644463b - 1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334aa4 - d998a599053cd477f54fc0af62a8ef75eb91096b153751b201b8374c4956508c - 6c82ea2ceb0265e74c96032787fe01139b578c3a14fd4e32a85195375b25da60 - 4f21187ee01df6042971d7c2b9dd8b611527377f28f933559f6b2edfe7bd8896 - 00627830bcdffcb884989013585cc6da726c7cc57c69e8664a244d234465f2a5 - e736512a65e563a2a726915b50247aff165190c75d151139f2b31211a3acf94e - 236d27b441fe64e88a443778359d57ba0fed8edbb01cc60a116f9599da4e47bf - e96850ac12d1199a080f1b591c60eae613fba444f9fe31fd42ee333678532556 - 07fbfeef02cdbb2d0a8d2329adc7fba22aa4cd124c6e66e0b0aca796ba6aeb69 - f8e76a9d1aaabe351bc42fefa6054977859b51158ba7143980d76db5b2cc6aec - 9f83eac5edf79357632fb60cb4811e71892436e582375860faf8d8c518ee33ca - e08b18af7faa227d97196d7b041bcb366118751fbeaa92d80f86324ce8711cfd - 65005cad0ce30878f508eb1ea2735e212ef3e42a78467d4f31b483087c3c63a3 - 2fa62f2ae92e2acdfc3cf21b3419acc347ff51ccb17161e829cc4a24965fd930 - b983d63153b9c13dd85340d7184bf01734d4357c1aabfbdc9711193ffa974832 - 4f88cf801f35708db0901ffaa55415ca4334678633dda763b5fbfba7cfd51dc5 - 79149ec9284a4db2349dbc5264d5fca7a72034261716d90a996cb57ba09f7d07 - 29a2f10cc58eec98d86e9306a3fbf2e711046e86b5a86cc0eed7625be1a01ebf'; - $bin1024 = hex2bin(preg_replace('{\s+}', '', $bin1024)); - - $inputs = [ - '0', - '0123456789', - '0123456789abcde', - '0123456789abcdef', - '0123456789abcdef0', - mb_substr($bin1024, 7, 5, '8bit'), - base64_encode(mb_substr($bin1024, 269, 11, '8bit')), - mb_substr($bin1024, 383, 97, '8bit'), - $bin1024, - ]; - - foreach (['Key', 'Password'] as $method) { - $keygen = 'generateRandom' . ($method === 'Key' ? 'Key' : 'String'); - $encrypt = 'encryptBy' . $method; - $decrypt = 'decryptBy' . $method; - - foreach ($inputs as $data) { - $key = $this->security->$keygen(16); - $encrypted = $this->security->$encrypt($data, $key); - - $keyHex = $method === 'Key' ? bin2hex($key) : $key; - $dataHex = trim(chunk_split(bin2hex($data), 64, "\n\t")); - $encryptedHex = trim(chunk_split(bin2hex($encrypted), 64, "\n\t")); - - echo <<assertEquals($data, $this->security->$decrypt($encrypted2, $key2)); - $this->assertEquals($data2, $this->security->$decrypt($encrypted2, $key)); - } - } - } - - public function dataProviderEncryptByKeyCompat() - { - // these ciphertexts generated using Yii 2.0.2 which is based on mcrypt. - $mcrypt = [ - [ - 'b86b7529a525d148cc73798da528d8a0', - '30', - '4fb4765bea6beb208ba9395bf6d7497f37626463323730396362366338376536 - 3236656535613035373835323061343031613764393062353439623834353135 - 376435383635393065393636656663378807b00020ea10101bbfc2ef0dfee082 - fcbc1927daee7e6d061bc7a7c8d8e877', - ], - [ - '7e214bb6b27108918c007c0f9e1bdd8a', - '30313233343536373839', - '98981d39f0c985aca577e2eb9472059339623332343335646634613630616335 - 6133323639663336633533313032353164393562303434623533326331653561 - 6566346561643066643331393437623366e93fe0ef0a220ef1228be9f9195475 - eb303b841b6371841126c13ed419d931', - ], - [ - 'c139f67915206b7296bc6ab383a2786c', - '303132333435363738396162636465', - '5773028f2be0df720cb3be2cb989e9e161616430393538363437623862326264 - 6436336133643738333866353339393932326432356433306630663062613331 - 386666313033626661333065313031623d5e980deacb6369592c90e7afca6e6b - 06736654378cc93b2d238e6360969956', - ], - [ - '910c052157953194d552e3a3f0061ab7', - '30313233343536373839616263646566', - '3141c48cc0b73ee43d5cd9ae5c8a153f66343039333638396632653239623434 - 3162616664636331316238336265626536336231653764663732396638336138 - 34636438616265376138613539656164b004dd4ebddba049ae068936643dd475 - c07696b0cc173c2eb4c2d7bc3364845e6e3656b463b04e2271cb10824f1365ec', - ], - [ - '28d0ad09ce367ca8e0772bbeeea6c40d', - '3031323334353637383961626364656630', - '1f19013959a0985cf0235c4ff46a20c135626235633437383532343736613963 - 3765646334666263323832643438663361323266303264383337613736363133 - 666432373632343236313331656362354de2203149f8b4f348c06ea4e2eb94e5 - de4deaf1d198e14e7c448421002bdfa9ed979502d86750d70aebaa1c727ae79e', - ], - [ - 'b658ac4b9fa13c3c1d40699aba886b7b', - '4e161a1df6', - '154015ebb822a55869721a0b1c22497762653266663264333631373938653539 - 3465316466396535343966373738666663646232656163383733633739323334 - 316363623562353462363133623134643d118216985ac7e3f6888a95552b6a67 - 6ff70daf8dfb65b4d5f62a936b7f64d7', - ], - [ - 'baeb43072f20af0f85c6252aa9f0d472', - '5862447074634952357761764253733d', - 'beb6dcd0fb444cbf759a241bd0ea26e537336135333532656136653262303736 - 3061656635326136376230333132663839626431366265363565643064616362 - 39633830313066356330653466613232dd9cfe4f4495f34a971a25d881dd48a3 - 12093a6307a87e4544e217cf9d39dd536a5882d2b9867abefef5c1dad127447e', - ], - [ - 'd527f854e8f37c49c71b82c48d8b4775', - '82c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c - 040f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed927364446 - 3b1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334a - a4', - 'baa84c2c05b2ac8efd9fc8f9824efb5d63306366393939626532323532646433 - 6539346265383936336262303339336635333164383339326436376631353366 - 6433616639653638393063376137626574bd7aa8c5f313e2d8b7a4ca4af35090 - 9695845c9d62cd91c486307d3ae0701e4abd1fa69a255aab1e6ac2874fa1bc0a - 065340418a6669427bcdec751300ce7666a38d17d850f7dae4ea9567045356e8 - f347941226bf7b2d4dd3a21c8aa0b381f8ad06c3a55a7d2cb967ad148142c287 - f12a563f9cd2c6224e7efb8fdd130bb9', - ], - [ - '01025bfec21dda4342809cf20382de29', - 'badec0c7d9ca734e161a1df6ca4daa8cdbf6b3bbb60ec404b47a23226ec266b1 - 3837ffc969e9c23e2bbba72facb491a6a3271193a35026a9ebc93698d689bf7b - 84fc384f544cc5d71c2945c8c48ae6348c753322fcaf75171b7d8f1e178e8545 - 3d5c79f03bae6d9705cabbe7004ec81e188812a66313297fcf5d4c61a48614d2 - 1b5379fae60736f88bc737257bc1cfbef7016108dd1f3a537aaa681544f5bb20 - c2d352212d6a2e460311ab7b93b611218b30c7402709bff89ecf814310c2db97 - 81f4142a54d6d41f82c33208c188a023c70befd697b496efb7c7b8569474a9d5 - 025a8ea8311c831b3de2b81800f28589b6aef537f6ada2e3d92a1ddd39cfd6b4 - 8113c8b36be890b099ca4e08655db0e9b5c211e706af052b776924233321412c - b1b540f08d88acd664c55854b05e31a15d4b0dc93b4514f62a88c3d4a451fe34 - 74d2fbaee742f232959b5f6c2b71a8b6ad95a0d5362f39309aca710f37a4dae2 - 228e27d35f4d3fc87ee6ece4538587fad7835f9803f5ca64dfd856ae767a3482 - c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c04 - 0f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed9273644463b - 1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334aa4 - d998a599053cd477f54fc0af62a8ef75eb91096b153751b201b8374c4956508c - 6c82ea2ceb0265e74c96032787fe01139b578c3a14fd4e32a85195375b25da60 - 4f21187ee01df6042971d7c2b9dd8b611527377f28f933559f6b2edfe7bd8896 - 00627830bcdffcb884989013585cc6da726c7cc57c69e8664a244d234465f2a5 - e736512a65e563a2a726915b50247aff165190c75d151139f2b31211a3acf94e - 236d27b441fe64e88a443778359d57ba0fed8edbb01cc60a116f9599da4e47bf - e96850ac12d1199a080f1b591c60eae613fba444f9fe31fd42ee333678532556 - 07fbfeef02cdbb2d0a8d2329adc7fba22aa4cd124c6e66e0b0aca796ba6aeb69 - f8e76a9d1aaabe351bc42fefa6054977859b51158ba7143980d76db5b2cc6aec - 9f83eac5edf79357632fb60cb4811e71892436e582375860faf8d8c518ee33ca - e08b18af7faa227d97196d7b041bcb366118751fbeaa92d80f86324ce8711cfd - 65005cad0ce30878f508eb1ea2735e212ef3e42a78467d4f31b483087c3c63a3 - 2fa62f2ae92e2acdfc3cf21b3419acc347ff51ccb17161e829cc4a24965fd930 - b983d63153b9c13dd85340d7184bf01734d4357c1aabfbdc9711193ffa974832 - 4f88cf801f35708db0901ffaa55415ca4334678633dda763b5fbfba7cfd51dc5 - 79149ec9284a4db2349dbc5264d5fca7a72034261716d90a996cb57ba09f7d07 - 29a2f10cc58eec98d86e9306a3fbf2e711046e86b5a86cc0eed7625be1a01ebf', - '08ad33a166a9b39ba7522ccf5414123062643565356136373131666663323763 - 3636343466313761356339656234343064626331343366346432343062626634 - 3264393630336535353431613338653717747da97dd4d63e215dc8bb9ce231d5 - b3cc9c287dfadb1b5acce0d4da2816de16114665271204188d91b642cdfdb494 - 66a89caa29a9139354f69c4c188d76d88d36d14004268f327c98f4736ba31728 - a46d8f50d1665bcf157e3164d756286eceac4ce81ba3ffd1b79ff0862f5f529b - d44f0e2fbcb88c388095cb894fd4ce059ba8f5436f0a15b2fa9a40acd6645ad1 - c6f16365250715cb0552dcfc220e844ba67e2a1206b1725a6bbb8f0e87b7067f - b51fc0226cd963bddf549227d5eaf5f996061d9c3b7e3306bd9be1114aed6199 - 6e44ee1144bebfca9a1064d40419837e54006f54161dd028b2702faa5cde214c - bc11ed1c77d4042b333e772473f4764fcdfcabdd0319f33d96ad0ab904cd2620 - 31683afc4c96dc27fde0570aaedc922a552d46687a606bb579b6ab8050f418f8 - f6a3fc33ef5eeba8dbf54b5a90a1034ff8a68d9ea691d9a1d6b8f41376735bec - 6c0f541f927cf107f2184f96235a6fca6d1db013966d8527389f8a79f4afd7bb - 297c85d56f74faaa069679edc78b16b17ab8d72de3788f2ac2fe8a2e15ddfb3f - 14ffd9ef18c95acf340f702a974b580cac93928417650b8f9e7409619774e483 - af66b18ec7547f744099e2bb4125905e5dd553beca90d03fa7d7bba201ab97ac - 92506c305ff79afe9c99a73cb20b9048464beeb100df0ecfb40161f95dd8708a - 6fd09e1b166f1e27429b1ca50f990a45425dec25b2a29dcde4fd1c23b0d660ba - 10241bc20cdc59c3609a7d6b094538d56b878c62dca3a54fbc53d815ae0549f6 - 978ea37a644add2bd2720b37a3502d683b0a8b9ce269bb3db8a44f3e8c3ba507 - 7759de171e1d040dfe5c9a610e21e3b41d95403654122ed7b75111622f14bb50 - fd7a3e637bba73fc8c4e22702b52329c224860a9e04b38b8c23527c732a281dc - f92103d71decf673b3fa83feab2c1937811e0b41163019e1b45e664d4acc570c - 2d4b24dc138285478c3898b0567c026a1651bbada0fb62ab5ce0d96e3601aec1 - c6f04ecb1b53f1d852893edb971703dcd919c2dd883d0851e2fc491cf9abf1b7 - c1652bac73a5a9e9bdbf164db948cc5b8299fd7f5535fa927130dc4e183ef35e - bb08723625e4cf62f253111e6f016e6cfba2e9cec30e273e4b2dcefa80d1c528 - 82c91609acf5989eec18afbefc25c898763c50d2a5cc54250d2672a39758f948 - 1866c26d260bf774db05280697d2b1a95b0481afa2b80bb205186ac290bc3770 - b19a652dc2f5d6611363cd851d921edad36851d64f4cac6ff67299455e120cee - 65a0d9471d1c952d7e81ba5e67e0a8a41a9a68f50d88a2b62151b564ffc2e435 - 8373e55df6cad337589a89054c050f93b4b252aa65466029313bf7311ae735a5 - 26cd2bac41af846c069ed614485cf62bd66c939dfeb27ecaaa197aa344a5488b - b3a2dca884c7fdc4ac08816b2b5ba3b7414f7ff7a06a3a6fe75e20c9eb97a881 - ac130616f176d1f26ae24bf4392e0a0e', - ], - ]; - - // these ciphertexts generated using my branch 7215-replace-mcrypt which is based on openssl. - $openssl = [ - [ - '67ae7370e4a144523543f1e3edf35b26', - '30', - '706e1670ec6beb91c565299710e4f43231336530323838313435653933623539 - 3238313639623066323530646630653236313832333361346664623132393436 - 34326131663964636634366665306439e6142bf3d0e6a5952231d8bfabbacd83 - ff04c61400529385d63a4b8f8696982d', - ], - [ - '5d4bae62bea3c8f4c49dd1a38a4e1b2a', - '30313233343536373839', - '4c9a34e1977dd656fd3e18d4bc2b00c762353830326262373135396530643235 - 3332643937653632353331626532373336653761643866646233336365323233 - 30633138663034313665653038306161eb77ac98344a0bf946f98e892e6e15db - b9e221a7c25135a36562c3ecb2981fcd', - ], - [ - '6832851af3c63a1e303bdf1bca38dd9c', - '303132333435363738396162636465', - 'd09d2faa163e774abd020bf8cd623f8962646233313330626133613964353834 - 3436663631383139653438326563623537373830663962303531366130383130 - 3333303531613337386534626136636415db7a6885b67f69d9974f5879ae7497 - 08811fc036508f23f55f3f9d16b9ff9d', - ], - [ - 'e8a9799f4254b26484ea447918dcaad4', - '30313233343536373839616263646566', - '1a76a05af572abe9b4e7a67d7f64baff39666636363332323133373034386531 - 3761353236333263643965313139303666636535343862363737333032323331 - 313136366562336535663033316231303811542783f13798b17d40aa7ec9b489 - 34404ab50784ad1722f5f4d4462f702d3a625ef712635b274a970a47b516b137', - ], - [ - '27cbf5a7c4327582393b2ec277cfe957', - '3031323334353637383961626364656630', - '60e2e14b404c5bd55b192ef2f1c7131c32356261636361313131336265323534 - 3439623033346337346133346239363337633736663831343632626638303038 - 64653361396366356165633061666538d2137b2defca383668827b6983f86254 - bd849c3e8c9a44b6e1ed203491d73b4cb0cb83658240a89baa9261755d707879', - ], - [ - '7b157beb08e8a8ac7d74f789ccbacae5', - '4e161a1df6', - 'a17ca346c4a88404b8a345b1d075173a66356137326335343137393136353762 - 3930636535636466336534316438376437376639366535666636313235653262 - 38393464663134313430333633343232b319ce688676fde03d092d73df75705f - bde594d9b2bfe41580a458555982dc70', - ], - [ - '88704df5b4881d2246388dc7c68066cc', - '5862447074634952357761764253733d', - '9069fbdd47ee81faf34eff40f8fee94333393037333936333439653537636132 - 6561613863336165333336323562353161636330366438633264376461626563 - 3836363462646536323261333034643070e4b0a3d196f36a4afb92a7ae4ef7b8 - eb44e9db29638fa32140e379ae7aa6b7e68f454635ade137165383fd3a5c049b', - ], - [ - '1d203fba1cd2a7b92abb8f40eb985538', - '82c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c - 040f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed927364446 - 3b1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334a - a4', - 'fade5d841aa10a29a2ef5236371ffc2964343165383664636264393666383364 - 6165646139316438666531633230306537343364336166666463656466306564 - 63326239653938303332656464346463136bd6dd0b7530490b91024ed944bc3e - 3fc4050d20ce05a9ed992ede75f62bdd2523d0cbc93493baf07ef98c895a353b - 5baaf26200572aa2e5bd22508db227556c5ee9eb7425418e9852c595e6ac0e61 - 37c186e04a3f19d855d8c4b8a8e6ad1be179ea5c816fe461a4cec212297873c8 - 5f96ee5c024cd88d1c32975fd95acd73', - ], - [ - '1f93719d7a66a724c3841835fbcb33fd', - 'badec0c7d9ca734e161a1df6ca4daa8cdbf6b3bbb60ec404b47a23226ec266b1 - 3837ffc969e9c23e2bbba72facb491a6a3271193a35026a9ebc93698d689bf7b - 84fc384f544cc5d71c2945c8c48ae6348c753322fcaf75171b7d8f1e178e8545 - 3d5c79f03bae6d9705cabbe7004ec81e188812a66313297fcf5d4c61a48614d2 - 1b5379fae60736f88bc737257bc1cfbef7016108dd1f3a537aaa681544f5bb20 - c2d352212d6a2e460311ab7b93b611218b30c7402709bff89ecf814310c2db97 - 81f4142a54d6d41f82c33208c188a023c70befd697b496efb7c7b8569474a9d5 - 025a8ea8311c831b3de2b81800f28589b6aef537f6ada2e3d92a1ddd39cfd6b4 - 8113c8b36be890b099ca4e08655db0e9b5c211e706af052b776924233321412c - b1b540f08d88acd664c55854b05e31a15d4b0dc93b4514f62a88c3d4a451fe34 - 74d2fbaee742f232959b5f6c2b71a8b6ad95a0d5362f39309aca710f37a4dae2 - 228e27d35f4d3fc87ee6ece4538587fad7835f9803f5ca64dfd856ae767a3482 - c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c04 - 0f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed9273644463b - 1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334aa4 - d998a599053cd477f54fc0af62a8ef75eb91096b153751b201b8374c4956508c - 6c82ea2ceb0265e74c96032787fe01139b578c3a14fd4e32a85195375b25da60 - 4f21187ee01df6042971d7c2b9dd8b611527377f28f933559f6b2edfe7bd8896 - 00627830bcdffcb884989013585cc6da726c7cc57c69e8664a244d234465f2a5 - e736512a65e563a2a726915b50247aff165190c75d151139f2b31211a3acf94e - 236d27b441fe64e88a443778359d57ba0fed8edbb01cc60a116f9599da4e47bf - e96850ac12d1199a080f1b591c60eae613fba444f9fe31fd42ee333678532556 - 07fbfeef02cdbb2d0a8d2329adc7fba22aa4cd124c6e66e0b0aca796ba6aeb69 - f8e76a9d1aaabe351bc42fefa6054977859b51158ba7143980d76db5b2cc6aec - 9f83eac5edf79357632fb60cb4811e71892436e582375860faf8d8c518ee33ca - e08b18af7faa227d97196d7b041bcb366118751fbeaa92d80f86324ce8711cfd - 65005cad0ce30878f508eb1ea2735e212ef3e42a78467d4f31b483087c3c63a3 - 2fa62f2ae92e2acdfc3cf21b3419acc347ff51ccb17161e829cc4a24965fd930 - b983d63153b9c13dd85340d7184bf01734d4357c1aabfbdc9711193ffa974832 - 4f88cf801f35708db0901ffaa55415ca4334678633dda763b5fbfba7cfd51dc5 - 79149ec9284a4db2349dbc5264d5fca7a72034261716d90a996cb57ba09f7d07 - 29a2f10cc58eec98d86e9306a3fbf2e711046e86b5a86cc0eed7625be1a01ebf', - '712929635f5be013159aec81296b96ec36333734373565366166383031313734 - 3331623863663837343237633863376539643865643339383531363139396566 - 34313731633765393462663264316130de90698e64fa4abc91639e72baee83bc - 2caf85f91318e0cbd0db5fa08c4ffb582ec55ca43de53a43f2844af35d5f87b9 - 8faa623107aee2e083f1c7aeedcb0472c93bb9eacbd39d839d5bf94c44658d7f - d70817f5d6b120f91ef86880f93e99151bc1ed13ed263a3ccc7243e5ea97f39f - 1ce2ce6b05a2b78f05c5d72041e35466068f52fb3d2ba3afa7594d7bc0981c54 - 8b31ae7e5b7e7e0e6f2fac9a336e6516d7e4b5cc658e1fe634daf9ad097715be - 14d54ef19adc381db31db78714a09e997dc7732853d39885566e41a2c0ecb08d - ef8ab56359a0e312446d9f1555539ad29e13080d438d6817280d4dbfe6cd4ab9 - 4a357dbddcea1bc90e0d0fa6d556b1ba75c23a1d3818ea91e0fa5b8005b8020e - f7a80ed2ee60aa8ee588e101dbf3b64bf6a3dca5b1d5bcb96eed5c594bab1dcf - c1f61d74ad3ff0f5fdf176a327e8de33d123cdd61c6c4dc946429c566ac0f77f - 48215d5889365fa664a879babd4758fb4d824cfb9e4bf6500ffec0e4ebefe4f6 - 2e521a7cd563fc954a9161047461e4054f324c5cf4f9e949566c9ac17c45aac1 - abf98caed42242c51aa0d81d732c538e437c4024e8f04eeeab6619aed46599e7 - f66c2041e0c346affab1f79cd7352a66686fac2b38615f8fc172ab0967fd4435 - 9dea9f41b57ba5a752e20456f2254e8eef576867ebda0f48fe47a2e91fc8d8af - dc1bf98a8d3530b4b02996fe4b05ec3dab200f9e79a4261c233caa9a33762f1f - 4b3482ab6f16f5dbd7bd87ed17e21c30140ce61fc2468c054ce51dded2683d7c - 375d69d662729d6fb8629b8dc25dcc5596f87f627a2138a3ef368a2a1591902f - 84ffc457bd556a346815986f153fd3a99ef169444436ac81853b318c0908cb33 - cf332edadfb870cab419365312c18aeda418b8b571783a6b2d8c397c33a22b31 - 55958cef153f4d9cfc3a1c6288ff17bfdd92132e1f1e5fe8041e30a383084811 - fe892d7fc33abff10dd20db07277677b16e7f90137adfc3cb36dd85de3618769 - bf8f3ce13642f9ea430f455d388281208190b335915e256320274a904ecd0938 - d3c34d99c88e3186a132777fc7b74b43efab1a08376035061de56a4fb6de611c - 41d2139c77a516c4f8144b123696356b4b9a752a9cd857630af4ef02339172e6 - 361a2fd6a18e3baaf8a3f7e9811ad5fb61abba7ae893b1e7748df2c5b7704eb9 - 65606b0253cba6a0561b0e70593c724f99e07d3e9a857aef894a64a35969b354 - 4726d35504d7b8c0c06cbf9106c5d504674daa879b39328d2c83e0f4e5622ea1 - 4fb742458214b410e2736d8cefabfb125c4769701711c15ab870b5ff192d4c71 - e805ac5100352e33227b162ebae123e20c477719c52c59e192c2e3731806404d - d4359f840b11ad495357210e259e6b9e8fe5e8f600e8746fe1a483d45b694324 - 0809649ed7320b0022a5ef7b414635933d6d18ec7218f829121d12dcb573ed77 - 79ab0519d2df17dbd8988b32ac0711ef', - ], - ]; - - return static::CRYPT_VECTORS === 'new' ? $openssl : $mcrypt; - } - - /** - * @dataProvider dataProviderEncryptByKeyCompat - * - * @param string $key encryption key hex string - * @param string $data plaintext hex string - * @param string $encrypted ciphertext hex string - */ - public function testEncryptByKeyCompat($key, $data, $encrypted) - { - $key = hex2bin(preg_replace('{\s+}', '', $key)); - $data = hex2bin(preg_replace('{\s+}', '', $data)); - $encrypted = hex2bin(preg_replace('{\s+}', '', $encrypted)); - - $this->assertEquals($data, $this->security->decryptByKey($encrypted, $key)); - } - - public function dataProviderEncryptByPasswordCompat() - { - // these ciphertexts generated using Yii 2.0.2 which is based on mcrypt. - $mcrypt = [ - [ - 'LtogIEhy59ve0Huy', - '30', - '83325c8abe8dc0afd801acb7785dc29c32393439653930663266396466653862 - 3965303964653935326238343065363734346264633932376364376430653933 - 37303963376232336634306339396136e6f4e7dc3e2fd23be186f037e4caa6d0 - 4ae8cb894d80c08bb790417af9cc176f', - ], - [ - '1_VTumNNc7VV463t', - '30313233343536373839', - 'a247ac24f3aa60e894904f58954ce8bf39386530366165343538336132616231 - 6532353066663430646432383531333465373336646333386437323733633763 - 646665346232623635393962626162323a44a150a556addd97addfb43a32f600 - aa2c479664682a308e6cdd523967cb4a', - ], - [ - 'DBpoIPndKRm2Rfem', - '303132333435363738396162636465', - '9ed20f30824312032e5e34e2c5ab61e333313930616634396137623261363863 - 3334323832333664626265663435643633323033383862613865633961356261 - 30353634393536636465643833633531b62ce156f34b92790b2d26312f3fd7d0 - 0a646da4d636f6998f1b0d859f255dc6', - ], - [ - 's1e1oRE1iM_oortb', - '30313233343536373839616263646566', - '5b03427dba481b5af8760edc3788fa0e66666663623539353163346466663761 - 6434663337383566366265663931303662366530653633663235303532373763 - 37346330393537646630616535373230c98134da00d77753741c1f0bb483f109 - 622a889f950310cd51d7d48d63202b20d378eac85f7d0c851fc9905d322aef96', - ], - [ - 'i1E7JvOQaESAKoeH', - '3031323334353637383961626364656630', - '7cf2ed4612d07de3ecfd54ac0e576e8539613861656439333965623533626238 - 3361653764663438643330383130313462613961636462383836383862313962 - 346439313666343336313766366538637bd566b1eecb0b1e0896eb1fd0fd11d9 - dcb9eee5cc3d90c4046a6849e8ad152caf85e8f96de3b24b4d523a2d60533e0b', - ], - [ - 'QUN24gpNGodXurMM', - '4e161a1df6', - '49fc2d51b3e6325d86334ea8872699ef31613661333031373065373834643033 - 3863343734366435343035316562643438636133306233373431323066333330 - 32613330623364326162326434306637042f9b4a005ed3b9532181d020378800 - deefcfa36d77ed4abdf35546c0bb4aec', - ], - [ - '1COt9D8ZsfclCic2', - '5862447074634952357761764253733d', - 'c4d5f90054faf3699d983795f44bdb1430643734643832343265323064323434 - 6535346565323733323764376266646539366431353266666639386231626438 - 653237646165393461626435656332332b4244fccb47ad8cdea56109c7d5a417 - 13b3844d9857507db59d0000037b169f7b67cf0ea793c0254bffc55342d8e4c7', - ], - [ - 'eUqmv4chMnO1H5cq', - '82c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c - 040f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed927364446 - 3b1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334a - a4', - '31435e0bf8c0be9a395791288f6d058839336130623938343839626436636433 - 6664373131666361383739633163373130323936653730306331663836373263 - 656135303466323439326564626162378298df437dab821e8b2f7086962ffeb1 - 7a674022ee498470e5e8fdff8905aed39e424588ecee69965bb6856f0356860e - aa978ffa42ccfef6d4fb00026014e107736f3ee9b2206a2cd52b18e3068cf6aa - 077c7304128a3cd92d4fc29dfa7c180eaf85feec791618db1ed01695536cf8ec - 7923c0b3fb974fd0ff92faa62723e94f', - ], - [ - '3Cl5v2Lmn61PiQ3H', - 'badec0c7d9ca734e161a1df6ca4daa8cdbf6b3bbb60ec404b47a23226ec266b1 - 3837ffc969e9c23e2bbba72facb491a6a3271193a35026a9ebc93698d689bf7b - 84fc384f544cc5d71c2945c8c48ae6348c753322fcaf75171b7d8f1e178e8545 - 3d5c79f03bae6d9705cabbe7004ec81e188812a66313297fcf5d4c61a48614d2 - 1b5379fae60736f88bc737257bc1cfbef7016108dd1f3a537aaa681544f5bb20 - c2d352212d6a2e460311ab7b93b611218b30c7402709bff89ecf814310c2db97 - 81f4142a54d6d41f82c33208c188a023c70befd697b496efb7c7b8569474a9d5 - 025a8ea8311c831b3de2b81800f28589b6aef537f6ada2e3d92a1ddd39cfd6b4 - 8113c8b36be890b099ca4e08655db0e9b5c211e706af052b776924233321412c - b1b540f08d88acd664c55854b05e31a15d4b0dc93b4514f62a88c3d4a451fe34 - 74d2fbaee742f232959b5f6c2b71a8b6ad95a0d5362f39309aca710f37a4dae2 - 228e27d35f4d3fc87ee6ece4538587fad7835f9803f5ca64dfd856ae767a3482 - c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c04 - 0f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed9273644463b - 1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334aa4 - d998a599053cd477f54fc0af62a8ef75eb91096b153751b201b8374c4956508c - 6c82ea2ceb0265e74c96032787fe01139b578c3a14fd4e32a85195375b25da60 - 4f21187ee01df6042971d7c2b9dd8b611527377f28f933559f6b2edfe7bd8896 - 00627830bcdffcb884989013585cc6da726c7cc57c69e8664a244d234465f2a5 - e736512a65e563a2a726915b50247aff165190c75d151139f2b31211a3acf94e - 236d27b441fe64e88a443778359d57ba0fed8edbb01cc60a116f9599da4e47bf - e96850ac12d1199a080f1b591c60eae613fba444f9fe31fd42ee333678532556 - 07fbfeef02cdbb2d0a8d2329adc7fba22aa4cd124c6e66e0b0aca796ba6aeb69 - f8e76a9d1aaabe351bc42fefa6054977859b51158ba7143980d76db5b2cc6aec - 9f83eac5edf79357632fb60cb4811e71892436e582375860faf8d8c518ee33ca - e08b18af7faa227d97196d7b041bcb366118751fbeaa92d80f86324ce8711cfd - 65005cad0ce30878f508eb1ea2735e212ef3e42a78467d4f31b483087c3c63a3 - 2fa62f2ae92e2acdfc3cf21b3419acc347ff51ccb17161e829cc4a24965fd930 - b983d63153b9c13dd85340d7184bf01734d4357c1aabfbdc9711193ffa974832 - 4f88cf801f35708db0901ffaa55415ca4334678633dda763b5fbfba7cfd51dc5 - 79149ec9284a4db2349dbc5264d5fca7a72034261716d90a996cb57ba09f7d07 - 29a2f10cc58eec98d86e9306a3fbf2e711046e86b5a86cc0eed7625be1a01ebf', - '0c5164ead7f48c5d95f5907399c146a261353462323734323738656231323164 - 3962333166373062373734636630623932616638626236393339363861646366 - 35643933393537303331343436303330a927c7a879272f81e1032d57530b5e69 - 60f70e14b7607e8e17583aa8197f547e375e07b7a9d6c11be406f5e01aac59e2 - 7e54bb3c33662ea294cfbd0e7bb8e5eb886edee341509a752fc3b9706807a948 - 00edd0bff8e624275420bff50995de70d2692a052e1710a0b9135f9f44abcb02 - 24a189f1bb414e4d73fb539728d40b47ebc34fdb5ec2fa61848bb828de5179a1 - e799eb09367bda9b59b3bdc51d3f92c1bd7dacf751b9324059869bf6adc3d88d - 226a153a75cae1a2426ea187ef62c97bbd35e97450da87d4da9aed08ebf30a3c - a3369cc65a17acebb8a6ff8ff698743a3782990bc5e8cd03a6882c0f7c50868c - 6b3ce967c9ea317555eb972e9bb7beb7b3215160a0bcca8c7f92a085beca256e - 4484b1cdcaee495917d8aa4dbf7675806f7f57e77a770ea7db6e080150b43f56 - 15709b371a303e89b032eac7fec3ee954ea52940a2e59343fd0fd59ac2d4f095 - 74d2863eed13774c63a94e87f7ccdbf0741a56074a7210e2f022809ca48637d8 - 057d80fb190f339ddee2b6f7aaef3f2c1848026bd33e377ac554e2b29dede4fc - 11e040b3837c24e6cd93430c2f9c19138cd1b505681958a09f223f65e6d7b123 - 43e426e204ee32411b1590133d58fbc4806ff784db93cd0205a7b4a1f4b96ee4 - 02b06ac00520118c89a7c4f1dfb4ac941a3d6f839e9312ee8cd9c3c02ef5cf2a - 29d266fcfd29c24b994bcd3c67000999486bad6b060f87d5c843f3f132be5a7c - 6ab2aab2091a83f0673efc4bf658e6c181c800a2eab5272c9cc8e9bdcf4ee061 - de613989f107f1755385697ad64cd1c613f1f742a980c48e27638b8423b82eba - 555c59020ee5794099377e816e8983a7579fc97178e5ac0f98bdda6dbf3f38f1 - 3f8b2d12cc792e729468a8408482985ac73e831a6ca5f67176f68bf216b77147 - fe4743ae60f628defa590b0b0b7d8c39d24ef6980ffc0c47882fa0e3f04ed3e5 - 6d8654e11a0f25a2b3dd03e900e3d59922fa7ccd544f98a04828a34826fd9bfe - e8c841ca6146cc96443ab2cbed3f846f5241d27b15f81df80e2b35219044e933 - 4967334529fe949604a19f7cad76842a16928066a01fb9ec750e78ae68ddcb4f - 833b5e89377ea31c7c87666c300f36f7583383f783f979cedbd05585c50caade - 73f9f38dfcc5f915106573694ce497a0787ce3fecf9678a75b62f258aea300e8 - 2176e5c51009ea1fbdf266606cfb93cc62f9abd6c056625df053da8d9e175d63 - ca716f148365a41796889e6d24e6c9a6ee6ac57bf7c35b45d4000ec638d191e5 - 54fe6b031f87b82f6076e9672f7162de1dafedb9fed9d38adeb999c7fc46f801 - cd546342404315b06faff51d549b2eb94390d40a9ad826c1595add3f11afb909 - 16dc20173f13010008bc12a6355d582205897e7eb885f526a08bee072dabbb15 - 3b1777d8e7d96b31db8b64d64404ae82b3506f10ef198fad6321aa8cf04b5f54 - d5236014d4b5ce20fbfba77f090d3573', - ], - ]; - - // these ciphertexts generated using my branch 7215-replace-mcrypt which is based on openssl. - $openssl = [ - [ - '3DZsVH4gt5xBueho', - '30', - 'e19edc37d284b77a5a4600334b67317662393266323434393038666330653031 - 3730313664646137663830626366383363336239313664336637653133313933 - 306133613836363563643538396163642b6c12f20e7e1ae97422ee659914cc57 - e99c7c97c7a4957e78ab957b18be4551', - ], - [ - 'CVALyUpDdMOSaxJN', - '30313233343536373839', - 'a2535797ac0c83932fd9a2b8d6b2602662663439623337616631623434333233 - 3033343439313063656162373231666330333261383561356632393932386462 - 3631666364313236303962373636316296930828e0e154a0e8d262846835f242 - e42de861cba81df69fe6fe5a5970fdf7', - ], - [ - 'wBZcBIhNSFiaCWE8', - '303132333435363738396162636465', - 'd77b5d334d2820b5b5a54c5f71fce21130373832656561636661623564383766 - 6338343636626662346566623035333461653566353366656438303063376561 - 32643033343166376162376333373166c6cf828b68ff940e8de977e3471d1d51 - 2e51bab7ee0f976dd6d87727b508f7cf', - ], - [ - 'PYeAhK5nWPIxGD2F', - '30313233343536373839616263646566', - '0c2b35c26794c55b94228af98ba7378133326361353835323130363730333039 - 3531343463653763663366386462363733666537646466326339303439373730 - 64343038313234393232313362653639dbec4d9abb2dcffbf186366476df34d2 - 500744fd27eda1e0ea0e54280b091d32ebd1e786402507cb3c591503e27f195b', - ], - [ - 'B9u8Tl9tRBgmnSHk', - '3031323334353637383961626364656630', - '8401d45dbce698cf9342152c75cd8f5164356231643534643561646636316462 - 6331373265623831373165363336616165343432383161633962646333373932 - 3139323034393665303863356331363743e5873d38758489b9d5800aabf31f3e - cf36e1e47955f5c96acdf8dc6cc7280c825949d46546796ec5a114985f5fe598', - ], - [ - 'cLHX5BvVQcdlozS6', - '4e161a1df6', - 'e04aed1dc385788c3c777bc7b3cfa20c32656633363730393363366138643831 - 3866303330613461666664623039326437623739613236333566353762333461 - 34653132366163653031303134353161eefebead8d190e854c05f598adfb8d7b - ef30c86c7cc7003f261b8ce26c62da55', - ], - [ - 'r8EZMeBVex-LC3c5', - '5862447074634952357761764253733d', - 'ae03ee587e7df6407a17d43e3381b76563616366633165613463383063353930 - 6163613736656635663234613263323833393131363661333737333133356366 - 3963313236356663373035323264623224b4aa1536a8deba1dfa026efa614fb9 - 4915763a2629a00fe5ff8f1afc894f1b644f9b08ebc7baefc06229f177b5e446', - ], - [ - 'TRS5GvlQ2WCoEzHY', - '82c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c - 040f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed927364446 - 3b1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334a - a4', - 'f05611e02a2cccbfea4679e8110087a061396332303030396562663732626138 - 3530363534313362373731316330363964393564653831636566646261363265 - 38323536366666633438396566323939bce309f535fca3d1fb23e8503f8cf3b8 - bca4c4bcfb4021592268f88070b5203f5023a6a39034e34048bc944c22e037fd - e6ca8ca17e2bdc8169d1e714830de6932cfe0dcdd1728e8bf848a6f4f7154d1c - 0f8c650e0ef650ba3b90372eb6d13e93e3c79610291a523a3967a3049b04f1d4 - c899e1554b04f906c2e6408a16702d19', - ], - [ - 'x_a2LHnyqH8WAwkZ', - 'badec0c7d9ca734e161a1df6ca4daa8cdbf6b3bbb60ec404b47a23226ec266b1 - 3837ffc969e9c23e2bbba72facb491a6a3271193a35026a9ebc93698d689bf7b - 84fc384f544cc5d71c2945c8c48ae6348c753322fcaf75171b7d8f1e178e8545 - 3d5c79f03bae6d9705cabbe7004ec81e188812a66313297fcf5d4c61a48614d2 - 1b5379fae60736f88bc737257bc1cfbef7016108dd1f3a537aaa681544f5bb20 - c2d352212d6a2e460311ab7b93b611218b30c7402709bff89ecf814310c2db97 - 81f4142a54d6d41f82c33208c188a023c70befd697b496efb7c7b8569474a9d5 - 025a8ea8311c831b3de2b81800f28589b6aef537f6ada2e3d92a1ddd39cfd6b4 - 8113c8b36be890b099ca4e08655db0e9b5c211e706af052b776924233321412c - b1b540f08d88acd664c55854b05e31a15d4b0dc93b4514f62a88c3d4a451fe34 - 74d2fbaee742f232959b5f6c2b71a8b6ad95a0d5362f39309aca710f37a4dae2 - 228e27d35f4d3fc87ee6ece4538587fad7835f9803f5ca64dfd856ae767a3482 - c2f315c69f20ec7ae391fc6c2de85281d54c97f74981b4efec0f5e4606765c04 - 0f1f45386bed4fdb9f998b0e7027c7414bea667b1205027c55eed9273644463b - 1832bc5338e3a7e10bf24d8e69f167b94551b6240f65b416feebd28599334aa4 - d998a599053cd477f54fc0af62a8ef75eb91096b153751b201b8374c4956508c - 6c82ea2ceb0265e74c96032787fe01139b578c3a14fd4e32a85195375b25da60 - 4f21187ee01df6042971d7c2b9dd8b611527377f28f933559f6b2edfe7bd8896 - 00627830bcdffcb884989013585cc6da726c7cc57c69e8664a244d234465f2a5 - e736512a65e563a2a726915b50247aff165190c75d151139f2b31211a3acf94e - 236d27b441fe64e88a443778359d57ba0fed8edbb01cc60a116f9599da4e47bf - e96850ac12d1199a080f1b591c60eae613fba444f9fe31fd42ee333678532556 - 07fbfeef02cdbb2d0a8d2329adc7fba22aa4cd124c6e66e0b0aca796ba6aeb69 - f8e76a9d1aaabe351bc42fefa6054977859b51158ba7143980d76db5b2cc6aec - 9f83eac5edf79357632fb60cb4811e71892436e582375860faf8d8c518ee33ca - e08b18af7faa227d97196d7b041bcb366118751fbeaa92d80f86324ce8711cfd - 65005cad0ce30878f508eb1ea2735e212ef3e42a78467d4f31b483087c3c63a3 - 2fa62f2ae92e2acdfc3cf21b3419acc347ff51ccb17161e829cc4a24965fd930 - b983d63153b9c13dd85340d7184bf01734d4357c1aabfbdc9711193ffa974832 - 4f88cf801f35708db0901ffaa55415ca4334678633dda763b5fbfba7cfd51dc5 - 79149ec9284a4db2349dbc5264d5fca7a72034261716d90a996cb57ba09f7d07 - 29a2f10cc58eec98d86e9306a3fbf2e711046e86b5a86cc0eed7625be1a01ebf', - '5d841d0cb575fdb8c7e2cc48be47021d38646237366663323933346163643933 - 3861336335396666356139383066663033336333303731336263663262626136 - 643635333333393362306631333266320d73812258a45d90f8240d59c4e39e87 - 8d4d999f36403a6f0b1d69ab9416792c5e8f2cf427af8423c8213a885fde488c - db95217c64c542f5e2be6b4375ff82e5c72a9f165049546b38295006f50665b1 - 354350de4a68b5f16a18f7df53e0999f4f7ba5ba0676e416a0444d5b7accda8b - 093ae31a23e3cb63b6f404c437071435b8143f282c4cb4403a2b538af5a0d94f - 1e582c3bb9d5379ba5d576643854c232d74f303dcac91a711bf440fb24e7ab2a - 70ef69008ffb59ad2455d4f1482e77114489a3b5a250384b24062f546f86073a - 91fdd85d34bd7814b4ce70ec8d6ea34f98067d7101050f3800f9f1fd92003856 - 223f8ca142749c2ef4c8d1991a62b0ff86623bf9afce65d55fb5efe80089cee4 - e4f12e94e1748c5740f075a94a2290ba2dc892fdfde516ebc190a4db63e77f93 - 54a3bec5ef695572dddcc9d7c43609724c73bc5bfe79d5f322890e4f39a31e6b - 3fb9388c78e133c58e395ca03eca2e8ab9520e4d2e5421e0d9a1f781a564dda7 - 720d56f413312762da078e0226053672983ecf5bdf18086a6f617071814d61e4 - 27e6f02167b8d38e381607e4238f21c0b6e6d9222f1cc6348b9f7d6fb084cc3b - 306b7acbb94f4b3ab6b66fe539865fb804899d3f64c8bca6bd02ee5509022a50 - 03d63e259bb414391fc10ae9b2e42c68a2be743488b69ca77c70741820aaeeb0 - da2ff00c07787a39ec613e665d78c30b5f57a14fcbe24f00cf55eeb174e23dac - a9eb3587bc8dc8fdf5ef062b7f1659b45c48246055fda699b6ae8b9fcc46a380 - ebc6b648662ef5fed1a4fe16c9aa310cc16f5ad642b80549262f5c77335f5435 - a43d30459297b754350a9dd635b0ca5342fc798d369225f6d692eea0c901eb72 - fd10af1199b7847ffc1a0c5915902fe339772183727c31497c752e3beb1cf010 - 2c97ab270def6628bdae630172d73a9fc0afed1d893870003828f64518512886 - 57d62ba52c8d325aa8409b0a40754dc3f84d1c8898e01e20c03464b83d2dae5d - 3d9f279778fb1161ac5d8f9c466fd0c6bdd6a21553ea9252ff018ae99b0d4425 - 0e55d177fb1e0275da97474ea052d85d96b7432c1be840e5994b127b147d1a0c - 64f1cea9115a37225c8b49960e0693680ee5593c81784c850811e1f10ce4f9a3 - 365e3d2d240e0eef8da6404d5a93ebd000a98d5d33dd5a238327e88dfdad2744 - ed0c4321a543c1a3231e53550e816c531b73bafec21e32daeecd199c7a2be75f - 450ce4d39e10ad81a7ca74877e1661376d7cce557a1d4dde53b503e1512efef6 - d607d5074ca8ba29db067454e529aec867907c6eded03ce90835d72974cddcc5 - 83628bd2948a78a2d666ed89889f59b1dd5b05704b7e68a801ad9f93809e0d8a - ae72a72923883d4de81d867bf639eb5dc581429041ca78763235fe11251254c8 - cca8bfe10e8810035e4cce023b6527744d0ea839bb035db99adc3ce742a5491d - c446220a6cb416a0bd3362b424dcdf3e', - ], - ]; - - return static::CRYPT_VECTORS === 'new' ? $openssl : $mcrypt; - } - - /** - * @dataProvider dataProviderEncryptByPasswordCompat - * - * @param string $password encryption password - * @param string $data plaintext hex string - * @param string $encrypted ciphertext hex string - */ - public function testEncryptByPasswordCompat($password, $data, $encrypted) - { - $data = hex2bin(preg_replace('{\s+}', '', $data)); - $encrypted = hex2bin(preg_replace('{\s+}', '', $encrypted)); - - $this->assertEquals($data, $this->security->decryptByPassword($encrypted, $password)); - } - - public function testGenerateRandomKey() - { - $length = 21; - $key = $this->security->generateRandomKey($length); - $this->assertEquals($length, strlen($key)); - } - - public function testGenerateRandomString() - { - $length = 21; - $key = $this->security->generateRandomString($length); - $this->assertEquals($length, strlen($key)); - $this->assertEquals(1, preg_match('/[A-Za-z0-9_-]+/', $key)); - } - - public function dataProviderPbkdf2() - { - return [ - [ - 'sha1', - 'password', - 'salt', - 1, - 20, - '0c60c80f961f0e71f3a9b524af6012062fe037a6' - ], - [ - 'sha1', - 'password', - 'salt', - 2, - 20, - 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957' - ], - [ - 'sha1', - 'password', - 'salt', - 4096, - 20, - '4b007901b765489abead49d926f721d065a429c1' - ], - [ - 'sha1', - 'password', - 'salt', - 16777216, - 20, - 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984' - ], - [ - 'sha1', - 'passwordPASSWORDpassword', - 'saltSALTsaltSALTsaltSALTsaltSALTsalt', - 4096, - 25, - '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038' - ], - [ - 'sha1', - "pass\0word", - "sa\0lt", - 4096, - 16, - '56fa6aa75548099dcc37d7f03425e0c3' - ], - [ - 'sha256', - 'password', - 'salt', - 1, - 20, - '120fb6cffcf8b32c43e7225256c4f837a86548c9' - ], - [ - 'sha256', - "pass\0word", - "sa\0lt", - 4096, - 32, - '89b69d0516f829893c696226650a86878c029ac13ee276509d5ae58b6466a724' - ], - [ - 'sha256', - 'passwordPASSWORDpassword', - 'saltSALTsaltSALTsaltSALTsaltSALTsalt', - 4096, - 40, - '348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9' - ], - ]; - } - - /** - * @dataProvider dataProviderPbkdf2 - * - * @param string $hash - * @param string $password - * @param string $salt - * @param integer $iterations - * @param integer $length - * @param string $okm - */ - public function testPbkdf2($hash, $password, $salt, $iterations, $length, $okm) - { - $this->security->derivationIterations = $iterations; - $DK = $this->security->pbkdf2($hash, $password, $salt, $iterations, $length); - $this->assertEquals($okm, bin2hex($DK)); - } - - public function dataProviderDeriveKey() - { - // See Appendix A in https://tools.ietf.org/html/rfc5869 - return [ - [ - 'Hash' => 'sha256', - 'IKM' => '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', - 'salt' => '000102030405060708090a0b0c', - 'info' => 'f0f1f2f3f4f5f6f7f8f9', - 'L' => 42, - 'PRK' => '077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5', - 'OKM' => '3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865', - ], - [ - 'Hash' => 'sha256', - 'IKM' => '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f', - 'salt' => '606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf', - 'info' => 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', - 'L' => 82, - 'PRK' => '06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244', - 'OKM' => 'b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87', - ], - [ - 'Hash' => 'sha256', - 'IKM' => '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', - 'salt' => '', - 'info' => '', - 'L' => 42, - 'PRK' => '19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04', - 'OKM' => '8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8', - ], - [ - 'Hash' => 'sha1', - 'IKM' => '0b0b0b0b0b0b0b0b0b0b0b', - 'salt' => '000102030405060708090a0b0c', - 'info' => 'f0f1f2f3f4f5f6f7f8f9', - 'L' => 42, - 'PRK' => '9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243', - 'OKM' => '085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896', - ], - [ - 'Hash' => 'sha1', - 'IKM' => '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f', - 'salt' => '606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf', - 'info' => 'b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', - 'L' => 82, - 'PRK' => '8adae09a2a307059478d309b26c4115a224cfaf6', - 'OKM' => '0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4', - ], - [ - 'Hash' => 'sha1', - 'IKM' => '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', - 'salt' => '', - 'info' => '', - 'L' => 42, - 'PRK' => 'da8c8a73c7fa77288ec6f5e7c297786aa0d32d01', - 'OKM' => '0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918', - ], - [ - 'Hash' => 'sha1', - 'IKM' => '0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c', - 'salt' => null, - 'info' => '', - 'L' => 42, - 'PRK' => '2adccada18779e7c2077ad2eb19d3f3e731385dd', - 'OKM' => '2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48', - ] - ]; - } - - /** - * @dataProvider dataProviderDeriveKey - * - * @param string $hash - * @param string $ikm - * @param string $salt - * @param string $info - * @param integer $l - * @param string $prk - * @param string $okm - */ - public function testHkdf($hash, $ikm, $salt, $info, $l, $prk, $okm) - { - $dk = $this->security->hkdf($hash, hex2bin($ikm), hex2bin($salt), hex2bin($info), $l); - $this->assertEquals($okm, bin2hex($dk)); - } - - public function dataProviderCompareStrings() - { - return [ - ["", ""], - [false, ""], - [null, ""], - [0, ""], - [0.00, ""], - ["", null], - ["", false], - ["", 0], - ["", "\0"], - ["\0", ""], - ["\0", "\0"], - ["0", "\0"], - [0, "\0"], - ["user", "User"], - ["password", "password"], - ["password", "passwordpassword"], - ["password1", "password"], - ["password", "password2"], - ["", "password"], - ["password", ""], - ]; - } - - /** - * @dataProvider dataProviderCompareStrings - * - * @param $expected - * @param $actual - */ - public function testCompareStrings($expected, $actual) - { - $this->assertEquals(strcmp($expected, $actual) === 0, $this->security->compareString($expected, $actual)); - } -} diff --git a/tests/unit/framework/behaviors/SluggableBehaviorTest.php b/tests/unit/framework/behaviors/SluggableBehaviorTest.php deleted file mode 100644 index 3bd6b72..0000000 --- a/tests/unit/framework/behaviors/SluggableBehaviorTest.php +++ /dev/null @@ -1,193 +0,0 @@ -mockApplication([ - 'components' => [ - 'db' => [ - 'class' => '\yii\db\Connection', - 'dsn' => 'sqlite::memory:', - ] - ] - ]); - - $columns = [ - 'id' => 'pk', - 'name' => 'string', - 'slug' => 'string', - 'category_id' => 'integer', - ]; - Yii::$app->getDb()->createCommand()->createTable('test_slug', $columns)->execute(); - } - - public function tearDown() - { - Yii::$app->getDb()->close(); - parent::tearDown(); - } - - // Tests : - - public function testSlug() - { - $model = new ActiveRecordSluggable(); - $model->name = 'test name'; - $model->validate(); - - $this->assertEquals('test-name', $model->slug); - } - - /** - * @depends testSlug - */ - public function testSlugSeveralAttributes() - { - $model = new ActiveRecordSluggable(); - $model->getBehavior('sluggable')->attribute = array('name', 'category_id'); - - $model->name = 'test'; - $model->category_id = 10; - - $model->validate(); - $this->assertEquals('test-10', $model->slug); - } - - /** - * @depends testSlug - */ - public function testUniqueByIncrement() - { - $name = 'test name'; - - $model = new ActiveRecordSluggableUnique(); - $model->name = $name; - $model->save(); - - $model = new ActiveRecordSluggableUnique(); - $model->sluggable->uniqueSlugGenerator = 'increment'; - $model->name = $name; - $model->save(); - - $this->assertEquals('test-name-2', $model->slug); - } - - /** - * @depends testUniqueByIncrement - */ - public function testUniqueByCallback() - { - $name = 'test name'; - - $model = new ActiveRecordSluggableUnique(); - $model->name = $name; - $model->save(); - - $model = new ActiveRecordSluggableUnique(); - $model->sluggable->uniqueSlugGenerator = function($baseSlug, $iteration) {return $baseSlug . '-callback';}; - $model->name = $name; - $model->save(); - - $this->assertEquals('test-name-callback', $model->slug); - } - - /** - * @depends testSlug - */ - public function testUpdateUnique() - { - $name = 'test name'; - - $model = new ActiveRecordSluggableUnique(); - $model->name = $name; - $model->save(); - - $model->save(); - $this->assertEquals('test-name', $model->slug); - - $model = ActiveRecordSluggableUnique::find()->one(); - $model->save(); - $this->assertEquals('test-name', $model->slug); - - $model->name = 'test-name'; - $model->save(); - $this->assertEquals('test-name', $model->slug); - } -} - -/** - * Test Active Record class with [[SluggableBehavior]] behavior attached. - * - * @property integer $id - * @property string $name - * @property string $slug - * @property integer $category_id - * - * @property SluggableBehavior $sluggable - */ -class ActiveRecordSluggable extends ActiveRecord -{ - public function behaviors() - { - return [ - 'sluggable' => [ - 'class' => SluggableBehavior::className(), - 'attribute' => 'name', - ], - ]; - } - - public static function tableName() - { - return 'test_slug'; - } - - /** - * @return SluggableBehavior - */ - public function getSluggable() - { - return $this->getBehavior('sluggable'); - } -} - -class ActiveRecordSluggableUnique extends ActiveRecordSluggable -{ - public function behaviors() - { - return [ - 'sluggable' => [ - 'class' => SluggableBehavior::className(), - 'attribute' => 'name', - 'ensureUnique' => true, - ], - ]; - } -} \ No newline at end of file diff --git a/tests/unit/framework/behaviors/TimestampBehaviorTest.php b/tests/unit/framework/behaviors/TimestampBehaviorTest.php deleted file mode 100644 index 40d6886..0000000 --- a/tests/unit/framework/behaviors/TimestampBehaviorTest.php +++ /dev/null @@ -1,110 +0,0 @@ -mockApplication([ - 'components' => [ - 'db' => [ - 'class' => '\yii\db\Connection', - 'dsn' => 'sqlite::memory:', - ] - ] - ]); - - $columns = [ - 'id' => 'pk', - 'created_at' => 'integer', - 'updated_at' => 'integer', - ]; - Yii::$app->getDb()->createCommand()->createTable('test_auto_timestamp', $columns)->execute(); - } - - public function tearDown() - { - Yii::$app->getDb()->close(); - parent::tearDown(); - } - - // Tests : - - public function testNewRecord() - { - $currentTime = time(); - - $model = new ActiveRecordTimestamp(); - $model->save(false); - - $this->assertTrue($model->created_at >= $currentTime); - $this->assertTrue($model->updated_at >= $currentTime); - } - - /** - * @depends testNewRecord - */ - public function testUpdateRecord() - { - $currentTime = time(); - - $model = new ActiveRecordTimestamp(); - $model->save(false); - - $enforcedTime = $currentTime - 100; - - $model->created_at = $enforcedTime; - $model->updated_at = $enforcedTime; - $model->save(false); - - $this->assertEquals($enforcedTime, $model->created_at, 'Create time has been set on update!'); - $this->assertTrue($model->updated_at >= $currentTime, 'Update time has NOT been set on update!'); - } -} - -/** - * Test Active Record class with [[TimestampBehavior]] behavior attached. - * - * @property integer $id - * @property integer $created_at - * @property integer $updated_at - */ -class ActiveRecordTimestamp extends ActiveRecord -{ - public function behaviors() - { - return [ - TimestampBehavior::className(), - ]; - } - - public static function tableName() - { - return 'test_auto_timestamp'; - } -} diff --git a/tests/unit/framework/caching/ApcCacheTest.php b/tests/unit/framework/caching/ApcCacheTest.php deleted file mode 100644 index 126471c..0000000 --- a/tests/unit/framework/caching/ApcCacheTest.php +++ /dev/null @@ -1,46 +0,0 @@ -markTestSkipped("APC not installed. Skipping."); - } elseif ('cli' === PHP_SAPI && !ini_get('apc.enable_cli')) { - $this->markTestSkipped("APC cli is not enabled. Skipping."); - } - - if (!ini_get("apc.enabled") || !ini_get("apc.enable_cli")) { - $this->markTestSkipped("APC is installed but not enabled. Skipping."); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new ApcCache(); - } - - return $this->_cacheInstance; - } - - public function testExpire() - { - $this->markTestSkipped("APC keys are expiring only on the next request."); - } - - public function testExpireAdd() - { - $this->markTestSkipped("APC keys are expiring only on the next request."); - } -} diff --git a/tests/unit/framework/caching/ArrayCacheTest.php b/tests/unit/framework/caching/ArrayCacheTest.php deleted file mode 100644 index 5ec7d73..0000000 --- a/tests/unit/framework/caching/ArrayCacheTest.php +++ /dev/null @@ -1,49 +0,0 @@ -_cacheInstance === null) { - $this->_cacheInstance = new ArrayCache(); - } - return $this->_cacheInstance; - } - - public function testExpire() - { - $cache = $this->getCacheInstance(); - - static::$microtime = \microtime(true); - $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); - static::$microtime++; - $this->assertEquals('expire_test', $cache->get('expire_test')); - static::$microtime++; - $this->assertFalse($cache->get('expire_test')); - } - - public function testExpireAdd() - { - $cache = $this->getCacheInstance(); - - static::$microtime = \microtime(true); - $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); - static::$microtime++; - $this->assertEquals('expire_testa', $cache->get('expire_testa')); - static::$microtime++; - $this->assertFalse($cache->get('expire_testa')); - } -} diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php deleted file mode 100644 index 4d976c4..0000000 --- a/tests/unit/framework/caching/CacheTestCase.php +++ /dev/null @@ -1,246 +0,0 @@ -mockApplication(); - } - - protected function tearDown() - { - static::$time = null; - static::$microtime = null; - } - - /** - * @return Cache - */ - public function prepare() - { - $cache = $this->getCacheInstance(); - - $cache->flush(); - $cache->set('string_test', 'string_test'); - $cache->set('number_test', 42); - $cache->set('array_test', ['array_test' => 'array_test']); - $cache['arrayaccess_test'] = new \stdClass(); - - return $cache; - } - - public function testSet() - { - $cache = $this->getCacheInstance(); - - $this->assertTrue($cache->set('string_test', 'string_test')); - $this->assertTrue($cache->set('number_test', 42)); - $this->assertTrue($cache->set('array_test', ['array_test' => 'array_test'])); - } - - public function testGet() - { - $cache = $this->prepare(); - - $this->assertEquals('string_test', $cache->get('string_test')); - - $this->assertEquals(42, $cache->get('number_test')); - - $array = $cache->get('array_test'); - $this->assertArrayHasKey('array_test', $array); - $this->assertEquals('array_test', $array['array_test']); - } - - /** - * @return array testing mset with and without expiry - */ - public function msetExpiry() - { - return [[0], [2]]; - } - - /** - * @dataProvider msetExpiry - */ - public function testMset($expiry) - { - $cache = $this->getCacheInstance(); - $cache->flush(); - - $cache->mset([ - 'string_test' => 'string_test', - 'number_test' => 42, - 'array_test' => ['array_test' => 'array_test'], - ], $expiry); - - $this->assertEquals('string_test', $cache->get('string_test')); - - $this->assertEquals(42, $cache->get('number_test')); - - $array = $cache->get('array_test'); - $this->assertArrayHasKey('array_test', $array); - $this->assertEquals('array_test', $array['array_test']); - } - - public function testExists() - { - $cache = $this->prepare(); - - $this->assertTrue($cache->exists('string_test')); - // check whether exists affects the value - $this->assertEquals('string_test', $cache->get('string_test')); - - $this->assertTrue($cache->exists('number_test')); - $this->assertFalse($cache->exists('not_exists')); - } - - public function testArrayAccess() - { - $cache = $this->getCacheInstance(); - - $cache['arrayaccess_test'] = new \stdClass(); - $this->assertInstanceOf('stdClass', $cache['arrayaccess_test']); - } - - public function testGetNonExistent() - { - $cache = $this->getCacheInstance(); - - $this->assertFalse($cache->get('non_existent_key')); - } - - public function testStoreSpecialValues() - { - $cache = $this->getCacheInstance(); - - $this->assertTrue($cache->set('null_value', null)); - $this->assertNull($cache->get('null_value')); - - $this->assertTrue($cache->set('bool_value', true)); - $this->assertTrue($cache->get('bool_value')); - } - - public function testMget() - { - $cache = $this->prepare(); - - $this->assertEquals(['string_test' => 'string_test', 'number_test' => 42], $cache->mget(['string_test', 'number_test'])); - // ensure that order does not matter - $this->assertEquals(['number_test' => 42, 'string_test' => 'string_test'], $cache->mget(['number_test', 'string_test'])); - $this->assertEquals(['number_test' => 42, 'non_existent_key' => null], $cache->mget(['number_test', 'non_existent_key'])); - } - - public function testExpire() - { - $cache = $this->getCacheInstance(); - - $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); - usleep(500000); - $this->assertEquals('expire_test', $cache->get('expire_test')); - usleep(2500000); - $this->assertFalse($cache->get('expire_test')); - } - - public function testExpireAdd() - { - $cache = $this->getCacheInstance(); - - $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); - usleep(500000); - $this->assertEquals('expire_testa', $cache->get('expire_testa')); - usleep(2500000); - $this->assertFalse($cache->get('expire_testa')); - } - - public function testAdd() - { - $cache = $this->prepare(); - - // should not change existing keys - $this->assertFalse($cache->add('number_test', 13)); - $this->assertEquals(42, $cache->get('number_test')); - - // should store data if it's not there yet - $this->assertFalse($cache->get('add_test')); - $this->assertTrue($cache->add('add_test', 13)); - $this->assertEquals(13, $cache->get('add_test')); - } - - public function testMadd() - { - $cache = $this->prepare(); - - $this->assertFalse($cache->get('add_test')); - - $cache->madd([ - 'number_test' => 13, - 'add_test' => 13, - ]); - - $this->assertEquals(42, $cache->get('number_test')); - $this->assertEquals(13, $cache->get('add_test')); - } - - public function testDelete() - { - $cache = $this->prepare(); - - $this->assertNotNull($cache->get('number_test')); - $this->assertTrue($cache->delete('number_test')); - $this->assertFalse($cache->get('number_test')); - } - - public function testFlush() - { - $cache = $this->prepare(); - $this->assertTrue($cache->flush()); - $this->assertFalse($cache->get('number_test')); - } -} diff --git a/tests/unit/framework/caching/DbCacheTest.php b/tests/unit/framework/caching/DbCacheTest.php deleted file mode 100644 index 0036ffe..0000000 --- a/tests/unit/framework/caching/DbCacheTest.php +++ /dev/null @@ -1,99 +0,0 @@ -markTestSkipped('pdo and pdo_mysql extensions are required.'); - } - - parent::setUp(); - - $this->getConnection()->createCommand(" - CREATE TABLE IF NOT EXISTS cache ( - id char(128) NOT NULL, - expire int(11) DEFAULT NULL, - data LONGBLOB, - PRIMARY KEY (id), - KEY expire (expire) - ); - ")->execute(); - } - - /** - * @param boolean $reset whether to clean up the test database - * @return \yii\db\Connection - */ - public function getConnection($reset = true) - { - if ($this->_connection === null) { - $databases = self::getParam('databases'); - $params = $databases['mysql']; - $db = new \yii\db\Connection; - $db->dsn = $params['dsn']; - $db->username = $params['username']; - $db->password = $params['password']; - if ($reset) { - $db->open(); - $lines = explode(';', file_get_contents($params['fixture'])); - foreach ($lines as $line) { - if (trim($line) !== '') { - $db->pdo->exec($line); - } - } - } - $this->_connection = $db; - } - - return $this->_connection; - } - - /** - * @return DbCache - */ - protected function getCacheInstance() - { - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new DbCache(['db' => $this->getConnection()]); - } - - return $this->_cacheInstance; - } - - public function testExpire() - { - $cache = $this->getCacheInstance(); - - static::$time = \time(); - $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); - static::$time++; - $this->assertEquals('expire_test', $cache->get('expire_test')); - static::$time++; - $this->assertFalse($cache->get('expire_test')); - } - - public function testExpireAdd() - { - $cache = $this->getCacheInstance(); - - static::$time = \time(); - $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); - static::$time++; - $this->assertEquals('expire_testa', $cache->get('expire_testa')); - static::$time++; - $this->assertFalse($cache->get('expire_testa')); - } -} diff --git a/tests/unit/framework/caching/FileCacheTest.php b/tests/unit/framework/caching/FileCacheTest.php deleted file mode 100644 index 1c7e183..0000000 --- a/tests/unit/framework/caching/FileCacheTest.php +++ /dev/null @@ -1,49 +0,0 @@ -_cacheInstance === null) { - $this->_cacheInstance = new FileCache(['cachePath' => '@yiiunit/runtime/cache']); - } - - return $this->_cacheInstance; - } - - public function testExpire() - { - $cache = $this->getCacheInstance(); - - static::$time = \time(); - $this->assertTrue($cache->set('expire_test', 'expire_test', 2)); - static::$time++; - $this->assertEquals('expire_test', $cache->get('expire_test')); - static::$time++; - $this->assertFalse($cache->get('expire_test')); - } - - public function testExpireAdd() - { - $cache = $this->getCacheInstance(); - - static::$time = \time(); - $this->assertTrue($cache->add('expire_testa', 'expire_testa', 2)); - static::$time++; - $this->assertEquals('expire_testa', $cache->get('expire_testa')); - static::$time++; - $this->assertFalse($cache->get('expire_testa')); - } -} diff --git a/tests/unit/framework/caching/MemCacheTest.php b/tests/unit/framework/caching/MemCacheTest.php deleted file mode 100644 index d3c35d3..0000000 --- a/tests/unit/framework/caching/MemCacheTest.php +++ /dev/null @@ -1,51 +0,0 @@ -markTestSkipped("memcache not installed. Skipping."); - } - - // check whether memcached is running and skip tests if not. - if (!@stream_socket_client('127.0.0.1:11211', $errorNumber, $errorDescription, 0.5)) { - $this->markTestSkipped('No redis server running at ' . '127.0.0.1:11211' . ' : ' . $errorNumber . ' - ' . $errorDescription); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new MemCache(); - } - - return $this->_cacheInstance; - } - - public function testExpire() - { - if (getenv('TRAVIS') == 'true') { - $this->markTestSkipped('Can not reliably test memcache expiry on travis-ci.'); - } - parent::testExpire(); - } - - public function testExpireAdd() - { - if (getenv('TRAVIS') == 'true') { - $this->markTestSkipped('Can not reliably test memcache expiry on travis-ci.'); - } - parent::testExpireAdd(); - } -} diff --git a/tests/unit/framework/caching/MemCachedTest.php b/tests/unit/framework/caching/MemCachedTest.php deleted file mode 100644 index 56a5570..0000000 --- a/tests/unit/framework/caching/MemCachedTest.php +++ /dev/null @@ -1,51 +0,0 @@ -markTestSkipped("memcached not installed. Skipping."); - } - - // check whether memcached is running and skip tests if not. - if (!@stream_socket_client('127.0.0.1:11211', $errorNumber, $errorDescription, 0.5)) { - $this->markTestSkipped('No redis server running at ' . '127.0.0.1:11211' . ' : ' . $errorNumber . ' - ' . $errorDescription); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new MemCache(['useMemcached' => true]); - } - - return $this->_cacheInstance; - } - - public function testExpire() - { - if (getenv('TRAVIS') == 'true') { - $this->markTestSkipped('Can not reliably test memcached expiry on travis-ci.'); - } - parent::testExpire(); - } - - public function testExpireAdd() - { - if (getenv('TRAVIS') == 'true') { - $this->markTestSkipped('Can not reliably test memcached expiry on travis-ci.'); - } - parent::testExpireAdd(); - } -} diff --git a/tests/unit/framework/caching/TagDependencyTest.php b/tests/unit/framework/caching/TagDependencyTest.php deleted file mode 100644 index 8b61b27..0000000 --- a/tests/unit/framework/caching/TagDependencyTest.php +++ /dev/null @@ -1,79 +0,0 @@ - '@yiiunit/runtime/cache']); - - // single tag test - $cache->set('a1', 11, 0, new TagDependency(['tags' => 't1'])); - $cache->set('a2', 12, 0, new TagDependency(['tags' => 't1'])); - $cache->set('b1', 21, 0, new TagDependency(['tags' => 't2'])); - $cache->set('b2', 22, 0, new TagDependency(['tags' => 't2'])); - - $this->assertEquals(11, $cache->get('a1')); - $this->assertEquals(12, $cache->get('a2')); - $this->assertEquals(21, $cache->get('b1')); - $this->assertEquals(22, $cache->get('b2')); - - TagDependency::invalidate($cache, 't1'); - $this->assertFalse($cache->get('a1')); - $this->assertFalse($cache->get('a2')); - $this->assertEquals(21, $cache->get('b1')); - $this->assertEquals(22, $cache->get('b2')); - - TagDependency::invalidate($cache, 't2'); - $this->assertFalse($cache->get('a1')); - $this->assertFalse($cache->get('a2')); - $this->assertFalse($cache->get('b1')); - $this->assertFalse($cache->get('b2')); - - // multiple tag test - $cache->set('a1', 11, 0, new TagDependency(['tags' => ['t1', 't2']])); - $cache->set('a2', 12, 0, new TagDependency(['tags' => 't1'])); - $cache->set('b1', 21, 0, new TagDependency(['tags' => ['t1', 't2']])); - $cache->set('b2', 22, 0, new TagDependency(['tags' => 't2'])); - - $this->assertEquals(11, $cache->get('a1')); - $this->assertEquals(12, $cache->get('a2')); - $this->assertEquals(21, $cache->get('b1')); - $this->assertEquals(22, $cache->get('b2')); - - TagDependency::invalidate($cache, 't1'); - $this->assertFalse($cache->get('a1')); - $this->assertFalse($cache->get('a2')); - $this->assertFalse($cache->get('b1')); - $this->assertEquals(22, $cache->get('b2')); - - TagDependency::invalidate($cache, 't2'); - $this->assertFalse($cache->get('a1')); - $this->assertFalse($cache->get('a2')); - $this->assertFalse($cache->get('b1')); - $this->assertFalse($cache->get('b2')); - - $cache->set('a1', 11, 0, new TagDependency(['tags' => ['t1', 't2']])); - $cache->set('a2', 12, 0, new TagDependency(['tags' => 't1'])); - $cache->set('b1', 21, 0, new TagDependency(['tags' => ['t1', 't2']])); - $cache->set('b2', 22, 0, new TagDependency(['tags' => 't2'])); - - $this->assertEquals(11, $cache->get('a1')); - $this->assertEquals(12, $cache->get('a2')); - $this->assertEquals(21, $cache->get('b1')); - $this->assertEquals(22, $cache->get('b2')); - - TagDependency::invalidate($cache, ['t1', 't2']); - $this->assertFalse($cache->get('a1')); - $this->assertFalse($cache->get('a2')); - $this->assertFalse($cache->get('b1')); - $this->assertFalse($cache->get('b2')); - } -} diff --git a/tests/unit/framework/caching/WinCacheTest.php b/tests/unit/framework/caching/WinCacheTest.php deleted file mode 100644 index ccf0fdc..0000000 --- a/tests/unit/framework/caching/WinCacheTest.php +++ /dev/null @@ -1,34 +0,0 @@ -markTestSkipped("Wincache not installed. Skipping."); - } - - if (!ini_get('wincache.ucenabled')) { - $this->markTestSkipped("Wincache user cache disabled. Skipping."); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new WinCache(); - } - - return $this->_cacheInstance; - } -} diff --git a/tests/unit/framework/caching/XCacheTest.php b/tests/unit/framework/caching/XCacheTest.php deleted file mode 100644 index ca2b79c..0000000 --- a/tests/unit/framework/caching/XCacheTest.php +++ /dev/null @@ -1,30 +0,0 @@ -markTestSkipped("XCache not installed. Skipping."); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new XCache(); - } - - return $this->_cacheInstance; - } -} diff --git a/tests/unit/framework/caching/ZendDataCacheTest.php b/tests/unit/framework/caching/ZendDataCacheTest.php deleted file mode 100644 index 63c0d10..0000000 --- a/tests/unit/framework/caching/ZendDataCacheTest.php +++ /dev/null @@ -1,30 +0,0 @@ -markTestSkipped("Zend Data cache not installed. Skipping."); - } - - if ($this->_cacheInstance === null) { - $this->_cacheInstance = new ZendDataCache(); - } - - return $this->_cacheInstance; - } -} diff --git a/tests/unit/framework/console/controllers/AssetControllerTest.php b/tests/unit/framework/console/controllers/AssetControllerTest.php deleted file mode 100644 index 8ef7532..0000000 --- a/tests/unit/framework/console/controllers/AssetControllerTest.php +++ /dev/null @@ -1,602 +0,0 @@ -mockApplication(); - $this->testFilePath = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . str_replace('\\', '_', get_class($this)) . uniqid(); - $this->createDir($this->testFilePath); - $this->testAssetsBasePath = $this->testFilePath . DIRECTORY_SEPARATOR . 'assets'; - $this->createDir($this->testAssetsBasePath); - } - - public function tearDown() - { - $this->removeDir($this->testFilePath); - } - - /** - * Creates directory. - * @param string $dirName directory full name. - */ - protected function createDir($dirName) - { - if (!file_exists($dirName)) { - mkdir($dirName, 0777, true); - } - } - - /** - * Removes directory. - * @param string $dirName directory full name - */ - protected function removeDir($dirName) - { - if (!empty($dirName) && file_exists($dirName)) { - exec("rm -rf {$dirName}"); - } - } - - /** - * Creates test asset controller instance. - * @return AssetControllerMock - */ - protected function createAssetController() - { - $module = $this->getMock('yii\\base\\Module', ['fake'], ['console']); - $assetController = new AssetControllerMock('asset', $module); - $assetController->interactive = false; - $assetController->jsCompressor = 'cp {from} {to}'; - $assetController->cssCompressor = 'cp {from} {to}'; - - return $assetController; - } - - /** - * Emulates running of the asset controller action. - * @param string $actionID id of action to be run. - * @param array $args action arguments. - * @return string command output. - */ - protected function runAssetControllerAction($actionID, array $args = []) - { - $controller = $this->createAssetController(); - $controller->run($actionID, $args); - return $controller->flushStdOutBuffer(); - } - - /** - * Creates test compress config. - * @param array[] $bundles asset bundles config. - * @return array config array. - */ - protected function createCompressConfig(array $bundles) - { - static $classNumber = 0; - $classNumber++; - $className = $this->declareAssetBundleClass(['class' => 'AssetBundleAll' . $classNumber]); - $baseUrl = '/test'; - $config = [ - 'bundles' => $bundles, - 'targets' => [ - $className => [ - 'basePath' => $this->testAssetsBasePath, - 'baseUrl' => $baseUrl, - 'js' => 'all.js', - 'css' => 'all.css', - ], - ], - 'assetManager' => [ - 'basePath' => $this->testAssetsBasePath, - 'baseUrl' => '', - ], - ]; - - return $config; - } - - /** - * Creates test compress config file. - * @param string $fileName output file name. - * @param array[] $bundles asset bundles config. - * @throws \Exception on failure. - */ - protected function createCompressConfigFile($fileName, array $bundles) - { - $content = 'createCompressConfig($bundles), true) . ';'; - if (file_put_contents($fileName, $content) <= 0) { - throw new \Exception("Unable to create file '{$fileName}'!"); - } - } - - /** - * Creates test asset file. - * @param string $fileRelativeName file name relative to [[testFilePath]] - * @param string $content file content - * @throws \Exception on failure. - */ - protected function createAssetSourceFile($fileRelativeName, $content) - { - $fileFullName = $this->testFilePath . DIRECTORY_SEPARATOR . $fileRelativeName; - $this->createDir(dirname($fileFullName)); - if (file_put_contents($fileFullName, $content) <= 0) { - throw new \Exception("Unable to create file '{$fileFullName}'!"); - } - } - - /** - * Creates a list of asset source files. - * @param array $files assert source files in format: file/relative/name => fileContent - */ - protected function createAssetSourceFiles(array $files) - { - foreach ($files as $name => $content) { - $this->createAssetSourceFile($name, $content); - } - } - - /** - * Invokes the asset controller method even if it is protected. - * @param string $methodName name of the method to be invoked. - * @param array $args method arguments. - * @return mixed method invoke result. - */ - protected function invokeAssetControllerMethod($methodName, array $args = []) - { - $controller = $this->createAssetController(); - $controllerClassReflection = new \ReflectionClass(get_class($controller)); - $methodReflection = $controllerClassReflection->getMethod($methodName); - $methodReflection->setAccessible(true); - $result = $methodReflection->invokeArgs($controller, $args); - $methodReflection->setAccessible(false); - - return $result; - } - - /** - * Composes asset bundle class source code. - * @param array $config asset bundle config. - * @return string class source code. - */ - protected function composeAssetBundleClassSource(array &$config) - { - $config = array_merge( - [ - 'namespace' => StringHelper::dirname(get_class($this)), - 'class' => 'AppAsset', - 'basePath' => $this->testFilePath, - 'baseUrl' => '', - 'css' => [], - 'js' => [], - 'depends' => [], - ], - $config - ); - foreach ($config as $name => $value) { - if (is_array($value)) { - $config[$name] = var_export($value, true); - } - } - - $source = <<composeAssetBundleClassSource($config); - eval($sourceCode); - - return $config['namespace'] . '\\' . $config['class']; - } - - // Tests : - - public function testActionTemplate() - { - $configFileName = $this->testFilePath . DIRECTORY_SEPARATOR . 'config.php'; - $this->runAssetControllerAction('template', [$configFileName]); - $this->assertTrue(file_exists($configFileName), 'Unable to create config file template!'); - $config = require($configFileName); - $this->assertTrue(is_array($config), 'Invalid config created!'); - } - - public function testActionCompress() - { - // Given : - $cssFiles = [ - 'css/test_body.css' => 'body { - padding-top: 20px; - padding-bottom: 60px; - }', - 'css/test_footer.css' => '.footer { - margin: 20px; - display: block; - }', - ]; - $this->createAssetSourceFiles($cssFiles); - - $jsFiles = [ - 'js/test_alert.js' => "function test() { - alert('Test message'); - }", - 'js/test_sum_ab.js' => "function sumAB(a, b) { - return a + b; - }", - ]; - $this->createAssetSourceFiles($jsFiles); - $assetBundleClassName = $this->declareAssetBundleClass([ - 'css' => array_keys($cssFiles), - 'js' => array_keys($jsFiles), - ]); - - $bundles = [ - $assetBundleClassName - ]; - $bundleFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'bundle.php'; - - $configFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'config2.php'; - $this->createCompressConfigFile($configFile, $bundles); - - // When : - $this->runAssetControllerAction('compress', [$configFile, $bundleFile]); - - // Then : - $this->assertTrue(file_exists($bundleFile), 'Unable to create output bundle file!'); - $compressedBundleConfig = require($bundleFile); - $this->assertTrue(is_array($compressedBundleConfig), 'Output bundle file has incorrect format!'); - $this->assertCount(2, $compressedBundleConfig, 'Output bundle config contains wrong bundle count!'); - - $this->assertArrayHasKey($assetBundleClassName, $compressedBundleConfig, 'Source bundle is lost!'); - $compressedAssetBundleConfig = $compressedBundleConfig[$assetBundleClassName]; - $this->assertEmpty($compressedAssetBundleConfig['css'], 'Compressed bundle css is not empty!'); - $this->assertEmpty($compressedAssetBundleConfig['js'], 'Compressed bundle js is not empty!'); - $this->assertNotEmpty($compressedAssetBundleConfig['depends'], 'Compressed bundle dependency is invalid!'); - - $compressedCssFileName = $this->testAssetsBasePath . DIRECTORY_SEPARATOR . 'all.css'; - $this->assertTrue(file_exists($compressedCssFileName), 'Unable to compress CSS files!'); - $compressedJsFileName = $this->testAssetsBasePath . DIRECTORY_SEPARATOR . 'all.js'; - $this->assertTrue(file_exists($compressedJsFileName), 'Unable to compress JS files!'); - - $compressedCssFileContent = file_get_contents($compressedCssFileName); - foreach ($cssFiles as $name => $content) { - $this->assertContains($content, $compressedCssFileContent, "Source of '{$name}' is missing in combined file!"); - } - $compressedJsFileContent = file_get_contents($compressedJsFileName); - foreach ($jsFiles as $name => $content) { - $this->assertContains($content, $compressedJsFileContent, "Source of '{$name}' is missing in combined file!"); - } - } - - /** - * @depends testActionCompress - * - * @see https://github.com/yiisoft/yii2/issues/5194 - */ - public function testCompressExternalAsset() - { - // Given : - $externalAssetConfig = [ - 'class' => 'ExternalAsset', - 'sourcePath' => null, - 'basePath' => null, - 'js' => [ - '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js', - ], - 'css' => [ - '//ajax.googleapis.com/css/libs/jquery/2.1.1/jquery.ui.min.css' - ], - ]; - $externalAssetBundleClassName = $this->declareAssetBundleClass($externalAssetConfig); - - $cssFiles = [ - 'css/test.css' => 'body { - padding-top: 20px; - padding-bottom: 60px; - }', - ]; - $this->createAssetSourceFiles($cssFiles); - $jsFiles = [ - 'js/test.js' => "function test() { - alert('Test message'); - }", - ]; - $this->createAssetSourceFiles($jsFiles); - $regularAssetBundleClassName = $this->declareAssetBundleClass([ - 'class' => 'RegularAsset', - 'css' => array_keys($cssFiles), - 'js' => array_keys($jsFiles), - 'depends' => [ - $externalAssetBundleClassName - ], - ]); - $bundles = [ - $regularAssetBundleClassName - ]; - $bundleFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'bundle.php'; - - $configFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'config.php'; - $this->createCompressConfigFile($configFile, $bundles); - - // When : - $this->runAssetControllerAction('compress', [$configFile, $bundleFile]); - - // Then : - $this->assertTrue(file_exists($bundleFile), 'Unable to create output bundle file!'); - $compressedBundleConfig = require($bundleFile); - $this->assertTrue(is_array($compressedBundleConfig), 'Output bundle file has incorrect format!'); - $this->assertArrayHasKey($externalAssetBundleClassName, $compressedBundleConfig, 'External bundle is lost!'); - - $compressedExternalAssetConfig = $compressedBundleConfig[$externalAssetBundleClassName]; - $this->assertEquals($externalAssetConfig['js'], $compressedExternalAssetConfig['js'], 'External bundle js is lost!'); - $this->assertEquals($externalAssetConfig['css'], $compressedExternalAssetConfig['css'], 'External bundle css is lost!'); - - $compressedRegularAssetConfig = $compressedBundleConfig[$regularAssetBundleClassName]; - $this->assertContains($externalAssetBundleClassName, $compressedRegularAssetConfig['depends'], 'Dependency on external bundle is lost!'); - } - - /** - * @depends testActionCompress - * - * @see https://github.com/yiisoft/yii2/issues/7539 - */ - public function testDetectCircularDependency() - { - // Given : - $namespace = __NAMESPACE__; - - $this->declareAssetBundleClass([ - 'namespace' => $namespace, - 'class' => 'AssetStart', - 'depends' => [ - $namespace . '\AssetA' - ], - ]); - $this->declareAssetBundleClass([ - 'namespace' => $namespace, - 'class' => 'AssetA', - 'depends' => [ - $namespace . '\AssetB' - ], - ]); - $this->declareAssetBundleClass([ - 'namespace' => $namespace, - 'class' => 'AssetB', - 'depends' => [ - $namespace . '\AssetC' - ], - ]); - $this->declareAssetBundleClass([ - 'namespace' => $namespace, - 'class' => 'AssetC', - 'depends' => [ - $namespace . '\AssetA' - ], - ]); - - $bundles = [ - $namespace . '\AssetStart' - ]; - $bundleFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'bundle.php'; - - $configFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'config.php'; - $this->createCompressConfigFile($configFile, $bundles); - - // Assert : - $expectedExceptionMessage = ": {$namespace}\AssetA -> {$namespace}\AssetB -> {$namespace}\AssetC -> {$namespace}\AssetA"; - $this->setExpectedException('yii\console\Exception', $expectedExceptionMessage); - - // When : - $this->runAssetControllerAction('compress', [$configFile, $bundleFile]); - } - - /** - * Data provider for [[testAdjustCssUrl()]]. - * @return array test data. - */ - public function adjustCssUrlDataProvider() - { - return [ - [ - '.published-same-dir-class {background-image: url(published_same_dir.png);}', - '/test/base/path/assets/input', - '/test/base/path/assets/output', - '.published-same-dir-class {background-image: url(../input/published_same_dir.png);}', - ], - [ - '.published-relative-dir-class {background-image: url(../img/published_relative_dir.png);}', - '/test/base/path/assets/input', - '/test/base/path/assets/output', - '.published-relative-dir-class {background-image: url(../img/published_relative_dir.png);}', - ], - [ - '.static-same-dir-class {background-image: url(\'static_same_dir.png\');}', - '/test/base/path/css', - '/test/base/path/assets/output', - '.static-same-dir-class {background-image: url(\'../../css/static_same_dir.png\');}', - ], - [ - '.static-relative-dir-class {background-image: url("../img/static_relative_dir.png");}', - '/test/base/path/css', - '/test/base/path/assets/output', - '.static-relative-dir-class {background-image: url("../../img/static_relative_dir.png");}', - ], - [ - '.absolute-url-class {background-image: url(http://domain.com/img/image.gif);}', - '/test/base/path/assets/input', - '/test/base/path/assets/output', - '.absolute-url-class {background-image: url(http://domain.com/img/image.gif);}', - ], - [ - '.absolute-url-secure-class {background-image: url(https://secure.domain.com/img/image.gif);}', - '/test/base/path/assets/input', - '/test/base/path/assets/output', - '.absolute-url-secure-class {background-image: url(https://secure.domain.com/img/image.gif);}', - ], - [ - "@font-face { - src: url('../fonts/glyphicons-halflings-regular.eot'); - src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'); - }", - '/test/base/path/assets/input/css', - '/test/base/path/assets/output', - "@font-face { - src: url('../input/fonts/glyphicons-halflings-regular.eot'); - src: url('../input/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'); - }", - ], - [ - "@font-face { - src: url('../fonts/glyphicons-halflings-regular.eot'); - src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'); - }", - '/test/base/path/assets/input/css', - '/test/base/path/assets', - "@font-face { - src: url('input/fonts/glyphicons-halflings-regular.eot'); - src: url('input/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'); - }", - ], - [ - "@font-face { - src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT==) format('truetype'); - }", - '/test/base/path/assets/input/css', - '/test/base/path/assets/output', - "@font-face { - src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT==) format('truetype'); - }", - ], - [ - '.published-same-dir-class {background-image: url(published_same_dir.png);}', - 'C:\test\base\path\assets\input', - 'C:\test\base\path\assets\output', - '.published-same-dir-class {background-image: url(../input/published_same_dir.png);}', - ], - [ - '.static-root-relative-class {background-image: url(\'/images/static_root_relative.png\');}', - '/test/base/path/css', - '/test/base/path/assets/output', - '.static-root-relative-class {background-image: url(\'/images/static_root_relative.png\');}', - ], - [ - '.published-relative-dir-class {background-image: url(../img/same_relative_dir.png);}', - '/test/base/path/assets/css', - '/test/base/path/assets/css', - '.published-relative-dir-class {background-image: url(../img/same_relative_dir.png);}', - ], - ]; - } - - /** - * @dataProvider adjustCssUrlDataProvider - * - * @param $cssContent - * @param $inputFilePath - * @param $outputFilePath - * @param $expectedCssContent - */ - public function testAdjustCssUrl($cssContent, $inputFilePath, $outputFilePath, $expectedCssContent) - { - $adjustedCssContent = $this->invokeAssetControllerMethod('adjustCssUrl', [$cssContent, $inputFilePath, $outputFilePath]); - - $this->assertEquals($expectedCssContent, $adjustedCssContent, 'Unable to adjust CSS correctly!'); - } - - /** - * Data provider for [[testFindRealPath()]] - * @return array test data - */ - public function findRealPathDataProvider() - { - return [ - [ - '/linux/absolute/path', - '/linux/absolute/path', - ], - [ - '/linux/up/../path', - '/linux/path', - ], - [ - '/linux/twice/up/../../path', - '/linux/path', - ], - [ - '/linux/../mix/up/../path', - '/mix/path', - ], - [ - 'C:\\windows\\absolute\\path', - 'C:\\windows\\absolute\\path', - ], - [ - 'C:\\windows\\up\\..\\path', - 'C:\\windows\\path', - ], - ]; - } - - /** - * @dataProvider findRealPathDataProvider - * - * @param string $sourcePath - * @param string $expectedRealPath - */ - public function testFindRealPath($sourcePath, $expectedRealPath) - { - $expectedRealPath = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $expectedRealPath); - $realPath = $this->invokeAssetControllerMethod('findRealPath', [$sourcePath]); - $this->assertEquals($expectedRealPath, $realPath); - } -} - -/** - * Mock class for [[\yii\console\controllers\AssetController]] - */ -class AssetControllerMock extends AssetController -{ - use StdOutBufferControllerTrait; -} \ No newline at end of file diff --git a/tests/unit/framework/console/controllers/BaseMessageControllerTest.php b/tests/unit/framework/console/controllers/BaseMessageControllerTest.php deleted file mode 100644 index f720837..0000000 --- a/tests/unit/framework/console/controllers/BaseMessageControllerTest.php +++ /dev/null @@ -1,385 +0,0 @@ -mockApplication(); - $this->sourcePath = Yii::getAlias('@yiiunit/runtime/test_source'); - FileHelper::createDirectory($this->sourcePath, 0777); - if (!file_exists($this->sourcePath)) { - $this->markTestIncomplete('Unit tests runtime directory should have writable permissions!'); - } - $this->configFileName = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . 'message_controller_test_config.php'; - } - - public function tearDown() - { - FileHelper::removeDirectory($this->sourcePath); - if (file_exists($this->configFileName)) { - unlink($this->configFileName); - } - } - - /** - * Creates test message controller instance. - * @return MessageControllerMock message command instance. - */ - protected function createMessageController() - { - $module = $this->getMock('yii\\base\\Module', ['fake'], ['console']); - $messageController = new MessageControllerMock('message', $module); - $messageController->interactive = false; - - return $messageController; - } - - /** - * Emulates running of the message controller action. - * @param string $actionID id of action to be run. - * @param array $args action arguments. - * @return string command output. - */ - protected function runMessageControllerAction($actionID, array $args = []) - { - $controller = $this->createMessageController(); - $controller->run($actionID, $args); - return $controller->flushStdOutBuffer(); - } - - /** - * Creates message command config file named as [[configFileName]]. - * @param array $config message command config. - */ - protected function saveConfigFile(array $config) - { - if (file_exists($this->configFileName)) { - unlink($this->configFileName); - } - $fileContent = 'configFileName, $fileContent); - } - - /** - * Creates source file with given content - * @param string $content file content - * @return string path to source file - */ - protected function createSourceFile($content) - { - $fileName = $this->sourcePath . DIRECTORY_SEPARATOR . md5(uniqid()) . '.php'; - file_put_contents($fileName, "getDefaultConfig(), $additionalConfig); - } - - // Tests: - - public function testActionConfig() - { - $configFileName = $this->configFileName; - $out = $this->runMessageControllerAction('config', [$configFileName]); - $this->assertTrue(file_exists($configFileName), "Unable to create config file from template. Command output:\n\n" . $out); - } - - public function testConfigFileNotExist() - { - $this->setExpectedException('yii\\console\\Exception'); - $this->runMessageControllerAction('extract', ['not_existing_file.php']); - } - - public function testCreateTranslation() - { - $category = 'test.category1'; - $message = 'test message'; - $sourceFileContent = "Yii::t('{$category}', '{$message}');"; - $this->createSourceFile($sourceFileContent); - - $this->saveConfigFile($this->getConfig()); - $out = $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messages = $this->loadMessages($category); - $this->assertArrayHasKey($message, $messages, "\"$message\" is missing in translation file. Command output:\n\n" . $out); - } - - /** - * @depends testCreateTranslation - */ - public function testNothingToSave() - { - $category = 'test_category2'; - $message = 'test message'; - $sourceFileContent = "Yii::t('{$category}', '{$message}')"; - $this->createSourceFile($sourceFileContent); - - $this->saveConfigFile($this->getConfig()); - $out = $this->runMessageControllerAction('extract', [$this->configFileName]); - $out .= $this->runMessageControllerAction('extract', [$this->configFileName]); - - $this->assertTrue(strpos($out, 'Nothing to save') !== false, "Controller should respond with \"Nothing to save\" if there's nothing to update. Command output:\n\n" . $out); - } - - /** - * @depends testCreateTranslation - */ - public function testMerge() - { - $category = 'test_category3'; - - $existingMessage = 'test existing message'; - $existingMessageTranslation = 'test existing message translation'; - $this->saveMessages( - [$existingMessage => $existingMessageTranslation], - $category - ); - - $newMessage = 'test new message'; - $sourceFileContent = "Yii::t('{$category}', '{$existingMessage}');"; - $sourceFileContent .= "Yii::t('{$category}', '{$newMessage}');"; - $this->createSourceFile($sourceFileContent); - - $this->saveConfigFile($this->getConfig()); - $out = $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messages = $this->loadMessages($category); - $this->assertArrayHasKey($newMessage, $messages, "Unable to add new message: \"$newMessage\". Command output:\n\n" . $out); - $this->assertArrayHasKey($existingMessage, $messages, "Unable to keep existing message: \"$existingMessage\". Command output:\n\n" . $out); - $this->assertEquals('', $messages[$newMessage], "Wrong new message content. Command output:\n\n" . $out); - $this->assertEquals($existingMessageTranslation, $messages[$existingMessage], "Unable to keep existing message content. Command output:\n\n" . $out); - } - - /** - * @depends testMerge - */ - public function testMarkObsoleteMessages() - { - $category = 'category'; - - $obsoleteMessage = 'obsolete message'; - $obsoleteTranslation = 'obsolete translation'; - $this->saveMessages([$obsoleteMessage => $obsoleteTranslation], $category); - - $sourceFileContent = "Yii::t('{$category}', 'any new message');"; - $this->createSourceFile($sourceFileContent); - - $this->saveConfigFile($this->getConfig(['removeUnused' => false])); - $out = $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messages = $this->loadMessages($category); - - $this->assertArrayHasKey($obsoleteMessage, $messages, "Obsolete message should not be removed. Command output:\n\n" . $out); - $this->assertEquals('@@' . $obsoleteTranslation . '@@', $messages[$obsoleteMessage], "Obsolete message was not marked properly. Command output:\n\n" . $out); - } - - /** - * @depends testMerge - */ - public function removeObsoleteMessages() - { - $category = 'category'; - - $obsoleteMessage = 'obsolete message'; - $obsoleteTranslation = 'obsolete translation'; - $this->saveMessages([$obsoleteMessage => $obsoleteTranslation], $category); - - $sourceFileContent = "Yii::t('{$category}', 'any new message');"; - $this->createSourceFile($sourceFileContent); - - $this->saveConfigFile($this->getConfig(['removeUnused' => true])); - $out = $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messages = $this->loadMessages($category); - - $this->assertArrayHasKey($obsoleteMessage, $messages, "Obsolete message should be removed. Command output:\n\n" . $out); - } - - /** - * @depends testMerge - */ - public function testMergeWithContentZero() - { - $category = 'test_category5'; - - $zeroMessage = 'test zero message'; - $zeroMessageContent = '0'; - $falseMessage = 'test false message'; - $falseMessageContent = 'false'; - $this->saveMessages([ - $zeroMessage => $zeroMessageContent, - $falseMessage => $falseMessageContent, - ], $category); - - $newMessage = 'test new message'; - $sourceFileContent = "Yii::t('{$category}', '{$zeroMessage}')"; - $sourceFileContent .= "Yii::t('{$category}', '{$falseMessage}')"; - $sourceFileContent .= "Yii::t('{$category}', '{$newMessage}')"; - $this->createSourceFile($sourceFileContent); - - $this->saveConfigFile($this->getConfig()); - $out = $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messages = $this->loadMessages($category); - $this->assertTrue($zeroMessageContent === $messages[$zeroMessage], "Message content \"0\" is lost. Command output:\n\n" . $out); - $this->assertTrue($falseMessageContent === $messages[$falseMessage], "Message content \"false\" is lost. Command output:\n\n" . $out); - } - - /** - * @depends testCreateTranslation - */ - public function testMultipleTranslators() - { - $category = 'test_category6'; - - $translators = [ - 'Yii::t', - 'Custom::translate', - ]; - - $sourceMessages = [ - 'first message', - 'second message', - ]; - $sourceFileContent = ''; - foreach ($sourceMessages as $key => $message) { - $sourceFileContent .= $translators[$key] . "('{$category}', '{$message}');\n"; - } - $this->createSourceFile($sourceFileContent); - - $this->saveConfigFile($this->getConfig(['translator' => $translators])); - $this->runMessageControllerAction('extract', [$this->configFileName]); - - $messages = $this->loadMessages($category); - - foreach ($sourceMessages as $sourceMessage) { - $this->assertArrayHasKey($sourceMessage, $messages); - } - } - - /** - * @depends testCreateTranslation - */ - public function testMultipleCategories() - { - $category1 = 'category1'; - $category2 = 'category2'; - - $message1 = 'message1'; - $message2 = 'message2'; - $message3 = 'message3'; - - $this->saveConfigFile($this->getConfig(['removeUnused' => true])); - - // Generate initial translation - $sourceFileContent = "Yii::t('{$category1}', '{$message1}'); Yii::t('{$category2}', '{$message2}');"; - $source = $this->createSourceFile($sourceFileContent); - $out = $this->runMessageControllerAction('extract', [$this->configFileName]); - unlink($source); - - $messages1 = $this->loadMessages($category1); - $messages2 = $this->loadMessages($category2); - - $this->assertArrayHasKey($message1, $messages1, "message1 not found in category1. Command output:\n\n" . $out); - $this->assertArrayHasKey($message2, $messages2, "message2 not found in category2. Command output:\n\n" . $out); - $this->assertArrayNotHasKey($message3, $messages2, "message3 found in category2. Command output:\n\n" . $out); - - // Change source code, run translation again - $sourceFileContent = "Yii::t('{$category1}', '{$message1}'); Yii::t('{$category2}', '{$message3}');"; - $source = $this->createSourceFile($sourceFileContent); - $out .= "\n" . $this->runMessageControllerAction('extract', [$this->configFileName]); - unlink($source); - - $messages1 = $this->loadMessages($category1); - $messages2 = $this->loadMessages($category2); - $this->assertArrayHasKey($message1, $messages1, "message1 not found in category1. Command output:\n\n" . $out); - $this->assertArrayHasKey($message3, $messages2, "message3 not found in category2. Command output:\n\n" . $out); - $this->assertArrayNotHasKey($message2, $messages2, "message2 found in category2. Command output:\n\n" . $out); - } - - public function testIgnoreCategories() - { - $category1 = 'category1'; - $category2 = 'category2'; - - $message1 = 'message1'; - $message2 = 'message2'; - $message3 = 'message3'; - - $this->saveConfigFile($this->getConfig(['ignoreCategories' => ['category2']])); - - // Generate initial translation - $sourceFileContent = "Yii::t('{$category1}', '{$message1}'); Yii::t('{$category2}', '{$message2}');"; - $source = $this->createSourceFile($sourceFileContent); - $out = $this->runMessageControllerAction('extract', [$this->configFileName]); - unlink($source); - - $messages1 = $this->loadMessages($category1); - $messages2 = $this->loadMessages($category2, false); - - $this->assertArrayHasKey($message1, $messages1, "message1 not found in category1. Command output:\n\n" . $out); - $this->assertArrayNotHasKey($message2, $messages2, "message2 found in category2. Command output:\n\n" . $out); - $this->assertArrayNotHasKey($message3, $messages2, "message3 found in category2. Command output:\n\n" . $out); - - // Change source code, run translation again - $sourceFileContent = "Yii::t('{$category1}', '{$message1}'); Yii::t('{$category2}', '{$message3}');"; - $source = $this->createSourceFile($sourceFileContent); - $out .= "\n" . $this->runMessageControllerAction('extract', [$this->configFileName]); - unlink($source); - - $messages1 = $this->loadMessages($category1); - $messages2 = $this->loadMessages($category2, false); - $this->assertArrayHasKey($message1, $messages1, "message1 not found in category1. Command output:\n\n" . $out); - $this->assertArrayNotHasKey($message3, $messages2, "message3 not found in category2. Command output:\n\n" . $out); - $this->assertArrayNotHasKey($message2, $messages2, "message2 found in category2. Command output:\n\n" . $out); - } -} - -class MessageControllerMock extends MessageController -{ - use StdOutBufferControllerTrait; -} \ No newline at end of file diff --git a/tests/unit/framework/console/controllers/CacheControllerTest.php b/tests/unit/framework/console/controllers/CacheControllerTest.php deleted file mode 100644 index 73e00d1..0000000 --- a/tests/unit/framework/console/controllers/CacheControllerTest.php +++ /dev/null @@ -1,143 +0,0 @@ -_cacheController = Yii::createObject([ - 'class' => 'yiiunit\framework\console\controllers\SilencedCacheController', - 'interactive' => false, - ],[null, null]); //id and module are null - - $databases = self::getParam('databases'); - $config = $databases[$this->driverName]; - $pdoDriver = 'pdo_' . $this->driverName; - - if (!extension_loaded('pdo') || !extension_loaded($pdoDriver)) { - $this->markTestSkipped('pdo and ' . $pdoDriver . ' extensions are required.'); - } - - - $this->mockApplication([ - 'components' => [ - 'firstCache' => 'yii\caching\ArrayCache', - 'secondCache' => 'yii\caching\ArrayCache', - 'session' => 'yii\web\CacheSession', // should be ignored at `actionFlushAll()` - 'db' => [ - 'class' => isset($config['class']) ? $config['class'] : 'yii\db\Connection', - 'dsn' => $config['dsn'], - 'username' => isset($config['username']) ? $config['username'] : null, - 'password' => isset($config['password']) ? $config['password'] : null, - 'enableSchemaCache' => true, - 'schemaCache' => 'firstCache', - ], - ], - ]); - - if(isset($config['fixture'])) { - Yii::$app->db->open(); - $lines = explode(';', file_get_contents($config['fixture'])); - foreach ($lines as $line) { - if (trim($line) !== '') { - Yii::$app->db->pdo->exec($line); - } - } - } - } - - public function testFlushOne() - { - Yii::$app->firstCache->set('firstKey', 'firstValue'); - Yii::$app->firstCache->set('secondKey', 'secondValue'); - Yii::$app->secondCache->set('thirdKey', 'thirdValue'); - - $this->_cacheController->actionFlush('firstCache'); - - $this->assertFalse(Yii::$app->firstCache->get('firstKey'),'first cache data should be flushed'); - $this->assertFalse(Yii::$app->firstCache->get('secondKey'),'first cache data should be flushed'); - $this->assertEquals('thirdValue', Yii::$app->secondCache->get('thirdKey'), 'second cache data should not be flushed'); - } - - public function testClearSchema() - { - $schema = Yii::$app->db->schema; - Yii::$app->db->createCommand()->createTable('test_schema_cache', ['id' => 'pk'])->execute(); - $noCacheSchemas = $schema->getTableSchemas('', true); - $cacheSchema = $schema->getTableSchemas('', false); - - $this->assertEquals($noCacheSchemas, $cacheSchema, 'Schema should not be modified.'); - - Yii::$app->db->createCommand()->dropTable('test_schema_cache')->execute(); - $noCacheSchemas = $schema->getTableSchemas('', true); - $this->assertNotEquals($noCacheSchemas, $cacheSchema, 'Schemas should be different.'); - - $this->_cacheController->actionFlushSchema('db'); - $cacheSchema = $schema->getTableSchemas('', false); - $this->assertEquals($noCacheSchemas, $cacheSchema, 'Schema cache should be flushed.'); - - } - - public function testFlushBoth() - { - Yii::$app->firstCache->set('firstKey', 'firstValue'); - Yii::$app->firstCache->set('secondKey', 'secondValue'); - Yii::$app->secondCache->set('thirdKey', 'secondValue'); - - $this->_cacheController->actionFlush('firstCache', 'secondCache'); - - $this->assertFalse(Yii::$app->firstCache->get('firstKey'),'first cache data should be flushed'); - $this->assertFalse(Yii::$app->firstCache->get('secondKey'),'first cache data should be flushed'); - $this->assertFalse(Yii::$app->secondCache->get('thirdKey'), 'second cache data should be flushed'); - } - - public function testNotFoundFlush() - { - Yii::$app->firstCache->set('firstKey', 'firstValue'); - - $this->_cacheController->actionFlush('notExistingCache'); - - $this->assertEquals('firstValue', Yii::$app->firstCache->get('firstKey'), 'first cache data should not be flushed'); - } - - /** - * @expectedException \yii\console\Exception - */ - public function testNothingToFlushException() - { - $this->_cacheController->actionFlush(); - } - - public function testFlushAll() - { - Yii::$app->firstCache->set('firstKey', 'firstValue'); - Yii::$app->secondCache->set('thirdKey', 'secondValue'); - - $this->_cacheController->actionFlushAll(); - - $this->assertFalse(Yii::$app->firstCache->get('firstKey'),'first cache data should be flushed'); - $this->assertFalse(Yii::$app->secondCache->get('thirdKey'), 'second cache data should be flushed'); - } - -} diff --git a/tests/unit/framework/console/controllers/EchoMigrateController.php b/tests/unit/framework/console/controllers/EchoMigrateController.php deleted file mode 100644 index 9e362bd..0000000 --- a/tests/unit/framework/console/controllers/EchoMigrateController.php +++ /dev/null @@ -1,18 +0,0 @@ -_fixtureController = Yii::createObject([ - 'class' => 'yiiunit\framework\console\controllers\FixtureConsoledController', - 'interactive' => false, - 'globalFixtures' => [], - 'namespace' => 'yiiunit\data\console\controllers\fixtures', - ],[null, null]); //id and module are null - } - - protected function tearDown() - { - $this->_fixtureController = null; - FixtureStorage::clear(); - - parent::tearDown(); - } - - public function testLoadGlobalFixture() - { - $this->_fixtureController->globalFixtures = [ - '\yiiunit\data\console\controllers\fixtures\Global' - ]; - - $this->_fixtureController->actionLoad('First'); - - $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); - $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); - } - - public function testUnloadGlobalFixture() - { - $this->_fixtureController->globalFixtures = [ - '\yiiunit\data\console\controllers\fixtures\Global' - ]; - - FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; - FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; - - $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); - $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); - - $this->_fixtureController->actionUnload('First'); - - $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should be unloaded'); - $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); - } - - public function testLoadAll() - { - $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should be empty'); - $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be empty'); - $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should be empty'); - - $this->_fixtureController->actionLoad('*'); - - $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); - $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); - $this->assertCount(1, FixtureStorage::$secondFixtureData, 'second fixture data should be loaded'); - } - - public function testUnloadAll() - { - FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; - FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; - FixtureStorage::$secondFixtureData[] = 'some seeded second fixture data'; - - $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); - $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); - $this->assertCount(1, FixtureStorage::$secondFixtureData, 'second fixture data should be loaded'); - - $this->_fixtureController->actionUnload('*'); - - $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should be unloaded'); - $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); - $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should be unloaded'); - } - - public function testLoadParticularExceptOnes() - { - $this->_fixtureController->actionLoad('First', '-Second', '-Global'); - - $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); - $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be loaded'); - $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be loaded'); - } - - public function testUnloadParticularExceptOnes() - { - FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; - FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; - FixtureStorage::$secondFixtureData[] = 'some seeded second fixture data'; - - $this->_fixtureController->actionUnload('First', '-Second', '-Global'); - - $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); - $this->assertNotEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be unloaded'); - $this->assertNotEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be unloaded'); - } - - public function testLoadAllExceptOnes() - { - $this->_fixtureController->actionLoad('*', '-Second', '-Global'); - - $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); - $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be loaded'); - $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be loaded'); - } - - public function testUnloadAllExceptOnes() - { - FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; - FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; - FixtureStorage::$secondFixtureData[] = 'some seeded second fixture data'; - - $this->_fixtureController->actionUnload('*', '-Second', '-Global'); - - $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); - $this->assertNotEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be unloaded'); - $this->assertNotEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be unloaded'); - } - - public function testNothingToLoadParticularExceptOnes() - { - $this->_fixtureController->actionLoad('First', '-First'); - - $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should not be loaded'); - } - - public function testNothingToUnloadParticularExceptOnes() - { - $this->_fixtureController->actionUnload('First', '-First'); - - $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should not be loaded'); - } - - /** - * @expectedException \yii\console\Exception - */ - public function testNoFixturesWereFoundInLoad() - { - $this->_fixtureController->actionLoad('NotExistingFixture'); - } - - /** - * @expectedException \yii\console\Exception - */ - public function testNoFixturesWereFoundInUnload() - { - $this->_fixtureController->actionUnload('NotExistingFixture'); - } - -} - -class FixtureConsoledController extends FixtureController -{ - - public function stdout($string) - { - } - -} diff --git a/tests/unit/framework/console/controllers/MigrateControllerTest.php b/tests/unit/framework/console/controllers/MigrateControllerTest.php deleted file mode 100644 index 02346fe..0000000 --- a/tests/unit/framework/console/controllers/MigrateControllerTest.php +++ /dev/null @@ -1,53 +0,0 @@ -migrateControllerClass = EchoMigrateController::className(); - $this->migrationBaseClass = Migration::className(); - - $this->mockApplication([ - 'components' => [ - 'db' => [ - 'class' => 'yii\db\Connection', - 'dsn' => 'sqlite::memory:', - ], - ], - ]); - - $this->setUpMigrationPath(); - parent::setUp(); - } - - public function tearDown() - { - $this->tearDownMigrationPath(); - parent::tearDown(); - } - - /** - * @return array applied migration entries - */ - protected function getMigrationHistory() - { - $query = new Query(); - return $query->from('migration')->all(); - } -} \ No newline at end of file diff --git a/tests/unit/framework/console/controllers/MigrateControllerTestTrait.php b/tests/unit/framework/console/controllers/MigrateControllerTestTrait.php deleted file mode 100644 index ec8315b..0000000 --- a/tests/unit/framework/console/controllers/MigrateControllerTestTrait.php +++ /dev/null @@ -1,258 +0,0 @@ -migrationPath = Yii::getAlias('@yiiunit/runtime/test_migrations'); - FileHelper::createDirectory($this->migrationPath); - if (!file_exists($this->migrationPath)) { - $this->markTestIncomplete('Unit tests runtime directory should have writable permissions!'); - } - } - - public function tearDownMigrationPath() - { - FileHelper::removeDirectory($this->migrationPath); - } - - /** - * @return array applied migration entries - */ - abstract protected function getMigrationHistory(); - - /** - * Creates test migrate controller instance. - * @return BaseMigrateController migrate command instance. - */ - protected function createMigrateController() - { - $module = $this->getMock('yii\\base\\Module', ['fake'], ['console']); - $class = $this->migrateControllerClass; - $migrateController = new $class('migrate', $module); - $migrateController->interactive = false; - $migrateController->migrationPath = $this->migrationPath; - return $migrateController; - } - - /** - * Emulates running of the migrate controller action. - * @param string $actionID id of action to be run. - * @param array $args action arguments. - * @return string command output. - */ - protected function runMigrateControllerAction($actionID, array $args = []) - { - $controller = $this->createMigrateController(); - ob_start(); - ob_implicit_flush(false); - $controller->run($actionID, $args); - - return ob_get_clean(); - } - - /** - * @param string $name - * @param string|null $date - * @return string generated class name - */ - protected function createMigration($name, $date = null) - { - if ($date === null) { - $date = gmdate('ymd_His'); - } - $class = 'm' . $date . '_' . $name; - $baseClass = $this->migrationBaseClass; - - $code = <<migrationPath . DIRECTORY_SEPARATOR . $class . '.php', $code); - return $class; - } - - /** - * Checks if applied migration history matches expected one. - * @param array $expectedMigrations migration names in expected order - * @param string $message failure message - */ - protected function assertMigrationHistory(array $expectedMigrations, $message = '') - { - $success = true; - $migrationHistory = $this->getMigrationHistory(); - $appliedMigrations = $migrationHistory; - foreach ($expectedMigrations as $expectedMigrationName) { - $appliedMigration = array_shift($appliedMigrations); - if (strpos($appliedMigration['version'], $expectedMigrationName) === false) { - $success = false; - break; - } - } - if (!$success) { - $message .= "\n"; - $message .= "Expected: " . var_export($expectedMigrations, true) . "\n"; - - $actualMigrations = []; - foreach ($migrationHistory as $row) { - $actualMigrations[] = $row['version']; - } - $message .= "Actual: " . var_export($actualMigrations, true) . "\n"; - } - $this->assertTrue($success, $message); - } - - // Tests : - - public function testCreate() - { - $migrationName = 'test_migration'; - $this->runMigrateControllerAction('create', [$migrationName]); - $files = FileHelper::findFiles($this->migrationPath); - $this->assertCount(1, $files, 'Unable to create new migration!'); - $this->assertContains($migrationName, basename($files[0]), 'Wrong migration name!'); - } - - public function testUp() - { - $this->createMigration('test1'); - $this->createMigration('test2'); - - $this->runMigrateControllerAction('up'); - - $this->assertMigrationHistory(['base', 'test1', 'test2']); - } - - /** - * @depends testUp - */ - public function testUpCount() - { - $this->createMigration('test1'); - $this->createMigration('test2'); - - $this->runMigrateControllerAction('up', [1]); - - $this->assertMigrationHistory(['base', 'test1']); - } - - /** - * @depends testUp - */ - public function testDownCount() - { - $this->createMigration('test1'); - $this->createMigration('test2'); - - $this->runMigrateControllerAction('up'); - $this->runMigrateControllerAction('down', [1]); - - $this->assertMigrationHistory(['base', 'test1']); - } - - /** - * @depends testDownCount - */ - public function testDownAll() - { - $this->createMigration('test1'); - $this->createMigration('test2'); - - $this->runMigrateControllerAction('up'); - $this->runMigrateControllerAction('down', ['all']); - - $this->assertMigrationHistory(['base']); - } - - /** - * @depends testUp - */ - public function testHistory() - { - $output = $this->runMigrateControllerAction('history'); - $this->assertContains('No migration', $output); - - $this->createMigration('test1'); - $this->createMigration('test2'); - $this->runMigrateControllerAction('up'); - - $output = $this->runMigrateControllerAction('history'); - $this->assertContains('_test1', $output); - $this->assertContains('_test2', $output); - } - - /** - * @depends testUp - */ - public function testNew() - { - $this->createMigration('test1'); - - $output = $this->runMigrateControllerAction('new'); - $this->assertContains('_test1', $output); - - $this->runMigrateControllerAction('up'); - - $output = $this->runMigrateControllerAction('new'); - $this->assertNotContains('_test1', $output); - } - - public function testMark() - { - $version = '010101_000001'; - $this->createMigration('test1', $version); - - $this->runMigrateControllerAction('mark', [$version]); - - $this->assertMigrationHistory(['base', 'test1']); - } - - /** - * @depends testUp - */ - public function testRedo() - { - $this->createMigration('test1'); - $this->runMigrateControllerAction('up'); - - $this->runMigrateControllerAction('redo'); - - $this->assertMigrationHistory(['base', 'test1']); - } -} \ No newline at end of file diff --git a/tests/unit/framework/console/controllers/PHPMessageControllerTest.php b/tests/unit/framework/console/controllers/PHPMessageControllerTest.php deleted file mode 100644 index 918c49d..0000000 --- a/tests/unit/framework/console/controllers/PHPMessageControllerTest.php +++ /dev/null @@ -1,87 +0,0 @@ -messagePath = Yii::getAlias('@yiiunit/runtime/test_messages'); - FileHelper::createDirectory($this->messagePath, 0777); - } - - public function tearDown() - { - parent::tearDown(); - FileHelper::removeDirectory($this->messagePath); - } - - /** - * @inheritdoc - */ - protected function getDefaultConfig() - { - return [ - 'format' => 'php', - 'languages' => [$this->language], - 'sourcePath' => $this->sourcePath, - 'messagePath' => $this->messagePath, - 'overwrite' => true, - ]; - } - - /** - * @param string $category - * @return string message file path - */ - protected function getMessageFilePath($category) - { - return $this->messagePath . '/' . $this->language . '/' . $category . '.php'; - } - - /** - * @inheritdoc - */ - protected function saveMessages($messages, $category) - { - $fileName = $this->getMessageFilePath($category); - if (file_exists($fileName)) { - unlink($fileName); - } else { - $dirName = dirname($fileName); - if (!file_exists($dirName)) { - mkdir($dirName, 0777, true); - } - } - $fileContent = 'getMessageFilePath($category); - - if (!file_exists($messageFilePath)) { - return []; - } - return require $messageFilePath; - } -} \ No newline at end of file diff --git a/tests/unit/framework/console/controllers/POMessageControllerTest.php b/tests/unit/framework/console/controllers/POMessageControllerTest.php deleted file mode 100644 index 18f2c74..0000000 --- a/tests/unit/framework/console/controllers/POMessageControllerTest.php +++ /dev/null @@ -1,87 +0,0 @@ -markTestSkipped('POMessageControllerTest can not run on HHVM because it relies on saving and re-including PHP files which is not supported by HHVM.'); - } - - $this->messagePath = Yii::getAlias('@yiiunit/runtime/test_messages'); - FileHelper::createDirectory($this->messagePath, 0777); - } - - public function tearDown() - { - parent::tearDown(); - FileHelper::removeDirectory($this->messagePath); - } - - /** - * @inheritdoc - */ - protected function getDefaultConfig() - { - return [ - 'format' => 'po', - 'languages' => [$this->language], - 'sourcePath' => $this->sourcePath, - 'messagePath' => $this->messagePath, - 'overwrite' => true, - ]; - } - - /** - * @return string message file path - */ - protected function getMessageFilePath() - { - return $this->messagePath . '/' . $this->language . '/' . $this->catalog . '.po'; - } - - /** - * @inheritdoc - */ - protected function saveMessages($messages, $category) - { - $messageFilePath = $this->getMessageFilePath(); - FileHelper::createDirectory(dirname($messageFilePath), 0777); - $gettext = new GettextPoFile(); - - $data = []; - foreach ($messages as $message => $translation) { - $data[$category . chr(4) . $message] = $translation; - } - - $gettext->save($messageFilePath, $data); - } - - /** - * @inheritdoc - */ - protected function loadMessages($category) - { - $messageFilePath = $this->getMessageFilePath(); - if (!file_exists($messageFilePath)) { - return []; - } - - $gettext = new GettextPoFile(); - return $gettext->load($messageFilePath, $category); - } -} \ No newline at end of file diff --git a/tests/unit/framework/console/controllers/SilencedCacheController.php b/tests/unit/framework/console/controllers/SilencedCacheController.php deleted file mode 100644 index 40eed6e..0000000 --- a/tests/unit/framework/console/controllers/SilencedCacheController.php +++ /dev/null @@ -1,20 +0,0 @@ -stdOutBuffer .= $string; - } - - public function flushStdOutBuffer() - { - $result = $this->stdOutBuffer; - $this->stdOutBuffer = ''; - return $result; - } -} \ No newline at end of file diff --git a/tests/unit/framework/data/ActiveDataProviderTest.php b/tests/unit/framework/data/ActiveDataProviderTest.php deleted file mode 100644 index f62b012..0000000 --- a/tests/unit/framework/data/ActiveDataProviderTest.php +++ /dev/null @@ -1,180 +0,0 @@ - - * @since 2.0 - * - * @group data - * @group db - */ -class ActiveDataProviderTest extends DatabaseTestCase -{ - protected function setUp() - { - parent::setUp(); - ActiveRecord::$db = $this->getConnection(); - } - - public function testActiveQuery() - { - $provider = new ActiveDataProvider([ - 'query' => Order::find()->orderBy('id'), - ]); - $orders = $provider->getModels(); - $this->assertEquals(3, count($orders)); - $this->assertTrue($orders[0] instanceof Order); - $this->assertTrue($orders[1] instanceof Order); - $this->assertTrue($orders[2] instanceof Order); - $this->assertEquals([1, 2, 3], $provider->getKeys()); - - $provider = new ActiveDataProvider([ - 'query' => Order::find(), - 'pagination' => [ - 'pageSize' => 2, - ] - ]); - $orders = $provider->getModels(); - $this->assertEquals(2, count($orders)); - } - - public function testActiveRelation() - { - /* @var $customer Customer */ - $customer = Customer::findOne(2); - $provider = new ActiveDataProvider([ - 'query' => $customer->getOrders(), - ]); - $orders = $provider->getModels(); - $this->assertEquals(2, count($orders)); - $this->assertTrue($orders[0] instanceof Order); - $this->assertTrue($orders[1] instanceof Order); - $this->assertEquals([2, 3], $provider->getKeys()); - - $provider = new ActiveDataProvider([ - 'query' => $customer->getOrders(), - 'pagination' => [ - 'pageSize' => 1, - ] - ]); - $orders = $provider->getModels(); - $this->assertEquals(1, count($orders)); - } - - public function testActiveRelationVia() - { - /* @var $order Order */ - $order = Order::findOne(2); - $provider = new ActiveDataProvider([ - 'query' => $order->getItems(), - ]); - $items = $provider->getModels(); - $this->assertEquals(3, count($items)); - $this->assertTrue($items[0] instanceof Item); - $this->assertTrue($items[1] instanceof Item); - $this->assertTrue($items[2] instanceof Item); - $this->assertEquals([3, 4, 5], $provider->getKeys()); - - $provider = new ActiveDataProvider([ - 'query' => $order->getItems(), - 'pagination' => [ - 'pageSize' => 2, - ] - ]); - $items = $provider->getModels(); - $this->assertEquals(2, count($items)); - } - - public function testActiveRelationViaTable() - { - /* @var $order Order */ - $order = Order::findOne(1); - $provider = new ActiveDataProvider([ - 'query' => $order->getBooks(), - ]); - $items = $provider->getModels(); - $this->assertEquals(2, count($items)); - $this->assertTrue($items[0] instanceof Item); - $this->assertTrue($items[1] instanceof Item); - - $provider = new ActiveDataProvider([ - 'query' => $order->getBooks(), - 'pagination' => [ - 'pageSize' => 1, - ] - ]); - $items = $provider->getModels(); - $this->assertEquals(1, count($items)); - } - - public function testQuery() - { - $query = new Query; - $provider = new ActiveDataProvider([ - 'db' => $this->getConnection(), - 'query' => $query->from('order')->orderBy('id'), - ]); - $orders = $provider->getModels(); - $this->assertEquals(3, count($orders)); - $this->assertTrue(is_array($orders[0])); - $this->assertEquals([0, 1, 2], $provider->getKeys()); - - $query = new Query; - $provider = new ActiveDataProvider([ - 'db' => $this->getConnection(), - 'query' => $query->from('order'), - 'pagination' => [ - 'pageSize' => 2, - ] - ]); - $orders = $provider->getModels(); - $this->assertEquals(2, count($orders)); - } - - public function testRefresh() - { - $query = new Query; - $provider = new ActiveDataProvider([ - 'db' => $this->getConnection(), - 'query' => $query->from('order')->orderBy('id'), - ]); - $this->assertEquals(3, count($provider->getModels())); - - $provider->getPagination()->pageSize = 2; - $this->assertEquals(3, count($provider->getModels())); - $provider->refresh(); - $this->assertEquals(2, count($provider->getModels())); - } - - public function testPaginationBeforeModels() - { - $query = new Query; - $provider = new ActiveDataProvider([ - 'db' => $this->getConnection(), - 'query' => $query->from('order')->orderBy('id'), - ]); - $pagination = $provider->getPagination(); - $this->assertEquals(0, $pagination->getPageCount()); - $this->assertCount(3, $provider->getModels()); - $this->assertEquals(1, $pagination->getPageCount()); - - $provider->getPagination()->pageSize = 2; - $this->assertEquals(3, count($provider->getModels())); - $provider->refresh(); - $this->assertEquals(2, count($provider->getModels())); - } -} diff --git a/tests/unit/framework/data/ArrayDataProviderTest.php b/tests/unit/framework/data/ArrayDataProviderTest.php deleted file mode 100644 index 2a6290d..0000000 --- a/tests/unit/framework/data/ArrayDataProviderTest.php +++ /dev/null @@ -1,182 +0,0 @@ -mockApplication(); - } - - public function testGetModels() - { - $simpleArray = [ - ['name' => 'zero'], - ['name' => 'one'] - ]; - $dataProvider = new ArrayDataProvider(['allModels' => $simpleArray]); - $this->assertEquals($simpleArray, $dataProvider->getModels()); - } - - public function testGetSortedData() - { - $simpleArray = [['sortField' => 1], ['sortField' => 0]]; - $dataProvider = new ArrayDataProvider( - [ - 'allModels' => $simpleArray, - 'sort' => [ - 'attributes' => [ - 'sort' => [ - 'asc' => ['sortField' => SORT_ASC], - 'desc' => ['sortField' => SORT_DESC], - 'label' => 'Sorting', - 'default' => 'asc', - ], - ], - 'defaultOrder' => [ - 'sort' => SORT_ASC, - ] - ], - ] - ); - $sortedArray = [['sortField' => 0], ['sortField' => 1]]; - $this->assertEquals($sortedArray, $dataProvider->getModels()); - } - - public function testGetSortedDataByInnerArrayField() - { - $simpleArray = [ - ['innerArray' => ['sortField' => 1]], - ['innerArray' => ['sortField' => 0]] - ]; - $dataProvider = new ArrayDataProvider( - [ - 'allModels' => $simpleArray, - 'sort' => [ - 'attributes' => [ - 'sort' => [ - 'asc' => ['innerArray.sortField' => SORT_ASC], - 'desc' => ['innerArray.sortField' => SORT_DESC], - 'label' => 'Sorting', - 'default' => 'asc', - ], - ], - 'defaultOrder' => [ - 'sort' => SORT_ASC, - ] - ], - ] - ); - $sortedArray = [ - ['innerArray' => ['sortField' => 0]], - ['innerArray' => ['sortField' => 1]] - ]; - $this->assertEquals($sortedArray, $dataProvider->getModels()); - } - - public function testCaseSensitiveSort() - { - // source data - $unsortedProjects = [ - ['title'=>'Zabbix', 'license'=>'GPL'], - ['title'=>'munin', 'license'=>'GPL'], - ['title'=>'Arch Linux', 'license'=>'GPL'], - ['title'=>'Nagios', 'license'=>'GPL'], - ['title'=>'zend framework', 'license'=>'BSD'], - ['title'=>'Zope', 'license'=>'ZPL'], - ['title'=>'active-record', 'license'=>false], - ['title'=>'ActiveState', 'license'=>false], - ['title'=>'mach', 'license'=>false], - ['title'=>'MySQL', 'license'=>'GPL'], - ['title'=>'mssql', 'license'=>'EULA'], - ['title'=>'Master-Master', 'license'=>false], - ['title'=>'Zend Engine', 'license'=>false], - ['title'=>'Mageia Linux', 'license'=>'GNU GPL'], - ['title'=>'nginx', 'license'=>'BSD'], - ['title'=>'Mozilla Firefox', 'license'=>'MPL'], - ]; - - // expected data - $sortedProjects = [ - // upper cased titles - ['title'=>'ActiveState', 'license'=>false], - ['title'=>'Arch Linux', 'license'=>'GPL'], - ['title'=>'Mageia Linux', 'license'=>'GNU GPL'], - ['title'=>'Master-Master', 'license'=>false], - ['title'=>'Mozilla Firefox', 'license'=>'MPL'], - ['title'=>'MySQL', 'license'=>'GPL'], - ['title'=>'Nagios', 'license'=>'GPL'], - ['title'=>'Zabbix', 'license'=>'GPL'], - ['title'=>'Zend Engine', 'license'=>false], - ['title'=>'Zope', 'license'=>'ZPL'], - // lower cased titles - ['title'=>'active-record', 'license'=>false], - ['title'=>'mach', 'license'=>false], - ['title'=>'mssql', 'license'=>'EULA'], - ['title'=>'munin', 'license'=>'GPL'], - ['title'=>'nginx', 'license'=>'BSD'], - ['title'=>'zend framework', 'license'=>'BSD'], - ]; - - $dataProvider = new ArrayDataProvider( - [ - 'allModels' => $unsortedProjects, - 'sort' => [ - 'attributes' => [ - 'sort' => [ - 'asc' => ['title' => SORT_ASC], - 'desc' => ['title' => SORT_DESC], - 'label' => 'Title', - 'default' => 'desc', - ], - ], - 'defaultOrder' => [ - 'sort' => SORT_ASC, - ] - ], - 'pagination' => [ - 'pageSize' => 100500, - ], - ] - ); - - $this->assertEquals($sortedProjects, $dataProvider->getModels()); - } - - public function testGetKeys() - { - $pagination = ['pageSize' => 2]; - - $simpleArray = [ - ['name' => 'zero'], - ['name' => 'one'], - ['name' => 'tow'], - ]; - $dataProvider = new ArrayDataProvider(['allModels' => $simpleArray, 'pagination' => $pagination]); - $this->assertEquals([0, 1], $dataProvider->getKeys()); - - $namedArray = [ - 'key1' => ['name' => 'zero'], - 'key2' => ['name' => 'one'], - 'key3' => ['name' => 'two'], - ]; - $dataProvider = new ArrayDataProvider(['allModels' => $namedArray, 'pagination' => $pagination]); - $this->assertEquals(['key1', 'key2'], $dataProvider->getKeys()); - - $mixedArray = [ - 'key1' => ['name' => 'zero'], - 9 => ['name' => 'one'], - 'key3' => ['name' => 'two'], - ]; - $dataProvider = new ArrayDataProvider(['allModels' => $mixedArray, 'pagination' => $pagination]); - $this->assertEquals(['key1', 9], $dataProvider->getKeys()); - } -} \ No newline at end of file diff --git a/tests/unit/framework/data/SortTest.php b/tests/unit/framework/data/SortTest.php deleted file mode 100644 index 11b18f6..0000000 --- a/tests/unit/framework/data/SortTest.php +++ /dev/null @@ -1,180 +0,0 @@ - - * @since 2.0 - * - * @group data - */ -class SortTest extends TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - public function testGetOrders() - { - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age,-name' - ], - 'enableMultiSort' => true, - ]); - - $orders = $sort->getOrders(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(SORT_ASC, $orders['age']); - $this->assertEquals(SORT_DESC, $orders['first_name']); - $this->assertEquals(SORT_DESC, $orders['last_name']); - - $sort->enableMultiSort = false; - $orders = $sort->getOrders(true); - $this->assertEquals(1, count($orders)); - $this->assertEquals(SORT_ASC, $orders['age']); - } - - public function testGetAttributeOrders() - { - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age,-name' - ], - 'enableMultiSort' => true, - ]); - - $orders = $sort->getAttributeOrders(); - $this->assertEquals(2, count($orders)); - $this->assertEquals(SORT_ASC, $orders['age']); - $this->assertEquals(SORT_DESC, $orders['name']); - - $sort->enableMultiSort = false; - $orders = $sort->getAttributeOrders(true); - $this->assertEquals(1, count($orders)); - $this->assertEquals(SORT_ASC, $orders['age']); - } - - public function testGetAttributeOrder() - { - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age,-name' - ], - 'enableMultiSort' => true, - ]); - - $this->assertEquals(SORT_ASC, $sort->getAttributeOrder('age')); - $this->assertEquals(SORT_DESC, $sort->getAttributeOrder('name')); - $this->assertNull($sort->getAttributeOrder('xyz')); - } - - public function testCreateSortParam() - { - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age,-name' - ], - 'enableMultiSort' => true, - 'route' => 'site/index', - ]); - - $this->assertEquals('-age,-name', $sort->createSortParam('age')); - $this->assertEquals('name,age', $sort->createSortParam('name')); - } - - public function testCreateUrl() - { - $manager = new UrlManager([ - 'baseUrl' => '/', - 'ScriptUrl' => '/index.php', - 'cache' => null, - ]); - - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age,-name' - ], - 'enableMultiSort' => true, - 'urlManager' => $manager, - 'route' => 'site/index', - ]); - - $this->assertEquals('/index.php?r=site%2Findex&sort=-age%2C-name', $sort->createUrl('age')); - $this->assertEquals('/index.php?r=site%2Findex&sort=name%2Cage', $sort->createUrl('name')); - } - - public function testLink() - { - $this->mockApplication(); - $manager = new UrlManager([ - 'baseUrl' => '/', - 'scriptUrl' => '/index.php', - 'cache' => null, - ]); - - $sort = new Sort([ - 'attributes' => [ - 'age', - 'name' => [ - 'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC], - 'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC], - ], - ], - 'params' => [ - 'sort' => 'age,-name' - ], - 'enableMultiSort' => true, - 'urlManager' => $manager, - 'route' => 'site/index', - ]); - - $this->assertEquals('Age', $sort->link('age')); - } -} diff --git a/tests/unit/framework/db/ActiveRecordTest.php b/tests/unit/framework/db/ActiveRecordTest.php deleted file mode 100644 index f9eef97..0000000 --- a/tests/unit/framework/db/ActiveRecordTest.php +++ /dev/null @@ -1,694 +0,0 @@ -getConnection(); - } - - public function getCustomerClass() - { - return Customer::className(); - } - - public function getItemClass() - { - return Item::className(); - } - - public function getOrderClass() - { - return Order::className(); - } - - public function getOrderItemClass() - { - return OrderItem::className(); - } - - public function getOrderWithNullFKClass() - { - return OrderWithNullFK::className(); - } - public function getOrderItemWithNullFKmClass() - { - return OrderItemWithNullFK::className(); - } - - public function testCustomColumns() - { - // find custom column - if ($this->driverName === 'oci') { - $customer = Customer::find()->select(['{{customer}}.*', '([[status]]*2) AS [[status2]]']) - ->where(['name' => 'user3'])->one(); - } else { - $customer = Customer::find()->select(['*', '([[status]]*2) AS [[status2]]']) - ->where(['name' => 'user3'])->one(); - } - $this->assertEquals(3, $customer->id); - $this->assertEquals(4, $customer->status2); - } - - public function testStatisticalFind() - { - // find count, sum, average, min, max, scalar - $this->assertEquals(3, Customer::find()->count()); - $this->assertEquals(2, Customer::find()->where('[[id]]=1 OR [[id]]=2')->count()); - $this->assertEquals(6, Customer::find()->sum('[[id]]')); - $this->assertEquals(2, Customer::find()->average('[[id]]')); - $this->assertEquals(1, Customer::find()->min('[[id]]')); - $this->assertEquals(3, Customer::find()->max('[[id]]')); - $this->assertEquals(3, Customer::find()->select('COUNT(*)')->scalar()); - } - - public function testFindScalar() - { - // query scalar - $customerName = Customer::find()->where(['[[id]]' => 2])->select('[[name]]')->scalar(); - $this->assertEquals('user2', $customerName); - } - - public function testFindColumn() - { - /* @var $this TestCase|ActiveRecordTestTrait */ - $this->assertEquals(['user1', 'user2', 'user3'], Customer::find()->select('[[name]]')->column()); - $this->assertEquals(['user3', 'user2', 'user1'], Customer::find()->orderBy(['[[name]]' => SORT_DESC])->select('[[name]]')->column()); - } - - public function testFindBySql() - { - // find one - $customer = Customer::findBySql('SELECT * FROM {{customer}} ORDER BY [[id]] DESC')->one(); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals('user3', $customer->name); - - // find all - $customers = Customer::findBySql('SELECT * FROM {{customer}}')->all(); - $this->assertEquals(3, count($customers)); - - // find with parameter binding - $customer = Customer::findBySql('SELECT * FROM {{customer}} WHERE [[id]]=:id', [':id' => 2])->one(); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals('user2', $customer->name); - } - - public function testFindLazyViaTable() - { - /* @var $order Order */ - $order = Order::findOne(1); - $this->assertEquals(1, $order->id); - $this->assertEquals(2, count($order->books)); - $this->assertEquals(1, $order->items[0]->id); - $this->assertEquals(2, $order->items[1]->id); - - $order = Order::findOne(2); - $this->assertEquals(2, $order->id); - $this->assertEquals(0, count($order->books)); - - $order = Order::find()->where(['id' => 1])->asArray()->one(); - $this->assertTrue(is_array($order)); - } - - public function testFindEagerViaTable() - { - $orders = Order::find()->with('books')->orderBy('id')->all(); - $this->assertEquals(3, count($orders)); - - $order = $orders[0]; - $this->assertEquals(1, $order->id); - $this->assertEquals(2, count($order->books)); - $this->assertEquals(1, $order->books[0]->id); - $this->assertEquals(2, $order->books[1]->id); - - $order = $orders[1]; - $this->assertEquals(2, $order->id); - $this->assertEquals(0, count($order->books)); - - $order = $orders[2]; - $this->assertEquals(3, $order->id); - $this->assertEquals(1, count($order->books)); - $this->assertEquals(2, $order->books[0]->id); - - // https://github.com/yiisoft/yii2/issues/1402 - $orders = Order::find()->with('books')->orderBy('id')->asArray()->all(); - $this->assertEquals(3, count($orders)); - $this->assertTrue(is_array($orders[0]['orderItems'][0])); - - $order = $orders[0]; - $this->assertTrue(is_array($order)); - $this->assertEquals(1, $order['id']); - $this->assertEquals(2, count($order['books'])); - $this->assertEquals(1, $order['books'][0]['id']); - $this->assertEquals(2, $order['books'][1]['id']); - } - - // deeply nested table relation - public function testDeeplyNestedTableRelation() - { - /* @var $customer Customer */ - $customer = Customer::findOne(1); - $this->assertNotNull($customer); - - $items = $customer->orderItems; - - $this->assertEquals(2, count($items)); - $this->assertInstanceOf(Item::className(), $items[0]); - $this->assertInstanceOf(Item::className(), $items[1]); - $this->assertEquals(1, $items[0]->id); - $this->assertEquals(2, $items[1]->id); - } - - /** - * https://github.com/yiisoft/yii2/issues/5341 - * - * Issue: Plan 1 -- * Account * -- * User - * Our Tests: Category 1 -- * Item * -- * Order - */ - public function testDeeplyNestedTableRelation2() - { - /* @var $category Category */ - $category = Category::findOne(1); - $this->assertNotNull($category); - $orders = $category->orders; - $this->assertEquals(2, count($orders)); - $this->assertInstanceOf(Order::className(), $orders[0]); - $this->assertInstanceOf(Order::className(), $orders[1]); - $ids = [$orders[0]->id, $orders[1]->id]; - sort($ids); - $this->assertEquals([1, 3], $ids); - - $category = Category::findOne(2); - $this->assertNotNull($category); - $orders = $category->orders; - $this->assertEquals(1, count($orders)); - $this->assertInstanceOf(Order::className(), $orders[0]); - $this->assertEquals(2, $orders[0]->id); - - } - - public function testStoreNull() - { - $record = new NullValues(); - $this->assertNull($record->var1); - $this->assertNull($record->var2); - $this->assertNull($record->var3); - $this->assertNull($record->stringcol); - - $record->id = 1; - - $record->var1 = 123; - $record->var2 = 456; - $record->var3 = 789; - $record->stringcol = 'hello!'; - - $record->save(false); - $this->assertTrue($record->refresh()); - - $this->assertEquals(123, $record->var1); - $this->assertEquals(456, $record->var2); - $this->assertEquals(789, $record->var3); - $this->assertEquals('hello!', $record->stringcol); - - $record->var1 = null; - $record->var2 = null; - $record->var3 = null; - $record->stringcol = null; - - $record->save(false); - $this->assertTrue($record->refresh()); - - $this->assertNull($record->var1); - $this->assertNull($record->var2); - $this->assertNull($record->var3); - $this->assertNull($record->stringcol); - - $record->var1 = 0; - $record->var2 = 0; - $record->var3 = 0; - $record->stringcol = ''; - - $record->save(false); - $this->assertTrue($record->refresh()); - - $this->assertEquals(0, $record->var1); - $this->assertEquals(0, $record->var2); - $this->assertEquals(0, $record->var3); - $this->assertEquals('', $record->stringcol); - } - - public function testStoreEmpty() - { - $record = new NullValues(); - $record->id = 1; - - // this is to simulate empty html form submission - $record->var1 = ''; - $record->var2 = ''; - $record->var3 = ''; - $record->stringcol = ''; - - $record->save(false); - $this->assertTrue($record->refresh()); - - // https://github.com/yiisoft/yii2/commit/34945b0b69011bc7cab684c7f7095d837892a0d4#commitcomment-4458225 - $this->assertTrue($record->var1 === $record->var2); - $this->assertTrue($record->var2 === $record->var3); - } - - public function testIsPrimaryKey() - { - $this->assertFalse(Customer::isPrimaryKey([])); - $this->assertTrue(Customer::isPrimaryKey(['id'])); - $this->assertFalse(Customer::isPrimaryKey(['id', 'name'])); - $this->assertFalse(Customer::isPrimaryKey(['name'])); - $this->assertFalse(Customer::isPrimaryKey(['name', 'email'])); - - $this->assertFalse(OrderItem::isPrimaryKey([])); - $this->assertFalse(OrderItem::isPrimaryKey(['order_id'])); - $this->assertFalse(OrderItem::isPrimaryKey(['item_id'])); - $this->assertFalse(OrderItem::isPrimaryKey(['quantity'])); - $this->assertFalse(OrderItem::isPrimaryKey(['quantity', 'subtotal'])); - $this->assertTrue(OrderItem::isPrimaryKey(['order_id', 'item_id'])); - $this->assertFalse(OrderItem::isPrimaryKey(['order_id', 'item_id', 'quantity'])); - } - - public function testJoinWith() - { - // left join and eager loading - $orders = Order::find()->joinWith('customer')->orderBy('customer.id DESC, order.id')->all(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, $orders[1]->id); - $this->assertEquals(1, $orders[2]->id); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[1]->isRelationPopulated('customer')); - $this->assertTrue($orders[2]->isRelationPopulated('customer')); - - // inner join filtering and eager loading - $orders = Order::find()->innerJoinWith([ - 'customer' => function ($query) { - $query->where('{{customer}}.[[id]]=2'); - }, - ])->orderBy('order.id')->all(); - $this->assertEquals(2, count($orders)); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, $orders[1]->id); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[1]->isRelationPopulated('customer')); - - // inner join filtering, eager loading, conditions on both primary and relation - $orders = Order::find()->innerJoinWith([ - 'customer' => function ($query) { - $query->where(['customer.id' => 2]); - }, - ])->where(['order.id' => [1, 2]])->orderBy('order.id')->all(); - $this->assertEquals(1, count($orders)); - $this->assertEquals(2, $orders[0]->id); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - - // inner join filtering without eager loading - $orders = Order::find()->innerJoinWith([ - 'customer' => function ($query) { - $query->where('{{customer}}.[[id]]=2'); - }, - ], false)->orderBy('order.id')->all(); - $this->assertEquals(2, count($orders)); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, $orders[1]->id); - $this->assertFalse($orders[0]->isRelationPopulated('customer')); - $this->assertFalse($orders[1]->isRelationPopulated('customer')); - - // inner join filtering without eager loading, conditions on both primary and relation - $orders = Order::find()->innerJoinWith([ - 'customer' => function ($query) { - $query->where(['customer.id' => 2]); - }, - ], false)->where(['order.id' => [1, 2]])->orderBy('order.id')->all(); - $this->assertEquals(1, count($orders)); - $this->assertEquals(2, $orders[0]->id); - $this->assertFalse($orders[0]->isRelationPopulated('customer')); - - // join with via-relation - $orders = Order::find()->innerJoinWith('books')->orderBy('order.id')->all(); - $this->assertEquals(2, count($orders)); - $this->assertEquals(1, $orders[0]->id); - $this->assertEquals(3, $orders[1]->id); - $this->assertTrue($orders[0]->isRelationPopulated('books')); - $this->assertTrue($orders[1]->isRelationPopulated('books')); - $this->assertEquals(2, count($orders[0]->books)); - $this->assertEquals(1, count($orders[1]->books)); - - // join with sub-relation - $orders = Order::find()->innerJoinWith([ - 'items' => function ($q) { - $q->orderBy('item.id'); - }, - 'items.category' => function ($q) { - $q->where('{{category}}.[[id]] = 2'); - }, - ])->orderBy('order.id')->all(); - $this->assertEquals(1, count($orders)); - $this->assertTrue($orders[0]->isRelationPopulated('items')); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, count($orders[0]->items)); - $this->assertTrue($orders[0]->items[0]->isRelationPopulated('category')); - $this->assertEquals(2, $orders[0]->items[0]->category->id); - - // join with table alias - $orders = Order::find()->joinWith([ - 'customer' => function ($q) { - $q->from('customer c'); - } - ])->orderBy('c.id DESC, order.id')->all(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, $orders[1]->id); - $this->assertEquals(1, $orders[2]->id); - $this->assertTrue($orders[0]->isRelationPopulated('customer')); - $this->assertTrue($orders[1]->isRelationPopulated('customer')); - $this->assertTrue($orders[2]->isRelationPopulated('customer')); - - // join with ON condition - $orders = Order::find()->joinWith('books2')->orderBy('order.id')->all(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(1, $orders[0]->id); - $this->assertEquals(2, $orders[1]->id); - $this->assertEquals(3, $orders[2]->id); - $this->assertTrue($orders[0]->isRelationPopulated('books2')); - $this->assertTrue($orders[1]->isRelationPopulated('books2')); - $this->assertTrue($orders[2]->isRelationPopulated('books2')); - $this->assertEquals(2, count($orders[0]->books2)); - $this->assertEquals(0, count($orders[1]->books2)); - $this->assertEquals(1, count($orders[2]->books2)); - - // lazy loading with ON condition - $order = Order::findOne(1); - $this->assertEquals(2, count($order->books2)); - $order = Order::findOne(2); - $this->assertEquals(0, count($order->books2)); - $order = Order::findOne(3); - $this->assertEquals(1, count($order->books2)); - - // eager loading with ON condition - $orders = Order::find()->with('books2')->all(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(1, $orders[0]->id); - $this->assertEquals(2, $orders[1]->id); - $this->assertEquals(3, $orders[2]->id); - $this->assertTrue($orders[0]->isRelationPopulated('books2')); - $this->assertTrue($orders[1]->isRelationPopulated('books2')); - $this->assertTrue($orders[2]->isRelationPopulated('books2')); - $this->assertEquals(2, count($orders[0]->books2)); - $this->assertEquals(0, count($orders[1]->books2)); - $this->assertEquals(1, count($orders[2]->books2)); - - // join with count and query - $query = Order::find()->joinWith('customer'); - $count = $query->count(); - $this->assertEquals(3, $count); - $orders = $query->all(); - $this->assertEquals(3, count($orders)); - - // https://github.com/yiisoft/yii2/issues/2880 - $query = Order::findOne(1); - $customer = $query->getCustomer()->joinWith([ - 'orders' => function ($q) { $q->orderBy([]); } - ])->one(); - $this->assertEquals(1, $customer->id); - $order = Order::find()->joinWith([ - 'items' => function ($q) { - $q->from(['items' => 'item']) - ->orderBy('items.id'); - }, - ])->orderBy('order.id')->one(); - - // join with sub-relation called inside Closure - $orders = Order::find()->joinWith([ - 'items' => function ($q) { - $q->orderBy('item.id'); - $q->joinWith([ - 'category'=> function ($q) { - $q->where('{{category}}.[[id]] = 2'); - } - ]); - }, - ])->orderBy('order.id')->all(); - $this->assertEquals(1, count($orders)); - $this->assertTrue($orders[0]->isRelationPopulated('items')); - $this->assertEquals(2, $orders[0]->id); - $this->assertEquals(3, count($orders[0]->items)); - $this->assertTrue($orders[0]->items[0]->isRelationPopulated('category')); - $this->assertEquals(2, $orders[0]->items[0]->category->id); - } - - public function testJoinWithAndScope() - { - // hasOne inner join - $customers = Customer::find()->active()->innerJoinWith('profile')->orderBy('customer.id')->all(); - $this->assertEquals(1, count($customers)); - $this->assertEquals(1, $customers[0]->id); - $this->assertTrue($customers[0]->isRelationPopulated('profile')); - - // hasOne outer join - $customers = Customer::find()->active()->joinWith('profile')->orderBy('customer.id')->all(); - $this->assertEquals(2, count($customers)); - $this->assertEquals(1, $customers[0]->id); - $this->assertEquals(2, $customers[1]->id); - $this->assertTrue($customers[0]->isRelationPopulated('profile')); - $this->assertTrue($customers[1]->isRelationPopulated('profile')); - $this->assertInstanceOf(Profile::className(), $customers[0]->profile); - $this->assertNull($customers[1]->profile); - - // hasMany - $customers = Customer::find()->active()->joinWith([ - 'orders' => function ($q) { - $q->orderBy('order.id'); - } - ])->orderBy('customer.id DESC, order.id')->all(); - $this->assertEquals(2, count($customers)); - $this->assertEquals(2, $customers[0]->id); - $this->assertEquals(1, $customers[1]->id); - $this->assertTrue($customers[0]->isRelationPopulated('orders')); - $this->assertTrue($customers[1]->isRelationPopulated('orders')); - } - - /** - * This query will do the same join twice, ensure duplicated JOIN gets removed - * https://github.com/yiisoft/yii2/pull/2650 - */ - public function testJoinWithVia() - { - Order::getDb()->getQueryBuilder()->separator = "\n"; - Order::find()->joinWith('itemsInOrder1')->joinWith([ - 'items' => function ($q) { - $q->orderBy('item.id'); - }, - ])->all(); - } - - public function testInverseOf() - { - // eager loading: find one and all - $customer = Customer::find()->with('orders2')->where(['id' => 1])->one(); - $this->assertTrue($customer->orders2[0]->customer2 === $customer); - $customers = Customer::find()->with('orders2')->where(['id' => [1, 3]])->all(); - $this->assertTrue($customers[0]->orders2[0]->customer2 === $customers[0]); - $this->assertTrue(empty($customers[1]->orders2)); - // lazy loading - $customer = Customer::findOne(2); - $orders = $customer->orders2; - $this->assertTrue(count($orders) === 2); - $this->assertTrue($customer->orders2[0]->customer2 === $customer); - $this->assertTrue($customer->orders2[1]->customer2 === $customer); - // ad-hoc lazy loading - $customer = Customer::findOne(2); - $orders = $customer->getOrders2()->all(); - $this->assertTrue(count($orders) === 2); - $this->assertTrue($customer->orders2[0]->customer2 === $customer); - $this->assertTrue($customer->orders2[1]->customer2 === $customer); - - // the other way around - $customer = Customer::find()->with('orders2')->where(['id' => 1])->asArray()->one(); - $this->assertTrue($customer['orders2'][0]['customer2']['id'] === $customer['id']); - $customers = Customer::find()->with('orders2')->where(['id' => [1, 3]])->asArray()->all(); - $this->assertTrue($customer['orders2'][0]['customer2']['id'] === $customers[0]['id']); - $this->assertTrue(empty($customers[1]['orders2'])); - - $orders = Order::find()->with('customer2')->where(['id' => 1])->all(); - $this->assertTrue($orders[0]->customer2->orders2 === [$orders[0]]); - $order = Order::find()->with('customer2')->where(['id' => 1])->one(); - $this->assertTrue($order->customer2->orders2 === [$order]); - - $orders = Order::find()->with('customer2')->where(['id' => 1])->asArray()->all(); - $this->assertTrue($orders[0]['customer2']['orders2'][0]['id'] === $orders[0]['id']); - $order = Order::find()->with('customer2')->where(['id' => 1])->asArray()->one(); - $this->assertTrue($order['customer2']['orders2'][0]['id'] === $orders[0]['id']); - - $orders = Order::find()->with('customer2')->where(['id' => [1, 3]])->all(); - $this->assertTrue($orders[0]->customer2->orders2 === [$orders[0]]); - $this->assertTrue($orders[1]->customer2->orders2 === [$orders[1]]); - - $orders = Order::find()->with('customer2')->where(['id' => [2, 3]])->orderBy('id')->all(); - $this->assertTrue($orders[0]->customer2->orders2 === $orders); - $this->assertTrue($orders[1]->customer2->orders2 === $orders); - - $orders = Order::find()->with('customer2')->where(['id' => [2, 3]])->orderBy('id')->asArray()->all(); - $this->assertTrue($orders[0]['customer2']['orders2'][0]['id'] === $orders[0]['id']); - $this->assertTrue($orders[0]['customer2']['orders2'][1]['id'] === $orders[1]['id']); - $this->assertTrue($orders[1]['customer2']['orders2'][0]['id'] === $orders[0]['id']); - $this->assertTrue($orders[1]['customer2']['orders2'][1]['id'] === $orders[1]['id']); - } - - public function testDefaultValues() - { - $model = new Type(); - $model->loadDefaultValues(); - $this->assertEquals(1, $model->int_col2); - $this->assertEquals('something', $model->char_col2); - $this->assertEquals(1.23, $model->float_col2); - $this->assertEquals(33.22, $model->numeric_col); - $this->assertEquals(true, $model->bool_col2); - - if ($this instanceof CubridActiveRecordTest) { - // cubrid has non-standard timestamp representation - $this->assertEquals('12:00:00 AM 01/01/2002', $model->time); - } else { - $this->assertEquals('2002-01-01 00:00:00', $model->time); - } - - $model = new Type(); - $model->char_col2 = 'not something'; - - $model->loadDefaultValues(); - $this->assertEquals('not something', $model->char_col2); - - $model = new Type(); - $model->char_col2 = 'not something'; - - $model->loadDefaultValues(false); - $this->assertEquals('something', $model->char_col2); - } - - public function testUnlinkAllViaTable() - { - /* @var $orderClass \yii\db\ActiveRecordInterface */ - $orderClass = $this->getOrderClass(); - /* @var $orderItemClass \yii\db\ActiveRecordInterface */ - $orderItemClass = $this->getOrderItemClass(); - /* @var $itemClass \yii\db\ActiveRecordInterface */ - $itemClass = $this->getItemClass(); - /* @var $orderItemsWithNullFKClass \yii\db\ActiveRecordInterface */ - $orderItemsWithNullFKClass = $this->getOrderItemWithNullFKmClass(); - - // via table with delete - /* @var $order Order */ - $order = $orderClass::findOne(1); - $this->assertEquals(2, count($order->booksViaTable)); - $orderItemCount = $orderItemClass::find()->count(); - $this->assertEquals(5, $itemClass::find()->count()); - $order->unlinkAll('booksViaTable', true); - $this->afterSave(); - $this->assertEquals(5, $itemClass::find()->count()); - $this->assertEquals($orderItemCount - 2, $orderItemClass::find()->count()); - $this->assertEquals(0, count($order->booksViaTable)); - - // via table without delete - $this->assertEquals(2, count($order->booksWithNullFKViaTable)); - $orderItemCount = $orderItemsWithNullFKClass::find()->count(); - $this->assertEquals(5, $itemClass::find()->count()); - $order->unlinkAll('booksWithNullFKViaTable',false); - $this->assertEquals(0, count($order->booksWithNullFKViaTable)); - $this->assertEquals(2,$orderItemsWithNullFKClass::find()->where(['AND', ['item_id' => [1, 2]], ['order_id' => null]])->count()); - $this->assertEquals($orderItemCount, $orderItemsWithNullFKClass::find()->count()); - $this->assertEquals(5, $itemClass::find()->count()); - } - - public function testCastValues() - { - $model = new Type(); - $model->int_col = 123; - $model->int_col2 = 456; - $model->smallint_col = 42; - $model->char_col = '1337'; - $model->char_col2 = 'test'; - $model->char_col3 = 'test123'; - $model->float_col = 3.742; - $model->float_col2 = 42.1337; - $model->bool_col = true; - $model->bool_col2 = false; - $model->save(false); - - /* @var $model Type */ - $model = Type::find()->one(); - $this->assertSame(123, $model->int_col); - $this->assertSame(456, $model->int_col2); - $this->assertSame(42, $model->smallint_col); - $this->assertSame('1337', trim($model->char_col)); - $this->assertSame('test', $model->char_col2); - $this->assertSame('test123', $model->char_col3); -// $this->assertSame(1337.42, $model->float_col); -// $this->assertSame(42.1337, $model->float_col2); -// $this->assertSame(true, $model->bool_col); -// $this->assertSame(false, $model->bool_col2); - } - - public function testIssues() - { - // https://github.com/yiisoft/yii2/issues/4938 - $category = Category::findOne(2); - $this->assertTrue($category instanceof Category); - $this->assertEquals(3, $category->getItems()->count()); - $this->assertEquals(1, $category->getLimitedItems()->count()); - $this->assertEquals(1, $category->getLimitedItems()->distinct(true)->count()); - - // https://github.com/yiisoft/yii2/issues/3197 - $orders = Order::find()->with('orderItems')->orderBy('id')->all(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(2, count($orders[0]->orderItems)); - $this->assertEquals(3, count($orders[1]->orderItems)); - $this->assertEquals(1, count($orders[2]->orderItems)); - $orders = Order::find()->with(['orderItems' => function ($q) { $q->indexBy('item_id'); }])->orderBy('id')->all(); - $this->assertEquals(3, count($orders)); - $this->assertEquals(2, count($orders[0]->orderItems)); - $this->assertEquals(3, count($orders[1]->orderItems)); - $this->assertEquals(1, count($orders[2]->orderItems)); - } - - public function testPopulateRecordCallWhenQueryingOnParentClass() - { - (new Cat())->save(false); - (new Dog())->save(false); - - $animal = Animal::find()->where(['type' => Dog::className()])->one(); - $this->assertEquals('bark', $animal->getDoes()); - - $animal = Animal::find()->where(['type' => Cat::className()])->one(); - $this->assertEquals('meow', $animal->getDoes()); - } -} diff --git a/tests/unit/framework/db/BatchQueryResultTest.php b/tests/unit/framework/db/BatchQueryResultTest.php deleted file mode 100644 index b5b10b3..0000000 --- a/tests/unit/framework/db/BatchQueryResultTest.php +++ /dev/null @@ -1,136 +0,0 @@ -getConnection(); - } - - public function testQuery() - { - $db = $this->getConnection(); - - // initialize property test - $query = new Query(); - $query->from('customer')->orderBy('id'); - $result = $query->batch(2, $db); - $this->assertTrue($result instanceof BatchQueryResult); - $this->assertEquals(2, $result->batchSize); - $this->assertTrue($result->query === $query); - - // normal query - $query = new Query(); - $query->from('customer')->orderBy('id'); - $allRows = []; - $batch = $query->batch(2, $db); - foreach ($batch as $rows) { - $allRows = array_merge($allRows, $rows); - } - $this->assertEquals(3, count($allRows)); - $this->assertEquals('user1', $allRows[0]['name']); - $this->assertEquals('user2', $allRows[1]['name']); - $this->assertEquals('user3', $allRows[2]['name']); - // rewind - $allRows = []; - foreach ($batch as $rows) { - $allRows = array_merge($allRows, $rows); - } - $this->assertEquals(3, count($allRows)); - // reset - $batch->reset(); - - // empty query - $query = new Query(); - $query->from('customer')->where(['id' => 100]); - $allRows = []; - $batch = $query->batch(2, $db); - foreach ($batch as $rows) { - $allRows = array_merge($allRows, $rows); - } - $this->assertEquals(0, count($allRows)); - - // query with index - $query = new Query(); - $query->from('customer')->indexBy('name'); - $allRows = []; - foreach ($query->batch(2, $db) as $rows) { - $allRows = array_merge($allRows, $rows); - } - $this->assertEquals(3, count($allRows)); - $this->assertEquals('address1', $allRows['user1']['address']); - $this->assertEquals('address2', $allRows['user2']['address']); - $this->assertEquals('address3', $allRows['user3']['address']); - - // each - $query = new Query(); - $query->from('customer')->orderBy('id'); - $allRows = []; - foreach ($query->each(100, $db) as $rows) { - $allRows[] = $rows; - } - $this->assertEquals(3, count($allRows)); - $this->assertEquals('user1', $allRows[0]['name']); - $this->assertEquals('user2', $allRows[1]['name']); - $this->assertEquals('user3', $allRows[2]['name']); - - // each with key - $query = new Query(); - $query->from('customer')->orderBy('id')->indexBy('name'); - $allRows = []; - foreach ($query->each(100, $db) as $key => $row) { - $allRows[$key] = $row; - } - $this->assertEquals(3, count($allRows)); - $this->assertEquals('address1', $allRows['user1']['address']); - $this->assertEquals('address2', $allRows['user2']['address']); - $this->assertEquals('address3', $allRows['user3']['address']); - } - - public function testActiveQuery() - { - $db = $this->getConnection(); - - $query = Customer::find()->orderBy('id'); - $customers = []; - foreach ($query->batch(2, $db) as $models) { - $customers = array_merge($customers, $models); - } - $this->assertEquals(3, count($customers)); - $this->assertEquals('user1', $customers[0]->name); - $this->assertEquals('user2', $customers[1]->name); - $this->assertEquals('user3', $customers[2]->name); - - // batch with eager loading - $query = Customer::find()->with('orders')->orderBy('id'); - $customers = []; - foreach ($query->batch(2, $db) as $models) { - $customers = array_merge($customers, $models); - foreach ($models as $model) { - $this->assertTrue($model->isRelationPopulated('orders')); - } - } - $this->assertEquals(3, count($customers)); - $this->assertEquals(1, count($customers[0]->orders)); - $this->assertEquals(2, count($customers[1]->orders)); - $this->assertEquals(0, count($customers[2]->orders)); - } -} diff --git a/tests/unit/framework/db/CommandTest.php b/tests/unit/framework/db/CommandTest.php deleted file mode 100644 index 21dd6f1..0000000 --- a/tests/unit/framework/db/CommandTest.php +++ /dev/null @@ -1,403 +0,0 @@ -getConnection(false); - - // null - $command = $db->createCommand(); - $this->assertEquals(null, $command->sql); - - // string - $sql = 'SELECT * FROM customer'; - $command = $db->createCommand($sql); - $this->assertEquals($sql, $command->sql); - } - - public function testGetSetSql() - { - $db = $this->getConnection(false); - - $sql = 'SELECT * FROM customer'; - $command = $db->createCommand($sql); - $this->assertEquals($sql, $command->sql); - - $sql2 = 'SELECT * FROM order'; - $command->sql = $sql2; - $this->assertEquals($sql2, $command->sql); - } - - public function testAutoQuoting() - { - $db = $this->getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; - $command = $db->createCommand($sql); - $this->assertEquals("SELECT `id`, `t`.`name` FROM `customer` t", $command->sql); - } - - public function testPrepareCancel() - { - $db = $this->getConnection(false); - - $command = $db->createCommand('SELECT * FROM {{customer}}'); - $this->assertEquals(null, $command->pdoStatement); - $command->prepare(); - $this->assertNotEquals(null, $command->pdoStatement); - $command->cancel(); - $this->assertEquals(null, $command->pdoStatement); - } - - public function testExecute() - { - $db = $this->getConnection(); - - $sql = 'INSERT INTO {{customer}}([[email]], [[name]], [[address]]) VALUES (\'user4@example.com\', \'user4\', \'address4\')'; - $command = $db->createCommand($sql); - $this->assertEquals(1, $command->execute()); - - $sql = 'SELECT COUNT(*) FROM {{customer}} WHERE [[name]] = \'user4\''; - $command = $db->createCommand($sql); - $this->assertEquals(1, $command->queryScalar()); - - $command = $db->createCommand('bad SQL'); - $this->setExpectedException('\yii\db\Exception'); - $command->execute(); - } - - public function testQuery() - { - $db = $this->getConnection(); - - // query - $sql = 'SELECT * FROM {{customer}}'; - $reader = $db->createCommand($sql)->query(); - $this->assertTrue($reader instanceof DataReader); - - // queryAll - $rows = $db->createCommand('SELECT * FROM {{customer}}')->queryAll(); - $this->assertEquals(3, count($rows)); - $row = $rows[2]; - $this->assertEquals(3, $row['id']); - $this->assertEquals('user3', $row['name']); - - $rows = $db->createCommand('SELECT * FROM {{customer}} WHERE [[id]] = 10')->queryAll(); - $this->assertEquals([], $rows); - - // queryOne - $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]'; - $row = $db->createCommand($sql)->queryOne(); - $this->assertEquals(1, $row['id']); - $this->assertEquals('user1', $row['name']); - - $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]'; - $command = $db->createCommand($sql); - $command->prepare(); - $row = $command->queryOne(); - $this->assertEquals(1, $row['id']); - $this->assertEquals('user1', $row['name']); - - $sql = 'SELECT * FROM {{customer}} WHERE [[id]] = 10'; - $command = $db->createCommand($sql); - $this->assertFalse($command->queryOne()); - - // queryColumn - $sql = 'SELECT * FROM {{customer}}'; - $column = $db->createCommand($sql)->queryColumn(); - $this->assertEquals(range(1, 3), $column); - - $command = $db->createCommand('SELECT [[id]] FROM {{customer}} WHERE [[id]] = 10'); - $this->assertEquals([], $command->queryColumn()); - - // queryScalar - $sql = 'SELECT * FROM {{customer}} ORDER BY [[id]]'; - $this->assertEquals($db->createCommand($sql)->queryScalar(), 1); - - $sql = 'SELECT [[id]] FROM {{customer}} ORDER BY [[id]]'; - $command = $db->createCommand($sql); - $command->prepare(); - $this->assertEquals(1, $command->queryScalar()); - - $command = $db->createCommand('SELECT [[id]] FROM {{customer}} WHERE [[id]] = 10'); - $this->assertFalse($command->queryScalar()); - - $command = $db->createCommand('bad SQL'); - $this->setExpectedException('\yii\db\Exception'); - $command->query(); - } - - public function testBindParamValue() - { - $db = $this->getConnection(); - - // bindParam - $sql = 'INSERT INTO {{customer}}([[email]], [[name]], [[address]]) VALUES (:email, :name, :address)'; - $command = $db->createCommand($sql); - $email = 'user4@example.com'; - $name = 'user4'; - $address = 'address4'; - $command->bindParam(':email', $email); - $command->bindParam(':name', $name); - $command->bindParam(':address', $address); - $command->execute(); - - $sql = 'SELECT [[name]] FROM {{customer}} WHERE [[email]] = :email'; - $command = $db->createCommand($sql); - $command->bindParam(':email', $email); - $this->assertEquals($name, $command->queryScalar()); - - $sql = <<createCommand($sql); - $intCol = 123; - $charCol = str_repeat('abc', 33) . 'x'; // a 100 char string - $boolCol = false; - $command->bindParam(':int_col', $intCol, \PDO::PARAM_INT); - $command->bindParam(':char_col', $charCol); - $command->bindParam(':bool_col', $boolCol, \PDO::PARAM_BOOL); - if ($this->driverName === 'oci') { - // can't bind floats without support from a custom PDO driver - $floatCol = 2; - $numericCol = 3; - // can't use blobs without support from a custom PDO driver - $blobCol = null; - $command->bindParam(':float_col', $floatCol, \PDO::PARAM_INT); - $command->bindParam(':numeric_col', $numericCol, \PDO::PARAM_INT); - $command->bindParam(':blob_col', $blobCol); - } else { - $floatCol = 1.23; - $numericCol = '1.23'; - $blobCol = "\x10\x11\x12"; - $command->bindParam(':float_col', $floatCol); - $command->bindParam(':numeric_col', $numericCol); - $command->bindParam(':blob_col', $blobCol); - } - $this->assertEquals(1, $command->execute()); - - $command = $db->createCommand('SELECT [[int_col]], [[char_col]], [[float_col]], [[blob_col]], [[numeric_col]], [[bool_col]] FROM {{type}}'); -// $command->prepare(); -// $command->pdoStatement->bindColumn('blob_col', $bc, \PDO::PARAM_LOB); - $row = $command->queryOne(); - $this->assertEquals($intCol, $row['int_col']); - $this->assertEquals($charCol, $row['char_col']); - $this->assertEquals($floatCol, $row['float_col']); - if ($this->driverName === 'mysql' || $this->driverName === 'sqlite' || $this->driverName === 'oci') { - $this->assertEquals($blobCol, $row['blob_col']); - } else { - $this->assertTrue(is_resource($row['blob_col'])); - $this->assertEquals($blobCol, stream_get_contents($row['blob_col'])); - } - $this->assertEquals($numericCol, $row['numeric_col']); - if ($this->driverName === 'mysql' || (defined('HHVM_VERSION') && $this->driverName === 'sqlite') || $this->driverName === 'oci') { - $this->assertEquals($boolCol, (int) $row['bool_col']); - } else { - $this->assertEquals($boolCol, $row['bool_col']); - } - - // bindValue - $sql = 'INSERT INTO {{customer}}([[email]], [[name]], [[address]]) VALUES (:email, \'user5\', \'address5\')'; - $command = $db->createCommand($sql); - $command->bindValue(':email', 'user5@example.com'); - $command->execute(); - - $sql = 'SELECT [[email]] FROM {{customer}} WHERE [[name]] = :name'; - $command = $db->createCommand($sql); - $command->bindValue(':name', 'user5'); - $this->assertEquals('user5@example.com', $command->queryScalar()); - } - - public function testFetchMode() - { - $db = $this->getConnection(); - - // default: FETCH_ASSOC - $sql = 'SELECT * FROM {{customer}}'; - $command = $db->createCommand($sql); - $result = $command->queryOne(); - $this->assertTrue(is_array($result) && isset($result['id'])); - - // FETCH_OBJ, customized via fetchMode property - $sql = 'SELECT * FROM {{customer}}'; - $command = $db->createCommand($sql); - $command->fetchMode = \PDO::FETCH_OBJ; - $result = $command->queryOne(); - $this->assertTrue(is_object($result)); - - // FETCH_NUM, customized in query method - $sql = 'SELECT * FROM {{customer}}'; - $command = $db->createCommand($sql); - $result = $command->queryOne([], \PDO::FETCH_NUM); - $this->assertTrue(is_array($result) && isset($result[0])); - } - - public function testBatchInsert() - { - $command = $this->getConnection()->createCommand(); - $command->batchInsert( - '{{customer}}', - ['email', 'name', 'address'], - [ - ['t1@example.com', 't1', 't1 address'], - ['t2@example.com', null, false], - ] - ); - $this->assertEquals(2, $command->execute()); - } - - /* - public function testInsert() - { - } - - public function testUpdate() - { - } - - public function testDelete() - { - } - - public function testCreateTable() - { - } - - public function testRenameTable() - { - } - - public function testDropTable() - { - } - - public function testTruncateTable() - { - } - - public function testAddColumn() - { - } - - public function testDropColumn() - { - } - - public function testRenameColumn() - { - } - - public function testAlterColumn() - { - } - - public function testAddForeignKey() - { - } - - public function testDropForeignKey() - { - } - - public function testCreateIndex() - { - } - - public function testDropIndex() - { - } - */ - - public function testIntegrityViolation() - { - $this->setExpectedException('\yii\db\IntegrityException'); - - $db = $this->getConnection(); - - $sql = 'INSERT INTO {{profile}}([[id]], [[description]]) VALUES (123, \'duplicate\')'; - $command = $db->createCommand($sql); - $command->execute(); - $command->execute(); - } - - public function testQueryCache() - { - $db = $this->getConnection(); - $db->enableQueryCache = true; - $db->queryCache = new FileCache(['cachePath' => '@yiiunit/runtime/cache']); - $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id'); - - $this->assertEquals('user1', $command->bindValue(':id', 1)->queryScalar()); - $update = $db->createCommand('UPDATE {{customer}} SET [[name]] = :name WHERE [[id]] = :id'); - $update->bindValues([':id' => 1, ':name' => 'user11'])->execute(); - $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar()); - - $db->cache(function (Connection $db) use ($command, $update) { - $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar()); - $update->bindValues([':id' => 2, ':name' => 'user22'])->execute(); - $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar()); - - $db->noCache(function () use ($command) { - $this->assertEquals('user22', $command->bindValue(':id', 2)->queryScalar()); - }); - - $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar()); - }, 10); - - $db->enableQueryCache = false; - $db->cache(function ($db) use ($command, $update) { - $this->assertEquals('user22', $command->bindValue(':id', 2)->queryScalar()); - $update->bindValues([':id' => 2, ':name' => 'user2'])->execute(); - $this->assertEquals('user2', $command->bindValue(':id', 2)->queryScalar()); - }, 10); - - $db->enableQueryCache = true; - $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id')->cache(); - $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar()); - $update->bindValues([':id' => 1, ':name' => 'user1'])->execute(); - $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar()); - $this->assertEquals('user1', $command->noCache()->bindValue(':id', 1)->queryScalar()); - - $command = $db->createCommand('SELECT [[name]] FROM {{customer}} WHERE [[id]] = :id'); - $db->cache(function (Connection $db) use ($command, $update) { - $this->assertEquals('user11', $command->bindValue(':id', 1)->queryScalar()); - $this->assertEquals('user1', $command->noCache()->bindValue(':id', 1)->queryScalar()); - }, 10); - } - - public function testColumnCase() - { - $db = $this->getConnection(false); - $this->assertEquals(\PDO::CASE_NATURAL, $db->slavePdo->getAttribute(\PDO::ATTR_CASE)); - - $sql = 'SELECT [[customer_id]], [[total]] FROM {{order}}'; - $rows = $db->createCommand($sql)->queryAll(); - $this->assertTrue(isset($rows[0])); - $this->assertTrue(isset($rows[0]['customer_id'])); - $this->assertTrue(isset($rows[0]['total'])); - - $db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER); - $rows = $db->createCommand($sql)->queryAll(); - $this->assertTrue(isset($rows[0])); - $this->assertTrue(isset($rows[0]['customer_id'])); - $this->assertTrue(isset($rows[0]['total'])); - - $db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_UPPER); - $rows = $db->createCommand($sql)->queryAll(); - $this->assertTrue(isset($rows[0])); - $this->assertTrue(isset($rows[0]['CUSTOMER_ID'])); - $this->assertTrue(isset($rows[0]['TOTAL'])); - } -} diff --git a/tests/unit/framework/db/ConnectionTest.php b/tests/unit/framework/db/ConnectionTest.php deleted file mode 100644 index d9084a3..0000000 --- a/tests/unit/framework/db/ConnectionTest.php +++ /dev/null @@ -1,169 +0,0 @@ -getConnection(false); - $params = $this->database; - - $this->assertEquals($params['dsn'], $connection->dsn); - $this->assertEquals($params['username'], $connection->username); - $this->assertEquals($params['password'], $connection->password); - } - - public function testOpenClose() - { - $connection = $this->getConnection(false, false); - - $this->assertFalse($connection->isActive); - $this->assertEquals(null, $connection->pdo); - - $connection->open(); - $this->assertTrue($connection->isActive); - $this->assertTrue($connection->pdo instanceof \PDO); - - $connection->close(); - $this->assertFalse($connection->isActive); - $this->assertEquals(null, $connection->pdo); - - $connection = new Connection; - $connection->dsn = 'unknown::memory:'; - $this->setExpectedException('yii\db\Exception'); - $connection->open(); - } - - public function testGetDriverName() - { - $connection = $this->getConnection(false, false); - $this->assertEquals($this->driverName, $connection->driverName); - } - - public function testQuoteValue() - { - $connection = $this->getConnection(false); - $this->assertEquals(123, $connection->quoteValue(123)); - $this->assertEquals("'string'", $connection->quoteValue('string')); - $this->assertEquals("'It\\'s interesting'", $connection->quoteValue("It's interesting")); - } - - public function testQuoteTableName() - { - $connection = $this->getConnection(false); - $this->assertEquals('`table`', $connection->quoteTableName('table')); - $this->assertEquals('`table`', $connection->quoteTableName('`table`')); - $this->assertEquals('`schema`.`table`', $connection->quoteTableName('schema.table')); - $this->assertEquals('`schema`.`table`', $connection->quoteTableName('schema.`table`')); - $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); - $this->assertEquals('(table)', $connection->quoteTableName('(table)')); - } - - public function testQuoteColumnName() - { - $connection = $this->getConnection(false); - $this->assertEquals('`column`', $connection->quoteColumnName('column')); - $this->assertEquals('`column`', $connection->quoteColumnName('`column`')); - $this->assertEquals('`table`.`column`', $connection->quoteColumnName('table.column')); - $this->assertEquals('`table`.`column`', $connection->quoteColumnName('table.`column`')); - $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); - $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); - $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); - } - - public function testTransaction() - { - $connection = $this->getConnection(false); - $this->assertNull($connection->transaction); - $transaction = $connection->beginTransaction(); - $this->assertNotNull($connection->transaction); - $this->assertTrue($transaction->isActive); - - $connection->createCommand()->insert('profile', ['description' => 'test transaction'])->execute(); - - $transaction->rollBack(); - $this->assertFalse($transaction->isActive); - $this->assertNull($connection->transaction); - - $this->assertEquals(0, $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction';")->queryScalar()); - - $transaction = $connection->beginTransaction(); - $connection->createCommand()->insert('profile', ['description' => 'test transaction'])->execute(); - $transaction->commit(); - $this->assertFalse($transaction->isActive); - $this->assertNull($connection->transaction); - - $this->assertEquals(1, $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction';")->queryScalar()); - } - - public function testTransactionIsolation() - { - $connection = $this->getConnection(true); - - $transaction = $connection->beginTransaction(Transaction::READ_UNCOMMITTED); - $transaction->commit(); - - $transaction = $connection->beginTransaction(Transaction::READ_COMMITTED); - $transaction->commit(); - - $transaction = $connection->beginTransaction(Transaction::REPEATABLE_READ); - $transaction->commit(); - - $transaction = $connection->beginTransaction(Transaction::SERIALIZABLE); - $transaction->commit(); - } - - /** - * @expectedException \Exception - */ - public function testTransactionShortcutException() - { - $connection = $this->getConnection(true); - $connection->transaction(function () use ($connection) { - $connection->createCommand()->insert('profile', ['description' => 'test transaction shortcut'])->execute(); - throw new \Exception('Exception in transaction shortcut'); - }); - - $profilesCount = $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction shortcut';")->queryScalar(); - $this->assertEquals(0, $profilesCount, 'profile should not be inserted in transaction shortcut'); - } - - public function testTransactionShortcutCorrect() - { - $connection = $this->getConnection(true); - - $result = $connection->transaction(function () use ($connection) { - $connection->createCommand()->insert('profile', ['description' => 'test transaction shortcut'])->execute(); - return true; - }); - - $this->assertTrue($result, 'transaction shortcut valid value should be returned from callback'); - - $profilesCount = $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction shortcut';")->queryScalar(); - $this->assertEquals(1, $profilesCount, 'profile should be inserted in transaction shortcut'); - } - - public function testTransactionShortcutCustom() - { - $connection = $this->getConnection(true); - - $result = $connection->transaction(function (Connection $db) { - $db->createCommand()->insert('profile', ['description' => 'test transaction shortcut'])->execute(); - return true; - }, Transaction::READ_UNCOMMITTED); - - $this->assertTrue($result, 'transaction shortcut valid value should be returned from callback'); - - $profilesCount = $connection->createCommand("SELECT COUNT(*) FROM profile WHERE description = 'test transaction shortcut';")->queryScalar(); - $this->assertEquals(1, $profilesCount, 'profile should be inserted in transaction shortcut'); - } - -} diff --git a/tests/unit/framework/db/DatabaseTestCase.php b/tests/unit/framework/db/DatabaseTestCase.php deleted file mode 100644 index e500e6c..0000000 --- a/tests/unit/framework/db/DatabaseTestCase.php +++ /dev/null @@ -1,92 +0,0 @@ -database = $databases[$this->driverName]; - $pdo_database = 'pdo_'.$this->driverName; - if ($this->driverName === 'oci') { - $pdo_database = 'oci8'; - } - - if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) { - $this->markTestSkipped('pdo and '.$pdo_database.' extension are required.'); - } - $this->mockApplication(); - } - - protected function tearDown() - { - if ($this->_db) { - $this->_db->close(); - } - $this->destroyApplication(); - } - - /** - * @param boolean $reset whether to clean up the test database - * @param boolean $open whether to open and populate test database - * @return \yii\db\Connection - */ - public function getConnection($reset = true, $open = true) - { - if (!$reset && $this->_db) { - return $this->_db; - } - $config = $this->database; - if (isset($config['fixture'])) { - $fixture = $config['fixture']; - unset($config['fixture']); - } else { - $fixture = null; - } - try { - $this->_db = $this->prepareDatabase($config, $fixture, $open); - } catch (\Exception $e) { - $this->markTestSkipped("Something wrong when preparing database: " . $e->getMessage()); - } - return $this->_db; - } - - public function prepareDatabase($config, $fixture, $open = true) - { - if (!isset($config['class'])) { - $config['class'] = 'yii\db\Connection'; - } - /* @var $db \yii\db\Connection */ - $db = \Yii::createObject($config); - if (!$open) { - return $db; - } - $db->open(); - if ($fixture !== null) { - if ($this->driverName === 'oci') { - list($drops, $creates) = explode('/* STATEMENTS */', file_get_contents($fixture), 2); - list($statements, $triggers, $data) = explode('/* TRIGGERS */', $creates, 3); - $lines = array_merge(explode('--', $drops), explode(';', $statements), explode('/', $triggers), explode(';', $data)); - } else { - $lines = explode(';', file_get_contents($fixture)); - } - foreach ($lines as $line) { - if (trim($line) !== '') { - $db->pdo->exec($line); - } - } - } - return $db; - } -} diff --git a/tests/unit/framework/db/QueryBuilderTest.php b/tests/unit/framework/db/QueryBuilderTest.php deleted file mode 100644 index 3c265e5..0000000 --- a/tests/unit/framework/db/QueryBuilderTest.php +++ /dev/null @@ -1,480 +0,0 @@ -driverName) { - case 'mysql': - return new MysqlQueryBuilder($this->getConnection(true, false)); - case 'sqlite': - return new SqliteQueryBuilder($this->getConnection(true, false)); - case 'mssql': - return new MssqlQueryBuilder($this->getConnection(true, false)); - case 'pgsql': - return new PgsqlQueryBuilder($this->getConnection(true, false)); - case 'cubrid': - return new CubridQueryBuilder($this->getConnection(true, false)); - } - throw new \Exception('Test is not implemented for ' . $this->driverName); - } - - /** - * adjust dbms specific escaping - * @param $sql - * @return mixed - */ - protected function replaceQuotes($sql) - { - if (!in_array($this->driverName, ['mssql', 'mysql', 'sqlite'])) { - return str_replace('`', '"', $sql); - } - return $sql; - } - - /** - * this is not used as a dataprovider for testGetColumnType to speed up the test - * when used as dataprovider every single line will cause a reconnect with the database which is not needed here - */ - public function columnTypes() - { - return [ - [Schema::TYPE_PK, 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY'], - [Schema::TYPE_PK . '(8)', 'int(8) NOT NULL AUTO_INCREMENT PRIMARY KEY'], - [Schema::TYPE_PK . ' CHECK (value > 5)', 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'int(8) NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_STRING, 'varchar(255)'], - [Schema::TYPE_STRING . '(32)', 'varchar(32)'], - [Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], - [Schema::TYPE_TEXT, 'text'], - [Schema::TYPE_TEXT . '(255)', 'text'], - [Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'], - [Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'], - [Schema::TYPE_SMALLINT, 'smallint(6)'], - [Schema::TYPE_SMALLINT . '(8)', 'smallint(8)'], - [Schema::TYPE_INTEGER, 'int(11)'], - [Schema::TYPE_INTEGER . '(8)', 'int(8)'], - [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'int(11) CHECK (value > 5)'], - [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'int(8) CHECK (value > 5)'], - [Schema::TYPE_INTEGER . ' NOT NULL', 'int(11) NOT NULL'], - [Schema::TYPE_BIGINT, 'bigint(20)'], - [Schema::TYPE_BIGINT . '(8)', 'bigint(8)'], - [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint(20) CHECK (value > 5)'], - [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint(8) CHECK (value > 5)'], - [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint(20) NOT NULL'], - [Schema::TYPE_FLOAT, 'float'], - [Schema::TYPE_FLOAT . '(16,5)', 'float'], - [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . ' NOT NULL', 'float NOT NULL'], - [Schema::TYPE_DOUBLE, 'double'], - [Schema::TYPE_DOUBLE . '(16,5)', 'double'], - [Schema::TYPE_DOUBLE . ' CHECK (value > 5.6)', 'double CHECK (value > 5.6)'], - [Schema::TYPE_DOUBLE . '(16,5) CHECK (value > 5.6)', 'double CHECK (value > 5.6)'], - [Schema::TYPE_DOUBLE . ' NOT NULL', 'double NOT NULL'], - [Schema::TYPE_DECIMAL, 'decimal(10,0)'], - [Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'], - [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'], - [Schema::TYPE_DATETIME, 'datetime'], - [Schema::TYPE_DATETIME . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'], - [Schema::TYPE_TIMESTAMP, 'timestamp'], - [Schema::TYPE_TIMESTAMP . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'], - [Schema::TYPE_TIME, 'time'], - [Schema::TYPE_TIME . " CHECK(value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK(value BETWEEN '12:00:00' AND '13:01:01')"], - [Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'], - [Schema::TYPE_DATE, 'date'], - [Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], - [Schema::TYPE_BINARY, 'blob'], - [Schema::TYPE_BOOLEAN, 'tinyint(1)'], - [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'tinyint(1) NOT NULL DEFAULT 1'], - [Schema::TYPE_MONEY, 'decimal(19,4)'], - [Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'], - [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'], - ]; - } - - public function testGetColumnType() - { - $qb = $this->getQueryBuilder(); - foreach ($this->columnTypes() as $item) { - list ($column, $expected) = $item; - $this->assertEquals($expected, $qb->getColumnType($column)); - } - } - - public function testCreateTableColumnTypes() - { - $qb = $this->getQueryBuilder(); - if ($qb->db->getTableSchema('column_type_table', true) !== null) { - $this->getConnection(false)->createCommand($qb->dropTable('column_type_table'))->execute(); - } - $columns = []; - $i = 0; - foreach ($this->columnTypes() as $item) { - list ($column, $expected) = $item; - if (strncmp($column, 'pk', 2) !== 0) { - $columns['col' . ++$i] = str_replace('CHECK (value', 'CHECK (col' . $i, $column); - } - } - $this->getConnection(false)->createCommand($qb->createTable('column_type_table', $columns))->execute(); - } - - public function conditionProvider() - { - $conditions = [ - // empty values - [ ['like', 'name', []], '0=1', [] ], - [ ['not like', 'name', []], '', [] ], - [ ['or like', 'name', []], '0=1', [] ], - [ ['or not like', 'name', []], '', [] ], - - // simple like - [ ['like', 'name', 'heyho'], '`name` LIKE :qp0', [':qp0' => '%heyho%'] ], - [ ['not like', 'name', 'heyho'], '`name` NOT LIKE :qp0', [':qp0' => '%heyho%'] ], - [ ['or like', 'name', 'heyho'], '`name` LIKE :qp0', [':qp0' => '%heyho%'] ], - [ ['or not like', 'name', 'heyho'], '`name` NOT LIKE :qp0', [':qp0' => '%heyho%'] ], - - // like for many values - [ ['like', 'name', ['heyho', 'abc']], '`name` LIKE :qp0 AND `name` LIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], - [ ['not like', 'name', ['heyho', 'abc']], '`name` NOT LIKE :qp0 AND `name` NOT LIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], - [ ['or like', 'name', ['heyho', 'abc']], '`name` LIKE :qp0 OR `name` LIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], - [ ['or not like', 'name', ['heyho', 'abc']], '`name` NOT LIKE :qp0 OR `name` NOT LIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], - - // like with Expression - [ ['like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` LIKE CONCAT("test", colname, "%")', [] ], - [ ['not like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` NOT LIKE CONCAT("test", colname, "%")', [] ], - [ ['or like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` LIKE CONCAT("test", colname, "%")', [] ], - [ ['or not like', 'name', new Expression('CONCAT("test", colname, "%")')], '`name` NOT LIKE CONCAT("test", colname, "%")', [] ], - [ ['like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` LIKE CONCAT("test", colname, "%") AND `name` LIKE :qp0', [':qp0' => '%abc%'] ], - [ ['not like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` NOT LIKE CONCAT("test", colname, "%") AND `name` NOT LIKE :qp0', [':qp0' => '%abc%'] ], - [ ['or like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` LIKE CONCAT("test", colname, "%") OR `name` LIKE :qp0', [':qp0' => '%abc%'] ], - [ ['or not like', 'name', [new Expression('CONCAT("test", colname, "%")'), 'abc']], '`name` NOT LIKE CONCAT("test", colname, "%") OR `name` NOT LIKE :qp0', [':qp0' => '%abc%'] ], - - // not - [ ['not', 'name'], 'NOT (name)', [] ], - - // and - [ ['and', 'id=1', 'id=2'], '(id=1) AND (id=2)', [] ], - [ ['and', 'type=1', ['or', 'id=1', 'id=2']], '(type=1) AND ((id=1) OR (id=2))', [] ], - - // or - [ ['or', 'id=1', 'id=2'], '(id=1) OR (id=2)', [] ], - [ ['or', 'type=1', ['or', 'id=1', 'id=2']], '(type=1) OR ((id=1) OR (id=2))', [] ], - - // between - [ ['between', 'id', 1, 10], '`id` BETWEEN :qp0 AND :qp1', [':qp0' => 1, ':qp1' => 10] ], - [ ['not between', 'id', 1, 10], '`id` NOT BETWEEN :qp0 AND :qp1', [':qp0' => 1, ':qp1' => 10] ], - [ ['between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), new Expression('NOW()')], '`date` BETWEEN (NOW() - INTERVAL 1 MONTH) AND NOW()', [] ], - [ ['between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), 123], '`date` BETWEEN (NOW() - INTERVAL 1 MONTH) AND :qp0', [':qp0' => 123] ], - [ ['not between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), new Expression('NOW()')], '`date` NOT BETWEEN (NOW() - INTERVAL 1 MONTH) AND NOW()', [] ], - [ ['not between', 'date', new Expression('(NOW() - INTERVAL 1 MONTH)'), 123], '`date` NOT BETWEEN (NOW() - INTERVAL 1 MONTH) AND :qp0', [':qp0' => 123] ], - - // in - [ ['in', 'id', [1, 2, 3]], '`id` IN (:qp0, :qp1, :qp2)', [':qp0' => 1, ':qp1' => 2, ':qp2' => 3] ], - [ ['not in', 'id', [1, 2, 3]], '`id` NOT IN (:qp0, :qp1, :qp2)', [':qp0' => 1, ':qp1' => 2, ':qp2' => 3] ], - [ ['in', 'id', (new Query())->select('id')->from('users')->where(['active' => 1])], '`id` IN (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], - [ ['not in', 'id', (new Query())->select('id')->from('users')->where(['active' => 1])], '`id` NOT IN (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], - - // exists - [ ['exists', (new Query())->select('id')->from('users')->where(['active' => 1])], 'EXISTS (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], - [ ['not exists', (new Query())->select('id')->from('users')->where(['active' => 1])], 'NOT EXISTS (SELECT `id` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], - - // simple conditions - [ ['=', 'a', 'b'], '`a` = :qp0', [':qp0' => 'b'] ], - [ ['>', 'a', 1], '`a` > :qp0', [':qp0' => 1] ], - [ ['>=', 'a', 'b'], '`a` >= :qp0', [':qp0' => 'b'] ], - [ ['<', 'a', 2], '`a` < :qp0', [':qp0' => 2] ], - [ ['<=', 'a', 'b'], '`a` <= :qp0', [':qp0' => 'b'] ], - [ ['<>', 'a', 3], '`a` <> :qp0', [':qp0' => 3] ], - [ ['!=', 'a', 'b'], '`a` != :qp0', [':qp0' => 'b'] ], - [ ['>=', 'date', new Expression('DATE_SUB(NOW(), INTERVAL 1 MONTH)')], '`date` >= DATE_SUB(NOW(), INTERVAL 1 MONTH)', [] ], - [ ['>=', 'date', new Expression('DATE_SUB(NOW(), INTERVAL :month MONTH)', [':month' => 2])], '`date` >= DATE_SUB(NOW(), INTERVAL :month MONTH)', [':month' => 2] ], - [ ['=', 'date', (new Query())->select('max(date)')->from('test')->where(['id' => 5])], '`date` = (SELECT max(date) FROM `test` WHERE `id`=:qp0)', [':qp0' => 5] ], - - // hash condition - [ ['a' => 1, 'b' => 2], '(`a`=:qp0) AND (`b`=:qp1)', [':qp0' => 1, ':qp1' => 2] ], - [ ['a' => new Expression('CONCAT(col1, col2)'), 'b' => 2], '(`a`=CONCAT(col1, col2)) AND (`b`=:qp0)', [':qp0' => 2] ], - - ]; - - switch ($this->driverName) { - case 'mssql': - case 'sqlite': - $conditions = array_merge($conditions, [ - [ ['in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '((`id` = :qp0 AND `name` = :qp1) OR (`id` = :qp2 AND `name` = :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ], - [ ['not in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '((`id` != :qp0 OR `name` != :qp1) AND (`id` != :qp2 OR `name` != :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ], - //[ ['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], 'EXISTS (SELECT 1 FROM (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0) AS a WHERE a.`id` = `id AND a.`name` = `name`)', [':qp0' => 1] ], - //[ ['not in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], 'NOT EXISTS (SELECT 1 FROM (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0) AS a WHERE a.`id` = `id` AND a.`name = `name`)', [':qp0' => 1] ], - ]); - break; - default: - $conditions = array_merge($conditions, [ - [ ['in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(`id`, `name`) IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ], - [ ['not in', ['id', 'name'], [['id' => 1, 'name' => 'foo'], ['id' => 2, 'name' => 'bar']]], '(`id`, `name`) NOT IN ((:qp0, :qp1), (:qp2, :qp3))', [':qp0' => 1, ':qp1' => 'foo', ':qp2' => 2, ':qp3' => 'bar'] ], - [ ['in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], '(`id`, `name`) IN (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], - [ ['not in', ['id', 'name'], (new Query())->select(['id', 'name'])->from('users')->where(['active' => 1])], '(`id`, `name`) NOT IN (SELECT `id`, `name` FROM `users` WHERE `active`=:qp0)', [':qp0' => 1] ], - ]); - break; - } - - // adjust dbms specific escaping - foreach($conditions as $i => $condition) { - $conditions[$i][1] = $this->replaceQuotes($condition[1]); - } - return $conditions; - } - - public function filterConditionProvider() - { - $conditions = [ - // like - [ ['like', 'name', []], '', [] ], - [ ['not like', 'name', []], '', [] ], - [ ['or like', 'name', []], '', [] ], - [ ['or not like', 'name', []], '', [] ], - - // not - [ ['not', ''], '', [] ], - - // and - [ ['and', '', ''], '', [] ], - [ ['and', '', 'id=2'], '(id=2)', [] ], - [ ['and', 'id=1', ''], '(id=1)', [] ], - [ ['and', 'type=1', ['or', '', 'id=2']], '(type=1) AND ((id=2))', [] ], - - // or - [ ['or', 'id=1', ''], '(id=1)', [] ], - [ ['or', 'type=1', ['or', '', 'id=2']], '(type=1) OR ((id=2))', [] ], - - - // between - [ ['between', 'id', 1, null], '', [] ], - [ ['not between', 'id', null, 10], '', [] ], - - // in - [ ['in', 'id', []], '', [] ], - [ ['not in', 'id', []], '', [] ], - - // simple conditions - [ ['=', 'a', ''], '', [] ], - [ ['>', 'a', ''], '', [] ], - [ ['>=', 'a', ''], '', [] ], - [ ['<', 'a', ''], '', [] ], - [ ['<=', 'a', ''], '', [] ], - [ ['<>', 'a', ''], '', [] ], - [ ['!=', 'a', ''], '', [] ], - ]; - - // adjust dbms specific escaping - foreach($conditions as $i => $condition) { - $conditions[$i][1] = $this->replaceQuotes($condition[1]); - } - return $conditions; - } - - /** - * @dataProvider conditionProvider - */ - public function testBuildCondition($condition, $expected, $expectedParams) - { - $query = (new Query())->where($condition); - list($sql, $params) = $this->getQueryBuilder()->build($query); - $this->assertEquals('SELECT *' . (empty($expected) ? '' : ' WHERE ' . $expected), $sql); - $this->assertEquals($expectedParams, $params); - } - - /** - * @dataProvider filterConditionProvider - */ - public function testBuildFilterCondition($condition, $expected, $expectedParams) - { - $query = (new Query())->filterWhere($condition); - list($sql, $params) = $this->getQueryBuilder()->build($query); - $this->assertEquals('SELECT *' . (empty($expected) ? '' : ' WHERE ' . $expected), $sql); - $this->assertEquals($expectedParams, $params); - } - - public function testAddDropPrimaryKey() - { - $tableName = 'constraints'; - $pkeyName = $tableName . "_pkey"; - - // ADD - $qb = $this->getQueryBuilder(); - $qb->db->createCommand()->addPrimaryKey($pkeyName, $tableName, ['id'])->execute(); - $tableSchema = $qb->db->getSchema()->getTableSchema($tableName); - $this->assertEquals(1, count($tableSchema->primaryKey)); - - //DROP - $qb->db->createCommand()->dropPrimaryKey($pkeyName, $tableName)->execute(); - $qb = $this->getQueryBuilder(); // resets the schema - $tableSchema = $qb->db->getSchema()->getTableSchema($tableName); - $this->assertEquals(0, count($tableSchema->primaryKey)); - } - - public function existsParamsProvider() - { - return [ - ['exists', $this->replaceQuotes("SELECT `id` FROM `TotalExample` `t` WHERE EXISTS (SELECT `1` FROM `Website` `w`)")], - ['not exists', $this->replaceQuotes("SELECT `id` FROM `TotalExample` `t` WHERE NOT EXISTS (SELECT `1` FROM `Website` `w`)")] - ]; - } - - /** - * @dataProvider existsParamsProvider - */ - public function testBuildWhereExists($cond, $expectedQuerySql) - { - $expectedQueryParams = []; - - $subQuery = new Query(); - $subQuery->select('1') - ->from('Website w'); - - $query = new Query(); - $query->select('id') - ->from('TotalExample t') - ->where([$cond, $subQuery]); - - list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query); - $this->assertEquals($expectedQuerySql, $actualQuerySql); - $this->assertEquals($expectedQueryParams, $actualQueryParams); - } - - - public function testBuildWhereExistsWithParameters() - { - $expectedQuerySql = $this->replaceQuotes( - "SELECT `id` FROM `TotalExample` `t` WHERE (EXISTS (SELECT `1` FROM `Website` `w` WHERE (w.id = t.website_id) AND (w.merchant_id = :merchant_id))) AND (t.some_column = :some_value)" - ); - $expectedQueryParams = [':some_value' => "asd", ':merchant_id' => 6]; - - $subQuery = new Query(); - $subQuery->select('1') - ->from('Website w') - ->where('w.id = t.website_id') - ->andWhere('w.merchant_id = :merchant_id', [':merchant_id' => 6]); - - $query = new Query(); - $query->select('id') - ->from('TotalExample t') - ->where(['exists', $subQuery]) - ->andWhere('t.some_column = :some_value', [':some_value' => "asd"]); - - list($actualQuerySql, $queryParams) = $this->getQueryBuilder()->build($query); - $this->assertEquals($expectedQuerySql, $actualQuerySql); - $this->assertEquals($expectedQueryParams, $queryParams); - } - - public function testBuildWhereExistsWithArrayParameters() - { - $expectedQuerySql = $this->replaceQuotes( - "SELECT `id` FROM `TotalExample` `t` WHERE (EXISTS (SELECT `1` FROM `Website` `w` WHERE (w.id = t.website_id) AND ((`w`.`merchant_id`=:qp0) AND (`w`.`user_id`=:qp1)))) AND (`t`.`some_column`=:qp2)" - ); - $expectedQueryParams = [':qp0' => 6, ':qp1' => 210, ':qp2' => 'asd']; - - $subQuery = new Query(); - $subQuery->select('1') - ->from('Website w') - ->where('w.id = t.website_id') - ->andWhere(['w.merchant_id' => 6, 'w.user_id' => '210']); - - $query = new Query(); - $query->select('id') - ->from('TotalExample t') - ->where(['exists', $subQuery]) - ->andWhere(['t.some_column' => "asd"]); - - list($actualQuerySql, $queryParams) = $this->getQueryBuilder()->build($query); - $this->assertEquals($expectedQuerySql, $actualQuerySql); - $this->assertEquals($expectedQueryParams, $queryParams); - } - - /** - * This test contains three select queries connected with UNION and UNION ALL constructions. - * It could be useful to use "phpunit --group=db --filter testBuildUnion" command for run it. - */ - public function testBuildUnion() - { - $expectedQuerySql = $this->replaceQuotes( - "(SELECT `id` FROM `TotalExample` `t1` WHERE (w > 0) AND (x < 2)) UNION ( SELECT `id` FROM `TotalTotalExample` `t2` WHERE w > 5 ) UNION ALL ( SELECT `id` FROM `TotalTotalExample` `t3` WHERE w = 3 )" - ); - $query = new Query(); - $secondQuery = new Query(); - $secondQuery->select('id') - ->from('TotalTotalExample t2') - ->where('w > 5'); - $thirdQuery = new Query(); - $thirdQuery->select('id') - ->from('TotalTotalExample t3') - ->where('w = 3'); - $query->select('id') - ->from('TotalExample t1') - ->where(['and', 'w > 0', 'x < 2']) - ->union($secondQuery) - ->union($thirdQuery, TRUE); - list($actualQuerySql, $queryParams) = $this->getQueryBuilder()->build($query); - $this->assertEquals($expectedQuerySql, $actualQuerySql); - $this->assertEquals([], $queryParams); - } - - public function testSelectSubquery() - { - $subquery = (new Query()) - ->select('COUNT(*)') - ->from('operations') - ->where('account_id = accounts.id'); - $query = (new Query()) - ->select('*') - ->from('accounts') - ->addSelect(['operations_count' => $subquery]); - list ($sql, $params) = $this->getQueryBuilder()->build($query); - $expected = $this->replaceQuotes('SELECT *, (SELECT COUNT(*) FROM `operations` WHERE account_id = accounts.id) AS `operations_count` FROM `accounts`'); - $this->assertEquals($expected, $sql); - $this->assertEmpty($params); - } - - public function testCompositeInCondition() - { - $condition = [ - 'in', - ['id', 'name'], - [ - ['id' => 1, 'name' => 'foo'], - ['id' => 2, 'name' => 'bar'], - ], - ]; - (new Query())->from('customer')->where($condition)->all($this->getConnection()); - } -} diff --git a/tests/unit/framework/db/QueryTest.php b/tests/unit/framework/db/QueryTest.php deleted file mode 100644 index 9af0781..0000000 --- a/tests/unit/framework/db/QueryTest.php +++ /dev/null @@ -1,239 +0,0 @@ -select('*'); - $this->assertEquals(['*'], $query->select); - $this->assertNull($query->distinct); - $this->assertEquals(null, $query->selectOption); - - $query = new Query; - $query->select('id, name', 'something')->distinct(true); - $this->assertEquals(['id', 'name'], $query->select); - $this->assertTrue($query->distinct); - $this->assertEquals('something', $query->selectOption); - - $query = new Query(); - $query->addSelect('email'); - $this->assertEquals(['email'], $query->select); - - $query = new Query(); - $query->select('id, name'); - $query->addSelect('email'); - $this->assertEquals(['id', 'name', 'email'], $query->select); - } - - public function testFrom() - { - $query = new Query; - $query->from('user'); - $this->assertEquals(['user'], $query->from); - } - - public function testWhere() - { - $query = new Query; - $query->where('id = :id', [':id' => 1]); - $this->assertEquals('id = :id', $query->where); - $this->assertEquals([':id' => 1], $query->params); - - $query->andWhere('name = :name', [':name' => 'something']); - $this->assertEquals(['and', 'id = :id', 'name = :name'], $query->where); - $this->assertEquals([':id' => 1, ':name' => 'something'], $query->params); - - $query->orWhere('age = :age', [':age' => '30']); - $this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->where); - $this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params); - } - - public function testFilterWhere() - { - // should work with hash format - $query = new Query; - $query->filterWhere([ - 'id' => 0, - 'title' => ' ', - 'author_ids' => [], - ]); - $this->assertEquals(['id' => 0], $query->where); - - $query->andFilterWhere(['status' => null]); - $this->assertEquals(['id' => 0], $query->where); - - $query->orFilterWhere(['name' => '']); - $this->assertEquals(['id' => 0], $query->where); - - // should work with operator format - $query = new Query; - $condition = ['like', 'name', 'Alex']; - $query->filterWhere($condition); - $this->assertEquals($condition, $query->where); - - $query->andFilterWhere(['between', 'id', null, null]); - $this->assertEquals($condition, $query->where); - - $query->orFilterWhere(['not between', 'id', null, null]); - $this->assertEquals($condition, $query->where); - - $query->andFilterWhere(['in', 'id', []]); - $this->assertEquals($condition, $query->where); - - $query->andFilterWhere(['not in', 'id', []]); - $this->assertEquals($condition, $query->where); - - $query->andFilterWhere(['not in', 'id', []]); - $this->assertEquals($condition, $query->where); - - $query->andFilterWhere(['like', 'id', '']); - $this->assertEquals($condition, $query->where); - - $query->andFilterWhere(['or like', 'id', '']); - $this->assertEquals($condition, $query->where); - - $query->andFilterWhere(['not like', 'id', ' ']); - $this->assertEquals($condition, $query->where); - - $query->andFilterWhere(['or not like', 'id', null]); - $this->assertEquals($condition, $query->where); - } - - public function testFilterRecursively() - { - $query = new Query(); - $query->filterWhere(['and', ['like', 'name', ''], ['like', 'title', ''], ['id' => 1], ['not', ['like', 'name', '']]]); - $this->assertEquals(['and', ['id' => 1]], $query->where); - } - - public function testJoin() - { - } - - public function testGroup() - { - $query = new Query; - $query->groupBy('team'); - $this->assertEquals(['team'], $query->groupBy); - - $query->addGroupBy('company'); - $this->assertEquals(['team', 'company'], $query->groupBy); - - $query->addGroupBy('age'); - $this->assertEquals(['team', 'company', 'age'], $query->groupBy); - } - - public function testHaving() - { - $query = new Query; - $query->having('id = :id', [':id' => 1]); - $this->assertEquals('id = :id', $query->having); - $this->assertEquals([':id' => 1], $query->params); - - $query->andHaving('name = :name', [':name' => 'something']); - $this->assertEquals(['and', 'id = :id', 'name = :name'], $query->having); - $this->assertEquals([':id' => 1, ':name' => 'something'], $query->params); - - $query->orHaving('age = :age', [':age' => '30']); - $this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->having); - $this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params); - } - - public function testOrder() - { - $query = new Query; - $query->orderBy('team'); - $this->assertEquals(['team' => SORT_ASC], $query->orderBy); - - $query->addOrderBy('company'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC], $query->orderBy); - - $query->addOrderBy('age'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_ASC], $query->orderBy); - - $query->addOrderBy(['age' => SORT_DESC]); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_ASC, 'age' => SORT_DESC], $query->orderBy); - - $query->addOrderBy('age ASC, company DESC'); - $this->assertEquals(['team' => SORT_ASC, 'company' => SORT_DESC, 'age' => SORT_ASC], $query->orderBy); - } - - public function testLimitOffset() - { - $query = new Query; - $query->limit(10)->offset(5); - $this->assertEquals(10, $query->limit); - $this->assertEquals(5, $query->offset); - } - - public function testUnion() - { - } - - public function testOne() - { - $db = $this->getConnection(); - - $result = (new Query)->from('customer')->where(['status' => 2])->one($db); - $this->assertEquals('user3', $result['name']); - - $result = (new Query)->from('customer')->where(['status' => 3])->one($db); - $this->assertFalse($result); - } - - public function testColumn() - { - $db = $this->getConnection(); - $result = (new Query)->select('name')->from('customer')->orderBy(['id' => SORT_DESC])->column($db); - $this->assertEquals(['user3', 'user2', 'user1'], $result); - - // https://github.com/yiisoft/yii2/issues/7515 - $result = (new Query)->from('customer') - ->select('name') - ->orderBy(['id' => SORT_DESC]) - ->indexBy('id') - ->column($db); - $this->assertEquals([3 => 'user3', 2 => 'user2', 1 => 'user1'], $result); - } - - public function testCount() - { - $db = $this->getConnection(); - - $count = (new Query)->from('customer')->count('*', $db); - $this->assertEquals(3, $count); - - $count = (new Query)->from('customer')->where(['status' => 2])->count('*', $db); - $this->assertEquals(1, $count); - - $count = (new Query)->select('status, COUNT(id)')->from('customer')->groupBy('status')->count('*', $db); - $this->assertEquals(2, $count); - } - - /** - * @see https://github.com/yiisoft/yii2/issues/8068 - * - * @depends testCount - */ - public function testCountHavingWithoutGroupBy() - { - if (!in_array($this->driverName, ['mysql'])) { - $this->markTestSkipped("{$this->driverName} does not support having without group by."); - } - - $db = $this->getConnection(); - - $count = (new Query)->from('customer')->having(['status' => 2])->count('*', $db); - $this->assertEquals(1, $count); - } -} diff --git a/tests/unit/framework/db/SchemaTest.php b/tests/unit/framework/db/SchemaTest.php deleted file mode 100644 index 1277faa..0000000 --- a/tests/unit/framework/db/SchemaTest.php +++ /dev/null @@ -1,336 +0,0 @@ -getConnection()->schema; - - $tables = $schema->getTableNames(); - $this->assertTrue(in_array('customer', $tables)); - $this->assertTrue(in_array('category', $tables)); - $this->assertTrue(in_array('item', $tables)); - $this->assertTrue(in_array('order', $tables)); - $this->assertTrue(in_array('order_item', $tables)); - $this->assertTrue(in_array('type', $tables)); - $this->assertTrue(in_array('animal', $tables)); - $this->assertTrue(in_array('animal_view', $tables)); - } - - public function testGetTableSchemas() - { - /* @var $schema Schema */ - $schema = $this->getConnection()->schema; - - $tables = $schema->getTableSchemas(); - $this->assertEquals(count($schema->getTableNames()), count($tables)); - foreach ($tables as $table) { - $this->assertInstanceOf('yii\db\TableSchema', $table); - } - } - - public function testGetTableSchemasWithAttrCase() - { - $db = $this->getConnection(false); - $db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_LOWER); - $this->assertEquals(count($db->schema->getTableNames()), count($db->schema->getTableSchemas())); - - $db->slavePdo->setAttribute(\PDO::ATTR_CASE, \PDO::CASE_UPPER); - $this->assertEquals(count($db->schema->getTableNames()), count($db->schema->getTableSchemas())); - } - - public function testGetNonExistingTableSchema() - { - $this->assertNull($this->getConnection()->schema->getTableSchema('nonexisting_table')); - } - - public function testSchemaCache() - { - /* @var $schema Schema */ - $schema = $this->getConnection()->schema; - - $schema->db->enableSchemaCache = true; - $schema->db->schemaCache = new FileCache(); - $noCacheTable = $schema->getTableSchema('type', true); - $cachedTable = $schema->getTableSchema('type', false); - $this->assertEquals($noCacheTable, $cachedTable); - } - - public function testCompositeFk() - { - /* @var $schema Schema */ - $schema = $this->getConnection()->schema; - - $table = $schema->getTableSchema('composite_fk'); - - $this->assertCount(1, $table->foreignKeys); - $this->assertTrue(isset($table->foreignKeys[0])); - $this->assertEquals('order_item', $table->foreignKeys[0][0]); - $this->assertEquals('order_id', $table->foreignKeys[0]['order_id']); - $this->assertEquals('item_id', $table->foreignKeys[0]['item_id']); - } - - public function testGetPDOType() - { - $values = [ - [null, \PDO::PARAM_NULL], - ['', \PDO::PARAM_STR], - ['hello', \PDO::PARAM_STR], - [0, \PDO::PARAM_INT], - [1, \PDO::PARAM_INT], - [1337, \PDO::PARAM_INT], - [true, \PDO::PARAM_BOOL], - [false, \PDO::PARAM_BOOL], - [$fp = fopen(__FILE__, 'rb'), \PDO::PARAM_LOB], - ]; - - /* @var $schema Schema */ - $schema = $this->getConnection()->schema; - - foreach ($values as $value) { - $this->assertEquals($value[1], $schema->getPdoType($value[0]), 'type for value ' . print_r($value[0], true) . ' does not match.'); - } - fclose($fp); - } - - public function getExpectedColumns() - { - return [ - 'int_col' => [ - 'type' => 'integer', - 'dbType' => 'int(11)', - 'phpType' => 'integer', - 'allowNull' => false, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => 11, - 'precision' => 11, - 'scale' => null, - 'defaultValue' => null, - ], - 'int_col2' => [ - 'type' => 'integer', - 'dbType' => 'int(11)', - 'phpType' => 'integer', - 'allowNull' => true, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => 11, - 'precision' => 11, - 'scale' => null, - 'defaultValue' => 1, - ], - 'smallint_col' => [ - 'type' => 'smallint', - 'dbType' => 'smallint(1)', - 'phpType' => 'integer', - 'allowNull' => true, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => 1, - 'precision' => 1, - 'scale' => null, - 'defaultValue' => 1, - ], - 'char_col' => [ - 'type' => 'string', - 'dbType' => 'char(100)', - 'phpType' => 'string', - 'allowNull' => false, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => 100, - 'precision' => 100, - 'scale' => null, - 'defaultValue' => null, - ], - 'char_col2' => [ - 'type' => 'string', - 'dbType' => 'varchar(100)', - 'phpType' => 'string', - 'allowNull' => true, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => 100, - 'precision' => 100, - 'scale' => null, - 'defaultValue' => 'something', - ], - 'char_col3' => [ - 'type' => 'text', - 'dbType' => 'text', - 'phpType' => 'string', - 'allowNull' => true, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => null, - 'precision' => null, - 'scale' => null, - 'defaultValue' => null, - ], - 'enum_col' => [ - 'type' => 'string', - 'dbType' => "enum('a','B')", - 'phpType' => 'string', - 'allowNull' => true, - 'autoIncrement' => false, - 'enumValues' => ['a', 'B'], - 'size' => null, - 'precision' => null, - 'scale' => null, - 'defaultValue' => null, - ], - 'float_col' => [ - 'type' => 'double', - 'dbType' => 'double(4,3)', - 'phpType' => 'double', - 'allowNull' => false, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => 4, - 'precision' => 4, - 'scale' => 3, - 'defaultValue' => null, - ], - 'float_col2' => [ - 'type' => 'double', - 'dbType' => 'double', - 'phpType' => 'double', - 'allowNull' => true, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => null, - 'precision' => null, - 'scale' => null, - 'defaultValue' => 1.23, - ], - 'blob_col' => [ - 'type' => 'binary', - 'dbType' => 'blob', - 'phpType' => 'resource', - 'allowNull' => true, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => null, - 'precision' => null, - 'scale' => null, - 'defaultValue' => null, - ], - 'numeric_col' => [ - 'type' => 'decimal', - 'dbType' => 'decimal(5,2)', - 'phpType' => 'string', - 'allowNull' => true, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => 5, - 'precision' => 5, - 'scale' => 2, - 'defaultValue' => '33.22', - ], - 'time' => [ - 'type' => 'timestamp', - 'dbType' => 'timestamp', - 'phpType' => 'string', - 'allowNull' => false, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => null, - 'precision' => null, - 'scale' => null, - 'defaultValue' => '2002-01-01 00:00:00', - ], - 'bool_col' => [ - 'type' => 'smallint', - 'dbType' => 'tinyint(1)', - 'phpType' => 'integer', - 'allowNull' => false, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => 1, - 'precision' => 1, - 'scale' => null, - 'defaultValue' => null, - ], - 'bool_col2' => [ - 'type' => 'smallint', - 'dbType' => 'tinyint(1)', - 'phpType' => 'integer', - 'allowNull' => true, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => 1, - 'precision' => 1, - 'scale' => null, - 'defaultValue' => 1, - ], - 'ts_default' => [ - 'type' => 'timestamp', - 'dbType' => 'timestamp', - 'phpType' => 'string', - 'allowNull' => false, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => null, - 'precision' => null, - 'scale' => null, - 'defaultValue' => new Expression('CURRENT_TIMESTAMP'), - ], - 'bit_col' => [ - 'type' => 'integer', - 'dbType' => 'bit(8)', - 'phpType' => 'integer', - 'allowNull' => false, - 'autoIncrement' => false, - 'enumValues' => null, - 'size' => 8, - 'precision' => 8, - 'scale' => null, - 'defaultValue' => 130, // b'10000010' - ], - ]; - } - - public function testColumnSchema() - { - $columns = $this->getExpectedColumns(); - - $table = $this->getConnection(false)->schema->getTableSchema('type', true); - - $expectedColNames = array_keys($columns); - sort($expectedColNames); - $colNames = $table->columnNames; - sort($colNames); - $this->assertEquals($expectedColNames, $colNames); - - foreach($table->columns as $name => $column) { - $expected = $columns[$name]; - $this->assertSame($expected['dbType'], $column->dbType, "dbType of colum $name does not match. type is $column->type, dbType is $column->dbType."); - $this->assertSame($expected['phpType'], $column->phpType, "phpType of colum $name does not match. type is $column->type, dbType is $column->dbType."); - $this->assertSame($expected['type'], $column->type, "type of colum $name does not match."); - $this->assertSame($expected['allowNull'], $column->allowNull, "allowNull of colum $name does not match."); - $this->assertSame($expected['autoIncrement'], $column->autoIncrement, "autoIncrement of colum $name does not match."); - $this->assertSame($expected['enumValues'], $column->enumValues, "enumValues of colum $name does not match."); - $this->assertSame($expected['size'], $column->size, "size of colum $name does not match."); - $this->assertSame($expected['precision'], $column->precision, "precision of colum $name does not match."); - $this->assertSame($expected['scale'], $column->scale, "scale of colum $name does not match."); - if (is_object($expected['defaultValue'])) { - $this->assertTrue(is_object($column->defaultValue), "defaultValue of colum $name is expected to be an object but it is not."); - $this->assertEquals((string) $expected['defaultValue'], (string) $column->defaultValue, "defaultValue of colum $name does not match."); - } else { - $this->assertSame($expected['defaultValue'], $column->defaultValue, "defaultValue of colum $name does not match."); - } - } - } -} diff --git a/tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php b/tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php deleted file mode 100644 index f01e69f..0000000 --- a/tests/unit/framework/db/cubrid/CubridActiveDataProviderTest.php +++ /dev/null @@ -1,14 +0,0 @@ -getConnection(); - - // bindParam - $sql = 'INSERT INTO customer(email, name, address) VALUES (:email, :name, :address)'; - $command = $db->createCommand($sql); - $email = 'user4@example.com'; - $name = 'user4'; - $address = 'address4'; - $command->bindParam(':email', $email); - $command->bindParam(':name', $name); - $command->bindParam(':address', $address); - $command->execute(); - - $sql = 'SELECT name FROM customer WHERE email=:email'; - $command = $db->createCommand($sql); - $command->bindParam(':email', $email); - $this->assertEquals($name, $command->queryScalar()); - - $sql = "INSERT INTO type (int_col, char_col, char_col2, enum_col, float_col, blob_col, numeric_col, bool_col) VALUES (:int_col, '', :char_col, :enum_col, :float_col, CHAR_TO_BLOB(:blob_col), :numeric_col, :bool_col)"; - $command = $db->createCommand($sql); - $intCol = 123; - $charCol = 'abc'; - $enumCol = 'a'; - $floatCol = 1.23; - $blobCol = "\x10\x11\x12"; - $numericCol = '1.23'; - $boolCol = true; - $command->bindParam(':int_col', $intCol); - $command->bindParam(':char_col', $charCol); - $command->bindParam(':enum_col', $enumCol); - $command->bindParam(':float_col', $floatCol); - $command->bindParam(':blob_col', $blobCol); - $command->bindParam(':numeric_col', $numericCol); - $command->bindParam(':bool_col', $boolCol); - $this->assertEquals(1, $command->execute()); - - $sql = 'SELECT * FROM type'; - $row = $db->createCommand($sql)->queryOne(); - $this->assertEquals($intCol, $row['int_col']); - $this->assertEquals($enumCol, $row['enum_col']); - $this->assertEquals($charCol, $row['char_col2']); - $this->assertEquals($floatCol, $row['float_col']); - $this->assertEquals($blobCol, fread($row['blob_col'], 3)); - $this->assertEquals($numericCol, $row['numeric_col']); - $this->assertEquals($boolCol, $row['bool_col']); - - // bindValue - $sql = 'INSERT INTO customer(email, name, address) VALUES (:email, \'user5\', \'address5\')'; - $command = $db->createCommand($sql); - $command->bindValue(':email', 'user5@example.com'); - $command->execute(); - - $sql = 'SELECT email FROM customer WHERE name=:name'; - $command = $db->createCommand($sql); - $command->bindValue(':name', 'user5'); - $this->assertEquals('user5@example.com', $command->queryScalar()); - } - - public function testAutoQuoting() - { - $db = $this->getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; - $command = $db->createCommand($sql); - $this->assertEquals('SELECT "id", "t"."name" FROM "customer" t', $command->sql); - } -} diff --git a/tests/unit/framework/db/cubrid/CubridConnectionTest.php b/tests/unit/framework/db/cubrid/CubridConnectionTest.php deleted file mode 100644 index 9b432d0..0000000 --- a/tests/unit/framework/db/cubrid/CubridConnectionTest.php +++ /dev/null @@ -1,44 +0,0 @@ -getConnection(false); - $this->assertEquals(123, $connection->quoteValue(123)); - $this->assertEquals("'string'", $connection->quoteValue('string')); - $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); - } - - public function testQuoteTableName() - { - $connection = $this->getConnection(false); - $this->assertEquals('"table"', $connection->quoteTableName('table')); - $this->assertEquals('"table"', $connection->quoteTableName('"table"')); - $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema.table')); - $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema."table"')); - $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); - $this->assertEquals('(table)', $connection->quoteTableName('(table)')); - } - - public function testQuoteColumnName() - { - $connection = $this->getConnection(false); - $this->assertEquals('"column"', $connection->quoteColumnName('column')); - $this->assertEquals('"column"', $connection->quoteColumnName('"column"')); - $this->assertEquals('"table"."column"', $connection->quoteColumnName('table.column')); - $this->assertEquals('"table"."column"', $connection->quoteColumnName('table."column"')); - $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); - $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); - $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); - } -} diff --git a/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php b/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php deleted file mode 100644 index 12d4c0b..0000000 --- a/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php +++ /dev/null @@ -1,82 +0,0 @@ - 5)', 'int NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'int NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_STRING, 'varchar(255)'], - [Schema::TYPE_STRING . '(32)', 'varchar(32)'], - [Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], - [Schema::TYPE_TEXT, 'varchar'], - [Schema::TYPE_TEXT . '(255)', 'varchar'], - [Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'varchar CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'varchar CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . ' NOT NULL', 'varchar NOT NULL'], - [Schema::TYPE_TEXT . '(255) NOT NULL', 'varchar NOT NULL'], - [Schema::TYPE_SMALLINT, 'smallint'], - [Schema::TYPE_SMALLINT . '(8)', 'smallint'], - [Schema::TYPE_INTEGER, 'int'], - [Schema::TYPE_INTEGER . '(8)', 'int'], - [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'int CHECK (value > 5)'], - [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'int CHECK (value > 5)'], - [Schema::TYPE_INTEGER . ' NOT NULL', 'int NOT NULL'], - [Schema::TYPE_BIGINT, 'bigint'], - [Schema::TYPE_BIGINT . '(8)', 'bigint'], - [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'], - [Schema::TYPE_FLOAT, 'float(7)'], - [Schema::TYPE_FLOAT . '(16)', 'float(16)'], - [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float(7) CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . '(16) CHECK (value > 5.6)', 'float(16) CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . ' NOT NULL', 'float(7) NOT NULL'], - [Schema::TYPE_DECIMAL, 'decimal(10,0)'], - [Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'], - [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'], - [Schema::TYPE_DATETIME, 'datetime'], - [Schema::TYPE_DATETIME . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'], - [Schema::TYPE_TIMESTAMP, 'timestamp'], - [Schema::TYPE_TIMESTAMP . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'], - [Schema::TYPE_TIME, 'time'], - [Schema::TYPE_TIME . " CHECK (value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK (value BETWEEN '12:00:00' AND '13:01:01')"], - [Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'], - [Schema::TYPE_DATE, 'date'], - [Schema::TYPE_DATE . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], - [Schema::TYPE_BINARY, 'blob'], - [Schema::TYPE_BOOLEAN, 'smallint'], - [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'smallint NOT NULL DEFAULT 1'], - [Schema::TYPE_MONEY, 'decimal(19,4)'], - [Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'], - [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'], - ]; - } -} diff --git a/tests/unit/framework/db/cubrid/CubridQueryTest.php b/tests/unit/framework/db/cubrid/CubridQueryTest.php deleted file mode 100644 index 50fe0d8..0000000 --- a/tests/unit/framework/db/cubrid/CubridQueryTest.php +++ /dev/null @@ -1,13 +0,0 @@ -getConnection()->schema; - - foreach ($values as $value) { - $this->assertEquals($value[1], $schema->getPdoType($value[0])); - } - fclose($fp); - } - - - public function getExpectedColumns() - { - $columns = parent::getExpectedColumns(); - $columns['int_col']['dbType'] = 'integer'; - $columns['int_col']['size'] = null; - $columns['int_col']['precision'] = null; - $columns['int_col2']['dbType'] = 'integer'; - $columns['int_col2']['size'] = null; - $columns['int_col2']['precision'] = null; - $columns['smallint_col']['dbType'] = 'short'; - $columns['smallint_col']['size'] = null; - $columns['smallint_col']['precision'] = null; - $columns['char_col3']['type'] = 'string'; - $columns['char_col3']['dbType'] = 'varchar(1073741823)'; - $columns['char_col3']['size'] = 1073741823; - $columns['char_col3']['precision'] = 1073741823; - $columns['enum_col']['dbType'] = "enum('a', 'B')"; - $columns['float_col']['dbType'] = 'double'; - $columns['float_col']['size'] = null; - $columns['float_col']['precision'] = null; - $columns['float_col']['scale'] = null; - $columns['numeric_col']['dbType'] = 'numeric(5,2)'; - $columns['blob_col']['phpType'] = 'resource'; - $columns['blob_col']['type'] = 'binary'; - $columns['bool_col']['dbType'] = 'short'; - $columns['bool_col']['size'] = null; - $columns['bool_col']['precision'] = null; - $columns['bool_col2']['dbType'] = 'short'; - $columns['bool_col2']['size'] = null; - $columns['bool_col2']['precision'] = null; - $columns['time']['defaultValue'] = '12:00:00 AM 01/01/2002'; - $columns['ts_default']['defaultValue'] = new Expression('SYS_TIMESTAMP'); - return $columns; - } -} diff --git a/tests/unit/framework/db/mssql/MssqlActiveDataProviderTest.php b/tests/unit/framework/db/mssql/MssqlActiveDataProviderTest.php deleted file mode 100644 index e9f4994..0000000 --- a/tests/unit/framework/db/mssql/MssqlActiveDataProviderTest.php +++ /dev/null @@ -1,14 +0,0 @@ -getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; - $command = $db->createCommand($sql); - $this->assertEquals("SELECT [id], [t].[name] FROM [customer] t", $command->sql); - } - - public function testPrepareCancel() - { - $this->markTestSkipped('MSSQL driver does not support this feature.'); - } - - public function testBindParamValue() - { - $db = $this->getConnection(); - - // bindParam - $sql = 'INSERT INTO customer(email, name, address) VALUES (:email, :name, :address)'; - $command = $db->createCommand($sql); - $email = 'user4@example.com'; - $name = 'user4'; - $address = 'address4'; - $command->bindParam(':email', $email); - $command->bindParam(':name', $name); - $command->bindParam(':address', $address); - $command->execute(); - - $sql = 'SELECT name FROM customer WHERE email=:email'; - $command = $db->createCommand($sql); - $command->bindParam(':email', $email); - $this->assertEquals($name, $command->queryScalar()); - - $sql = 'INSERT INTO type (int_col, char_col, float_col, blob_col, numeric_col, bool_col) VALUES (:int_col, :char_col, :float_col, CONVERT([varbinary], :blob_col), :numeric_col, :bool_col)'; - $command = $db->createCommand($sql); - $intCol = 123; - $charCol = 'abc'; - $floatCol = 1.23; - $blobCol = "\x10\x11\x12"; - $numericCol = '1.23'; - $boolCol = false; - $command->bindParam(':int_col', $intCol); - $command->bindParam(':char_col', $charCol); - $command->bindParam(':float_col', $floatCol); - $command->bindParam(':blob_col', $blobCol); - $command->bindParam(':numeric_col', $numericCol); - $command->bindParam(':bool_col', $boolCol); - $this->assertEquals(1, $command->execute()); - - $sql = 'SELECT int_col, char_col, float_col, CONVERT([nvarchar], blob_col) AS blob_col, numeric_col FROM type'; - $row = $db->createCommand($sql)->queryOne(); - $this->assertEquals($intCol, $row['int_col']); - $this->assertEquals($charCol, trim($row['char_col'])); - $this->assertEquals($floatCol, $row['float_col']); - $this->assertEquals($blobCol, $row['blob_col']); - $this->assertEquals($numericCol, $row['numeric_col']); - - // bindValue - $sql = 'INSERT INTO customer(email, name, address) VALUES (:email, \'user5\', \'address5\')'; - $command = $db->createCommand($sql); - $command->bindValue(':email', 'user5@example.com'); - $command->execute(); - - $sql = 'SELECT email FROM customer WHERE name=:name'; - $command = $db->createCommand($sql); - $command->bindValue(':name', 'user5'); - $this->assertEquals('user5@example.com', $command->queryScalar()); - } -} diff --git a/tests/unit/framework/db/mssql/MssqlConnectionTest.php b/tests/unit/framework/db/mssql/MssqlConnectionTest.php deleted file mode 100644 index 02f7bfd..0000000 --- a/tests/unit/framework/db/mssql/MssqlConnectionTest.php +++ /dev/null @@ -1,45 +0,0 @@ -getConnection(false); - $this->assertEquals(123, $connection->quoteValue(123)); - $this->assertEquals("'string'", $connection->quoteValue('string')); - $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); - } - - public function testQuoteTableName() - { - $connection = $this->getConnection(false); - $this->assertEquals('[table]', $connection->quoteTableName('table')); - $this->assertEquals('[table]', $connection->quoteTableName('[table]')); - $this->assertEquals('[schema].[table]', $connection->quoteTableName('schema.table')); - $this->assertEquals('[schema].[table]', $connection->quoteTableName('schema.[table]')); - $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); - $this->assertEquals('(table)', $connection->quoteTableName('(table)')); - } - - public function testQuoteColumnName() - { - $connection = $this->getConnection(false); - $this->assertEquals('[column]', $connection->quoteColumnName('column')); - $this->assertEquals('[column]', $connection->quoteColumnName('[column]')); - $this->assertEquals('[table].[column]', $connection->quoteColumnName('table.column')); - $this->assertEquals('[table].[column]', $connection->quoteColumnName('table.[column]')); - $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); - $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); - $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); - } -} diff --git a/tests/unit/framework/db/mssql/MssqlQueryBuilderTest.php b/tests/unit/framework/db/mssql/MssqlQueryBuilderTest.php deleted file mode 100644 index 987d6a4..0000000 --- a/tests/unit/framework/db/mssql/MssqlQueryBuilderTest.php +++ /dev/null @@ -1,57 +0,0 @@ -select('id')->from('example')->limit(10)->offset(5); - - list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query); - - $this->assertEquals($expectedQuerySql, $actualQuerySql); - $this->assertEquals($expectedQueryParams, $actualQueryParams); - } - - public function testLimit() - { - $expectedQuerySql = 'SELECT `id` FROM `exapmle` OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; - $expectedQueryParams = null; - - $query = new Query(); - $query->select('id')->from('example')->limit(10); - - list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query); - - $this->assertEquals($expectedQuerySql, $actualQuerySql); - $this->assertEquals($expectedQueryParams, $actualQueryParams); - } - - public function testOffset() - { - $expectedQuerySql = 'SELECT `id` FROM `exapmle` OFFSET 10 ROWS'; - $expectedQueryParams = null; - - $query = new Query(); - $query->select('id')->from('example')->offset(10); - - list($actualQuerySql, $actualQueryParams) = $this->getQueryBuilder()->build($query); - - $this->assertEquals($expectedQuerySql, $actualQuerySql); - $this->assertEquals($expectedQueryParams, $actualQueryParams); - } -} diff --git a/tests/unit/framework/db/mssql/MssqlQueryTest.php b/tests/unit/framework/db/mssql/MssqlQueryTest.php deleted file mode 100644 index 89830d0..0000000 --- a/tests/unit/framework/db/mssql/MssqlQueryTest.php +++ /dev/null @@ -1,14 +0,0 @@ -int_col = 123; - $model->int_col2 = 456; - $model->smallint_col = 42; - $model->char_col = '1337'; - $model->char_col2 = 'test'; - $model->char_col3 = 'test123'; - $model->float_col = 3.742; - $model->float_col2 = 42.1337; - $model->bool_col = 1; - $model->bool_col2 = 0; - $model->save(false); - - /* @var $model Type */ - $model = Type::find()->one(); - $this->assertSame(123, $model->int_col); - $this->assertSame(456, $model->int_col2); - $this->assertSame(42, $model->smallint_col); - $this->assertSame('1337', trim($model->char_col)); - $this->assertSame('test', $model->char_col2); - $this->assertSame('test123', $model->char_col3); -// $this->assertSame(1337.42, $model->float_col); -// $this->assertSame(42.1337, $model->float_col2); -// $this->assertSame(true, $model->bool_col); -// $this->assertSame(false, $model->bool_col2); - } - - public function testDefaultValues() - { - $model = new Type(); - $model->loadDefaultValues(); - $this->assertEquals(1, $model->int_col2); - $this->assertEquals('something', $model->char_col2); - $this->assertEquals(1.23, $model->float_col2); - $this->assertEquals(33.22, $model->numeric_col); - $this->assertEquals(true, $model->bool_col2); - - // not testing $model->time, because oci\Schema can't read default value - - $model = new Type(); - $model->char_col2 = 'not something'; - - $model->loadDefaultValues(); - $this->assertEquals('not something', $model->char_col2); - - $model = new Type(); - $model->char_col2 = 'not something'; - - $model->loadDefaultValues(false); - $this->assertEquals('something', $model->char_col2); - } - - public function testFindAsArray() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - // asArray - $customer = $customerClass::find()->where(['id' => 2])->asArray()->one(); - $this->assertEquals([ - 'id' => 2, - 'email' => 'user2@example.com', - 'name' => 'user2', - 'address' => 'address2', - 'status' => 1, - 'profile_id' => null, - 'bool_status' => true, - ], $customer); - - // find all asArray - $customers = $customerClass::find()->asArray()->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers[0]); - $this->assertArrayHasKey('name', $customers[0]); - $this->assertArrayHasKey('email', $customers[0]); - $this->assertArrayHasKey('address', $customers[0]); - $this->assertArrayHasKey('status', $customers[0]); - $this->assertArrayHasKey('bool_status', $customers[0]); - $this->assertArrayHasKey('id', $customers[1]); - $this->assertArrayHasKey('name', $customers[1]); - $this->assertArrayHasKey('email', $customers[1]); - $this->assertArrayHasKey('address', $customers[1]); - $this->assertArrayHasKey('status', $customers[1]); - $this->assertArrayHasKey('bool_status', $customers[1]); - $this->assertArrayHasKey('id', $customers[2]); - $this->assertArrayHasKey('name', $customers[2]); - $this->assertArrayHasKey('email', $customers[2]); - $this->assertArrayHasKey('address', $customers[2]); - $this->assertArrayHasKey('status', $customers[2]); - $this->assertArrayHasKey('bool_status', $customers[2]); - } -} diff --git a/tests/unit/framework/db/oci/OracleCommandTest.php b/tests/unit/framework/db/oci/OracleCommandTest.php deleted file mode 100644 index aed38a3..0000000 --- a/tests/unit/framework/db/oci/OracleCommandTest.php +++ /dev/null @@ -1,22 +0,0 @@ -getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; - $command = $db->createCommand($sql); - $this->assertEquals('SELECT "id", "t"."name" FROM "customer" t', $command->sql); - } -} diff --git a/tests/unit/framework/db/oci/OracleQueryTest.php b/tests/unit/framework/db/oci/OracleQueryTest.php deleted file mode 100644 index 4c0e50f..0000000 --- a/tests/unit/framework/db/oci/OracleQueryTest.php +++ /dev/null @@ -1,25 +0,0 @@ -getConnection(); - - $result = (new Query)->from('customer')->where(['[[status]]' => 2])->one($db); - $this->assertEquals('user3', $result['name']); - - $result = (new Query)->from('customer')->where(['[[status]]' => 3])->one($db); - $this->assertFalse($result); - } -} diff --git a/tests/unit/framework/db/oci/OracleSchemaTest.php b/tests/unit/framework/db/oci/OracleSchemaTest.php deleted file mode 100644 index 747d06e..0000000 --- a/tests/unit/framework/db/oci/OracleSchemaTest.php +++ /dev/null @@ -1,97 +0,0 @@ -getConnection(false)->schema->getTableSchema('order', true); - $this->assertSame(false, $table->columns['id']->autoIncrement); - } -} diff --git a/tests/unit/framework/db/pgsql/PostgreSQLActiveDataProviderTest.php b/tests/unit/framework/db/pgsql/PostgreSQLActiveDataProviderTest.php deleted file mode 100644 index 081f680..0000000 --- a/tests/unit/framework/db/pgsql/PostgreSQLActiveDataProviderTest.php +++ /dev/null @@ -1,14 +0,0 @@ -getCustomerClass(); - /* @var $this TestCase|ActiveRecordTestTrait */ - $customer = new $customerClass(); - $customer->name = 'boolean customer'; - $customer->email = 'mail@example.com'; - $customer->bool_status = false; - $customer->save(false); - - $customer->refresh(); - $this->assertSame(false, $customer->bool_status); - - $customer->bool_status = true; - $customer->save(false); - - $customer->refresh(); - $this->assertSame(true, $customer->bool_status); - - $customers = $customerClass::find()->where(['bool_status' => true])->all(); - $this->assertEquals(3, count($customers)); - - $customers = $customerClass::find()->where(['bool_status' => false])->all(); - $this->assertEquals(1, count($customers)); - } - - public function testFindAsArray() - { - /* @var $customerClass \yii\db\ActiveRecordInterface */ - $customerClass = $this->getCustomerClass(); - - // asArray - $customer = $customerClass::find()->where(['id' => 2])->asArray()->one(); - $this->assertEquals([ - 'id' => 2, - 'email' => 'user2@example.com', - 'name' => 'user2', - 'address' => 'address2', - 'status' => 1, - 'profile_id' => null, - 'bool_status' => true, - ], $customer); - - // find all asArray - $customers = $customerClass::find()->asArray()->all(); - $this->assertEquals(3, count($customers)); - $this->assertArrayHasKey('id', $customers[0]); - $this->assertArrayHasKey('name', $customers[0]); - $this->assertArrayHasKey('email', $customers[0]); - $this->assertArrayHasKey('address', $customers[0]); - $this->assertArrayHasKey('status', $customers[0]); - $this->assertArrayHasKey('bool_status', $customers[0]); - $this->assertArrayHasKey('id', $customers[1]); - $this->assertArrayHasKey('name', $customers[1]); - $this->assertArrayHasKey('email', $customers[1]); - $this->assertArrayHasKey('address', $customers[1]); - $this->assertArrayHasKey('status', $customers[1]); - $this->assertArrayHasKey('bool_status', $customers[1]); - $this->assertArrayHasKey('id', $customers[2]); - $this->assertArrayHasKey('name', $customers[2]); - $this->assertArrayHasKey('email', $customers[2]); - $this->assertArrayHasKey('address', $customers[2]); - $this->assertArrayHasKey('status', $customers[2]); - $this->assertArrayHasKey('bool_status', $customers[2]); - } - - public function testBooleanValues() - { - $db = $this->getConnection(); - $command = $db->createCommand(); - $command->batchInsert('bool_values', - ['bool_col'], [ - [true], - [false], - ] - )->execute(); - - $this->assertEquals(1, BoolAR::find()->where('bool_col = TRUE')->count('*', $db)); - $this->assertEquals(1, BoolAR::find()->where('bool_col = FALSE')->count('*', $db)); - $this->assertEquals(2, BoolAR::find()->where('bool_col IN (TRUE, FALSE)')->count('*', $db)); - - $this->assertEquals(1, BoolAR::find()->where(['bool_col' => true])->count('*', $db)); - $this->assertEquals(1, BoolAR::find()->where(['bool_col' => false])->count('*', $db)); - $this->assertEquals(2, BoolAR::find()->where(['bool_col' => [true, false]])->count('*', $db)); - - $this->assertEquals(1, BoolAR::find()->where('bool_col = :bool_col', ['bool_col' => true])->count('*', $db)); - $this->assertEquals(1, BoolAR::find()->where('bool_col = :bool_col', ['bool_col' => false])->count('*', $db)); - - $this->assertSame(true, BoolAR::find()->where(['bool_col' => true])->one($db)->bool_col); - $this->assertSame(false, BoolAR::find()->where(['bool_col' => false])->one($db)->bool_col); - } - - /** - * https://github.com/yiisoft/yii2/issues/4672 - */ - public function testBooleanValues2() - { - $db = $this->getConnection(); - $db->charset = 'utf8'; - - $db->createCommand("DROP TABLE IF EXISTS bool_user;")->execute(); - $db->createCommand()->createTable('bool_user', [ - 'id' => Schema::TYPE_PK, - 'username' => Schema::TYPE_STRING . ' NOT NULL', - 'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL', - 'password_hash' => Schema::TYPE_STRING . ' NOT NULL', - 'password_reset_token' => Schema::TYPE_STRING, - 'email' => Schema::TYPE_STRING . ' NOT NULL', - 'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10', - - 'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10', - 'created_at' => Schema::TYPE_INTEGER . ' NOT NULL', - 'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL', - ])->execute(); - $db->createCommand()->addColumn('bool_user', 'is_deleted', Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT FALSE')->execute(); - - $user = new UserAR(); - $user->username = 'test'; - $user->auth_key = 'test'; - $user->password_hash = 'test'; - $user->email = 'test@example.com'; - $user->save(false); - - $this->assertEquals(1, count(UserAR::find()->where(['is_deleted' => false])->all($db))); - $this->assertEquals(0, count(UserAR::find()->where(['is_deleted' => true])->all($db))); - $this->assertEquals(1, count(UserAR::find()->where(['is_deleted' => [true, false]])->all($db))); - } - - public function testBooleanDefaultValues() - { - $model = new BoolAR(); - $this->assertNull($model->bool_col); - $this->assertNull($model->default_true); - $this->assertNull($model->default_false); - $model->loadDefaultValues(); - $this->assertNull($model->bool_col); - $this->assertSame(true, $model->default_true); - $this->assertSame(false, $model->default_false); - - $this->assertTrue($model->save(false)); - } -} - -class BoolAR extends ActiveRecord -{ - public static function tableName() - { - return 'bool_values'; - } -} - -class UserAR extends ActiveRecord -{ - const STATUS_DELETED = 0; - const STATUS_ACTIVE = 10; - const ROLE_USER = 10; - - public static function tableName() - { - return '{{%bool_user}}'; - } - - public function behaviors() - { - return [ - TimestampBehavior::className(), - ]; - } -} - diff --git a/tests/unit/framework/db/pgsql/PostgreSQLCommandTest.php b/tests/unit/framework/db/pgsql/PostgreSQLCommandTest.php deleted file mode 100644 index 1382bd7..0000000 --- a/tests/unit/framework/db/pgsql/PostgreSQLCommandTest.php +++ /dev/null @@ -1,57 +0,0 @@ -getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; - $command = $db->createCommand($sql); - $this->assertEquals('SELECT "id", "t"."name" FROM "customer" t', $command->sql); - } - - public function testBooleanValuesInsert() - { - $db = $this->getConnection(); - $command = $db->createCommand(); - $command->insert('bool_values', ['bool_col' => true]); - $this->assertEquals(1, $command->execute()); - - $command = $db->createCommand(); - $command->insert('bool_values', ['bool_col' => false]); - $this->assertEquals(1, $command->execute()); - - $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = TRUE;'); - $this->assertEquals(1, $command->queryScalar()); - $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = FALSE;'); - $this->assertEquals(1, $command->queryScalar()); - } - - public function testBooleanValuesBatchInsert() - { - $db = $this->getConnection(); - $command = $db->createCommand(); - $command->batchInsert('bool_values', - ['bool_col'], [ - [true], - [false], - ] - ); - $this->assertEquals(2, $command->execute()); - - $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = TRUE;'); - $this->assertEquals(1, $command->queryScalar()); - $command = $db->createCommand('SELECT COUNT(*) FROM "bool_values" WHERE bool_col = FALSE;'); - $this->assertEquals(1, $command->queryScalar()); - } -} \ No newline at end of file diff --git a/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php b/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php deleted file mode 100644 index c569a44..0000000 --- a/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php +++ /dev/null @@ -1,77 +0,0 @@ -getConnection(true); - } - - public function testQuoteValue() - { - $connection = $this->getConnection(false); - $this->assertEquals(123, $connection->quoteValue(123)); - $this->assertEquals("'string'", $connection->quoteValue('string')); - $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); - } - - public function testQuoteTableName() - { - $connection = $this->getConnection(false); - $this->assertEquals('"table"', $connection->quoteTableName('table')); - $this->assertEquals('"table"', $connection->quoteTableName('"table"')); - $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema.table')); - $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema."table"')); - $this->assertEquals('"schema"."table"', $connection->quoteTableName('"schema"."table"')); - $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); - $this->assertEquals('(table)', $connection->quoteTableName('(table)')); - } - - public function testQuoteColumnName() - { - $connection = $this->getConnection(false); - $this->assertEquals('"column"', $connection->quoteColumnName('column')); - $this->assertEquals('"column"', $connection->quoteColumnName('"column"')); - $this->assertEquals('"table"."column"', $connection->quoteColumnName('table.column')); - $this->assertEquals('"table"."column"', $connection->quoteColumnName('table."column"')); - $this->assertEquals('"table"."column"', $connection->quoteColumnName('"table"."column"')); - $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); - $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); - $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); - } - - public function testTransactionIsolation() - { - $connection = $this->getConnection(true); - - $transaction = $connection->beginTransaction(); - $transaction->setIsolationLevel(Transaction::READ_UNCOMMITTED); - $transaction->commit(); - - $transaction = $connection->beginTransaction(); - $transaction->setIsolationLevel(Transaction::READ_COMMITTED); - $transaction->commit(); - - $transaction = $connection->beginTransaction(); - $transaction->setIsolationLevel(Transaction::REPEATABLE_READ); - $transaction->commit(); - - $transaction = $connection->beginTransaction(); - $transaction->setIsolationLevel(Transaction::SERIALIZABLE); - $transaction->commit(); - - $transaction = $connection->beginTransaction(); - $transaction->setIsolationLevel(Transaction::SERIALIZABLE . ' READ ONLY DEFERRABLE'); - $transaction->commit(); - } -} diff --git a/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php b/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php deleted file mode 100644 index 9dbc47b..0000000 --- a/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php +++ /dev/null @@ -1,125 +0,0 @@ - 5)', 'serial NOT NULL PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'serial NOT NULL PRIMARY KEY CHECK (value > 5)'], - [Schema::TYPE_STRING, 'varchar(255)'], - [Schema::TYPE_STRING . '(32)', 'varchar(32)'], - [Schema::TYPE_STRING . ' CHECK (value LIKE \'test%\')', 'varchar(255) CHECK (value LIKE \'test%\')'], - [Schema::TYPE_STRING . '(32) CHECK (value LIKE \'test%\')', 'varchar(32) CHECK (value LIKE \'test%\')'], - [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], - [Schema::TYPE_TEXT, 'text'], - [Schema::TYPE_TEXT . '(255)', 'text'], - [Schema::TYPE_TEXT . ' CHECK (value LIKE \'test%\')', 'text CHECK (value LIKE \'test%\')'], - [Schema::TYPE_TEXT . '(255) CHECK (value LIKE \'test%\')', 'text CHECK (value LIKE \'test%\')'], - [Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'], - [Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'], - [Schema::TYPE_SMALLINT, 'smallint'], - [Schema::TYPE_SMALLINT . '(8)', 'smallint'], - [Schema::TYPE_INTEGER, 'integer'], - [Schema::TYPE_INTEGER . '(8)', 'integer'], - [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'integer CHECK (value > 5)'], - [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'integer CHECK (value > 5)'], - [Schema::TYPE_INTEGER . ' NOT NULL', 'integer NOT NULL'], - [Schema::TYPE_BIGINT, 'bigint'], - [Schema::TYPE_BIGINT . '(8)', 'bigint'], - [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'], - [Schema::TYPE_FLOAT, 'double precision'], - [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'double precision CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'double precision CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . ' NOT NULL', 'double precision NOT NULL'], - [Schema::TYPE_DECIMAL, 'numeric(10,0)'], - [Schema::TYPE_DECIMAL . '(12,4)', 'numeric(12,4)'], - [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'numeric(10,0) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'numeric(12,4) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . ' NOT NULL', 'numeric(10,0) NOT NULL'], - [Schema::TYPE_DATETIME, 'timestamp(0)'], - [Schema::TYPE_DATETIME . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp(0) CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATETIME . ' NOT NULL', 'timestamp(0) NOT NULL'], - [Schema::TYPE_TIMESTAMP, 'timestamp(0)'], - [Schema::TYPE_TIMESTAMP . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp(0) CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp(0) NOT NULL'], - [Schema::TYPE_TIMESTAMP.'(4)', 'timestamp(4)'], - [Schema::TYPE_TIME, 'time(0)'], - [Schema::TYPE_TIME . " CHECK (value BETWEEN '12:00:00' AND '13:01:01')", "time(0) CHECK (value BETWEEN '12:00:00' AND '13:01:01')"], - [Schema::TYPE_TIME . ' NOT NULL', 'time(0) NOT NULL'], - [Schema::TYPE_DATE, 'date'], - [Schema::TYPE_DATE . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], - [Schema::TYPE_BINARY, 'bytea'], - [Schema::TYPE_BOOLEAN, 'boolean'], - [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT TRUE', 'boolean NOT NULL DEFAULT TRUE'], - [Schema::TYPE_MONEY, 'numeric(19,4)'], - [Schema::TYPE_MONEY . '(16,2)', 'numeric(16,2)'], - [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'numeric(19,4) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'numeric(16,2) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . ' NOT NULL', 'numeric(19,4) NOT NULL'], - ]; - } - - public function conditionProvider() - { - return array_merge(parent::conditionProvider(), [ - // adding conditions for ILIKE i.e. case insensitive LIKE - // http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE - - // empty values - [ ['ilike', 'name', []], '0=1', [] ], - [ ['not ilike', 'name', []], '', [] ], - [ ['or ilike', 'name', []], '0=1', [] ], - [ ['or not ilike', 'name', []], '', [] ], - - // simple ilike - [ ['ilike', 'name', 'heyho'], '"name" ILIKE :qp0', [':qp0' => '%heyho%'] ], - [ ['not ilike', 'name', 'heyho'], '"name" NOT ILIKE :qp0', [':qp0' => '%heyho%'] ], - [ ['or ilike', 'name', 'heyho'], '"name" ILIKE :qp0', [':qp0' => '%heyho%'] ], - [ ['or not ilike', 'name', 'heyho'], '"name" NOT ILIKE :qp0', [':qp0' => '%heyho%'] ], - - // ilike for many values - [ ['ilike', 'name', ['heyho', 'abc']], '"name" ILIKE :qp0 AND "name" ILIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], - [ ['not ilike', 'name', ['heyho', 'abc']], '"name" NOT ILIKE :qp0 AND "name" NOT ILIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], - [ ['or ilike', 'name', ['heyho', 'abc']], '"name" ILIKE :qp0 OR "name" ILIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], - [ ['or not ilike', 'name', ['heyho', 'abc']], '"name" NOT ILIKE :qp0 OR "name" NOT ILIKE :qp1', [':qp0' => '%heyho%', ':qp1' => '%abc%'] ], - ]); - } - - public function testAlterColumn() - { - $qb = $this->getQueryBuilder(); - - $expected = 'ALTER TABLE "foo1" ALTER COLUMN "bar" TYPE varchar(255)'; - $sql = $qb->alterColumn('foo1', 'bar', 'varchar(255)'); - $this->assertEquals($expected, $sql); - - $expected = 'ALTER TABLE "foo1" ALTER COLUMN "bar" SET NOT null'; - $sql = $qb->alterColumn('foo1', 'bar', 'SET NOT null'); - $this->assertEquals($expected, $sql); - - $expected = 'ALTER TABLE "foo1" ALTER COLUMN "bar" drop default'; - $sql = $qb->alterColumn('foo1', 'bar', 'drop default'); - $this->assertEquals($expected, $sql); - - $expected = 'ALTER TABLE "foo1" ALTER COLUMN "bar" reset xyz'; - $sql = $qb->alterColumn('foo1', 'bar', 'reset xyz'); - $this->assertEquals($expected, $sql); - } -} diff --git a/tests/unit/framework/db/pgsql/PostgreSQLQueryTest.php b/tests/unit/framework/db/pgsql/PostgreSQLQueryTest.php deleted file mode 100644 index af2c383..0000000 --- a/tests/unit/framework/db/pgsql/PostgreSQLQueryTest.php +++ /dev/null @@ -1,40 +0,0 @@ -getConnection(); - $command = $db->createCommand(); - $command->batchInsert('bool_values', - ['bool_col'], [ - [true], - [false], - ] - )->execute(); - - $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = TRUE')->count('*', $db)); - $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = FALSE')->count('*', $db)); - $this->assertEquals(2, (new Query())->from('bool_values')->where('bool_col IN (TRUE, FALSE)')->count('*', $db)); - - $this->assertEquals(1, (new Query())->from('bool_values')->where(['bool_col' => true])->count('*', $db)); - $this->assertEquals(1, (new Query())->from('bool_values')->where(['bool_col' => false])->count('*', $db)); - $this->assertEquals(2, (new Query())->from('bool_values')->where(['bool_col' => [true, false]])->count('*', $db)); - - $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = :bool_col', ['bool_col' => true])->count('*', $db)); - $this->assertEquals(1, (new Query())->from('bool_values')->where('bool_col = :bool_col', ['bool_col' => false])->count('*', $db)); - } -} diff --git a/tests/unit/framework/db/pgsql/PostgreSQLSchemaTest.php b/tests/unit/framework/db/pgsql/PostgreSQLSchemaTest.php deleted file mode 100644 index 7b8e9bb..0000000 --- a/tests/unit/framework/db/pgsql/PostgreSQLSchemaTest.php +++ /dev/null @@ -1,109 +0,0 @@ -getConnection()->schema; - - foreach ($values as $value) { - $this->assertEquals($value[1], $schema->getPdoType($value[0])); - } - fclose($fp); - } - - public function testBooleanDefaultValues() - { - /* @var $schema Schema */ - $schema = $this->getConnection()->schema; - - $table = $schema->getTableSchema('bool_values'); - $this->assertSame(true, $table->getColumn('default_true')->defaultValue); - $this->assertSame(false, $table->getColumn('default_false')->defaultValue); - } - - public function testFindSchemaNames() - { - $schema = $this->getConnection()->schema; - - $this->assertEquals(3, count($schema->getSchemaNames())); - } -} diff --git a/tests/unit/framework/db/sqlite/SqliteActiveDataProviderTest.php b/tests/unit/framework/db/sqlite/SqliteActiveDataProviderTest.php deleted file mode 100644 index 245bc88..0000000 --- a/tests/unit/framework/db/sqlite/SqliteActiveDataProviderTest.php +++ /dev/null @@ -1,14 +0,0 @@ -getConnection(false); - - $sql = 'SELECT [[id]], [[t.name]] FROM {{customer}} t'; - $command = $db->createCommand($sql); - $this->assertEquals("SELECT `id`, `t`.`name` FROM `customer` t", $command->sql); - } -} diff --git a/tests/unit/framework/db/sqlite/SqliteConnectionTest.php b/tests/unit/framework/db/sqlite/SqliteConnectionTest.php deleted file mode 100644 index c36e5e6..0000000 --- a/tests/unit/framework/db/sqlite/SqliteConnectionTest.php +++ /dev/null @@ -1,145 +0,0 @@ -getConnection(false); - $params = $this->database; - - $this->assertEquals($params['dsn'], $connection->dsn); - } - - public function testQuoteValue() - { - $connection = $this->getConnection(false); - $this->assertEquals(123, $connection->quoteValue(123)); - $this->assertEquals("'string'", $connection->quoteValue('string')); - $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting")); - } - - public function testQuoteTableName() - { - $connection = $this->getConnection(false); - $this->assertEquals("`table`", $connection->quoteTableName('table')); - $this->assertEquals("`schema`.`table`", $connection->quoteTableName('schema.table')); - $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}')); - $this->assertEquals('(table)', $connection->quoteTableName('(table)')); - } - - public function testQuoteColumnName() - { - $connection = $this->getConnection(false); - $this->assertEquals('`column`', $connection->quoteColumnName('column')); - $this->assertEquals("`table`.`column`", $connection->quoteColumnName('table.column')); - $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]')); - $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}')); - $this->assertEquals('(column)', $connection->quoteColumnName('(column)')); - } - - public function testTransactionIsolation() - { - $connection = $this->getConnection(true); - - $transaction = $connection->beginTransaction(Transaction::READ_UNCOMMITTED); - $transaction->rollBack(); - - $transaction = $connection->beginTransaction(Transaction::SERIALIZABLE); - $transaction->rollBack(); - } - - public function testMasterSlave() - { - $counts = [[0, 2], [1, 2], [2, 2]]; - - foreach ($counts as $count) { - list($masterCount, $slaveCount) = $count; - - $db = $this->prepareMasterSlave($masterCount, $slaveCount); - - $this->assertTrue($db->getSlave() instanceof Connection); - $this->assertTrue($db->getSlave()->isActive); - $this->assertFalse($db->isActive); - - // test SELECT uses slave - $this->assertEquals(2, $db->createCommand('SELECT COUNT(*) FROM profile')->queryScalar()); - $this->assertFalse($db->isActive); - - // test UPDATE uses master - $db->createCommand("UPDATE profile SET description='test' WHERE id=1")->execute(); - $this->assertTrue($db->isActive); - $this->assertNotEquals('test', $db->createCommand("SELECT description FROM profile WHERE id=1")->queryScalar()); - $result = $db->useMaster(function (Connection $db) { - return $db->createCommand("SELECT description FROM profile WHERE id=1")->queryScalar(); - }); - $this->assertEquals('test', $result); - - // test ActiveRecord read/write split - ActiveRecord::$db = $db = $this->prepareMasterSlave($masterCount, $slaveCount); - $this->assertFalse($db->isActive); - - $customer = Customer::findOne(1); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals('user1', $customer->name); - $this->assertFalse($db->isActive); - - $customer->name = 'test'; - $customer->save(); - $this->assertTrue($db->isActive); - $customer = Customer::findOne(1); - $this->assertTrue($customer instanceof Customer); - $this->assertEquals('user1', $customer->name); - $result = $db->useMaster(function () { - return Customer::findOne(1)->name; - }); - $this->assertEquals('test', $result); - } - } - - /** - * @param integer $masterCount - * @param integer $slaveCount - * @return Connection - */ - protected function prepareMasterSlave($masterCount, $slaveCount) - { - $databases = self::getParam('databases'); - $fixture = $databases[$this->driverName]['fixture']; - $basePath = \Yii::getAlias('@yiiunit/runtime'); - - $config = [ - 'class' => 'yii\db\Connection', - 'dsn' => "sqlite:$basePath/yii2test.sq3", - ]; - $this->prepareDatabase($config, $fixture)->close(); - - for ($i = 0; $i < $masterCount; ++$i) { - $master = ['dsn' => "sqlite:$basePath/yii2test_master{$i}.sq3"]; - $db = $this->prepareDatabase($master, $fixture); - $db->close(); - $config['masters'][] = $master; - } - - for ($i = 0; $i < $slaveCount; ++$i) { - $slave = ['dsn' => "sqlite:$basePath/yii2test_slave{$i}.sq3"]; - $db = $this->prepareDatabase($slave, $fixture); - $db->close(); - $config['slaves'][] = $slave; - } - - return \Yii::createObject($config); - } -} diff --git a/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php b/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php deleted file mode 100644 index 34ab18a..0000000 --- a/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php +++ /dev/null @@ -1,94 +0,0 @@ - 5)', 'integer PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (value > 5)'], - [Schema::TYPE_PK . '(8) CHECK (value > 5)', 'integer PRIMARY KEY AUTOINCREMENT NOT NULL CHECK (value > 5)'], - [Schema::TYPE_STRING, 'varchar(255)'], - [Schema::TYPE_STRING . '(32)', 'varchar(32)'], - [Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'], - [Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'], - [Schema::TYPE_TEXT, 'text'], - [Schema::TYPE_TEXT . '(255)', 'text'], - [Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'text CHECK (value LIKE "test%")'], - [Schema::TYPE_TEXT . ' NOT NULL', 'text NOT NULL'], - [Schema::TYPE_TEXT . '(255) NOT NULL', 'text NOT NULL'], - [Schema::TYPE_SMALLINT, 'smallint'], - [Schema::TYPE_SMALLINT . '(8)', 'smallint'], - [Schema::TYPE_INTEGER, 'integer'], - [Schema::TYPE_INTEGER . '(8)', 'integer'], - [Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'integer CHECK (value > 5)'], - [Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'integer CHECK (value > 5)'], - [Schema::TYPE_INTEGER . ' NOT NULL', 'integer NOT NULL'], - [Schema::TYPE_BIGINT, 'bigint'], - [Schema::TYPE_BIGINT . '(8)', 'bigint'], - [Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'], - [Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'], - [Schema::TYPE_FLOAT, 'float'], - [Schema::TYPE_FLOAT . '(16,5)', 'float'], - [Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . '(16,5) CHECK (value > 5.6)', 'float CHECK (value > 5.6)'], - [Schema::TYPE_FLOAT . ' NOT NULL', 'float NOT NULL'], - [Schema::TYPE_DECIMAL, 'decimal(10,0)'], - [Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'], - [Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'], - [Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'], - [Schema::TYPE_DATETIME, 'datetime'], - [Schema::TYPE_DATETIME . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'], - [Schema::TYPE_TIMESTAMP, 'timestamp'], - [Schema::TYPE_TIMESTAMP . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'], - [Schema::TYPE_TIME, 'time'], - [Schema::TYPE_TIME . " CHECK (value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK (value BETWEEN '12:00:00' AND '13:01:01')"], - [Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'], - [Schema::TYPE_DATE, 'date'], - [Schema::TYPE_DATE . " CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK (value BETWEEN '2011-01-01' AND '2013-01-01')"], - [Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'], - [Schema::TYPE_BINARY, 'blob'], - [Schema::TYPE_BOOLEAN, 'boolean'], - [Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'boolean NOT NULL DEFAULT 1'], - [Schema::TYPE_MONEY, 'decimal(19,4)'], - [Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'], - [Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'], - [Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'], - ]; - } - - public function testAddDropPrimaryKey() - { - $this->setExpectedException('yii\base\NotSupportedException'); - parent::testAddDropPrimaryKey(); - } - - public function testBatchInsert() - { - $db = $this->getConnection(); - if (version_compare($db->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '3.7.11', '>=')) { - $this->markTestSkipped('This test is only relevant for SQLite < 3.7.11'); - } - $sql = $this->getQueryBuilder()->batchInsert('{{customer}} t', ['t.id', 't.name'], [[1, 'a'], [2, 'b']]); - $this->assertEquals("INSERT INTO {{customer}} t (`t`.`id`, `t`.`name`) SELECT 1, 'a' UNION SELECT 2, 'b'", $sql); - } -} diff --git a/tests/unit/framework/db/sqlite/SqliteQueryTest.php b/tests/unit/framework/db/sqlite/SqliteQueryTest.php deleted file mode 100644 index 5c85077..0000000 --- a/tests/unit/framework/db/sqlite/SqliteQueryTest.php +++ /dev/null @@ -1,13 +0,0 @@ - - * @since 2.0 - */ -class ContainerTest extends TestCase -{ - public function testDefault() - { - $namespace = __NAMESPACE__ . '\stubs'; - $QuxInterface = "$namespace\\QuxInterface"; - $Foo = Foo::className(); - $Bar = Bar::className(); - $Qux = Qux::className(); - - // automatic wiring - $container = new Container; - $container->set($QuxInterface, $Qux); - $foo = $container->get($Foo); - $this->assertTrue($foo instanceof $Foo); - $this->assertTrue($foo->bar instanceof $Bar); - $this->assertTrue($foo->bar->qux instanceof $Qux); - $foo2 = $container->get($Foo); - $this->assertFalse($foo === $foo2); - - // full wiring - $container = new Container; - $container->set($QuxInterface, $Qux); - $container->set($Bar); - $container->set($Qux); - $container->set($Foo); - $foo = $container->get($Foo); - $this->assertTrue($foo instanceof $Foo); - $this->assertTrue($foo->bar instanceof $Bar); - $this->assertTrue($foo->bar->qux instanceof $Qux); - - // wiring by closure - $container = new Container; - $container->set('foo', function () { - $qux = new Qux; - $bar = new Bar($qux); - return new Foo($bar); - }); - $foo = $container->get('foo'); - $this->assertTrue($foo instanceof $Foo); - $this->assertTrue($foo->bar instanceof $Bar); - $this->assertTrue($foo->bar->qux instanceof $Qux); - - // wiring by closure which uses container - $container = new Container; - $container->set($QuxInterface, $Qux); - $container->set('foo', function (Container $c, $params, $config) { - return $c->get(Foo::className()); - }); - $foo = $container->get('foo'); - $this->assertTrue($foo instanceof $Foo); - $this->assertTrue($foo->bar instanceof $Bar); - $this->assertTrue($foo->bar->qux instanceof $Qux); - - // predefined constructor parameters - $container = new Container; - $container->set('foo', $Foo, [Instance::of('bar')]); - $container->set('bar', $Bar, [Instance::of('qux')]); - $container->set('qux', $Qux); - $foo = $container->get('foo'); - $this->assertTrue($foo instanceof $Foo); - $this->assertTrue($foo->bar instanceof $Bar); - $this->assertTrue($foo->bar->qux instanceof $Qux); - - // wiring by closure - $container = new Container; - $container->set('qux', new Qux); - $qux1 = $container->get('qux'); - $qux2 = $container->get('qux'); - $this->assertTrue($qux1 === $qux2); - - // config - $container = new Container; - $container->set('qux', $Qux); - $qux = $container->get('qux', [], ['a' => 2]); - $this->assertEquals(2, $qux->a); - $qux = $container->get('qux', [3]); - $this->assertEquals(3, $qux->a); - $qux = $container->get('qux', [3, ['a' => 4]]); - $this->assertEquals(4, $qux->a); - } -} diff --git a/tests/unit/framework/di/InstanceTest.php b/tests/unit/framework/di/InstanceTest.php deleted file mode 100644 index 70f7970..0000000 --- a/tests/unit/framework/di/InstanceTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @since 2.0 - */ -class InstanceTest extends TestCase -{ - public function testOf() - { - $container = new Container; - $className = Component::className(); - $instance = Instance::of($className); - - $this->assertTrue($instance instanceof Instance); - $this->assertTrue($instance->get($container) instanceof Component); - $this->assertTrue(Instance::ensure($instance, $className, $container) instanceof Component); - $this->assertTrue($instance->get($container) !== Instance::ensure($instance, $className, $container)); - } - - public function testEnsure() - { - $container = new Container; - $container->set('db', [ - 'class' => 'yii\db\Connection', - 'dsn' => 'test', - ]); - - $this->assertTrue(Instance::ensure('db', 'yii\db\Connection', $container) instanceof Connection); - $this->assertTrue(Instance::ensure(new Connection, 'yii\db\Connection', $container) instanceof Connection); - $this->assertTrue(Instance::ensure([ - 'class' => 'yii\db\Connection', - 'dsn' => 'test', - ], 'yii\db\Connection', $container) instanceof Connection); - } -} diff --git a/tests/unit/framework/di/ServiceLocatorTest.php b/tests/unit/framework/di/ServiceLocatorTest.php deleted file mode 100644 index 66139bd..0000000 --- a/tests/unit/framework/di/ServiceLocatorTest.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @since 2.0 - */ -class ServiceLocatorTest extends TestCase -{ - public function testCallable() - { - // anonymous function - $container = new ServiceLocator; - $className = TestClass::className(); - $container->set($className, function () { - return new TestClass([ - 'prop1' => 100, - 'prop2' => 200, - ]); - }); - $object = $container->get($className); - $this->assertTrue($object instanceof $className); - $this->assertEquals(100, $object->prop1); - $this->assertEquals(200, $object->prop2); - - // static method - $container = new ServiceLocator; - $className = TestClass::className(); - $container->set($className, [__NAMESPACE__ . "\\Creator", 'create']); - $object = $container->get($className); - $this->assertTrue($object instanceof $className); - $this->assertEquals(1, $object->prop1); - $this->assertNull($object->prop2); - } - - public function testObject() - { - $object = new TestClass; - $className = TestClass::className(); - $container = new ServiceLocator; - $container->set($className, $object); - $this->assertTrue($container->get($className) === $object); - } - - public function testShared() - { - // with configuration: shared - $container = new ServiceLocator; - $className = TestClass::className(); - $container->set($className, [ - 'class' => $className, - 'prop1' => 10, - 'prop2' => 20, - ]); - $object = $container->get($className); - $this->assertEquals(10, $object->prop1); - $this->assertEquals(20, $object->prop2); - $this->assertTrue($object instanceof $className); - // check shared - $object2 = $container->get($className); - $this->assertTrue($object2 instanceof $className); - $this->assertTrue($object === $object2); - } -} diff --git a/tests/unit/framework/di/stubs/Bar.php b/tests/unit/framework/di/stubs/Bar.php deleted file mode 100644 index d0bc788..0000000 --- a/tests/unit/framework/di/stubs/Bar.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class Bar extends Object -{ - public $qux; - - public function __construct(QuxInterface $qux, $config = []) - { - $this->qux = $qux; - parent::__construct($config); - } -} diff --git a/tests/unit/framework/di/stubs/Foo.php b/tests/unit/framework/di/stubs/Foo.php deleted file mode 100644 index 75a5612..0000000 --- a/tests/unit/framework/di/stubs/Foo.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @since 2.0 - */ -class Foo extends Object -{ - public $bar; - - public function __construct(Bar $bar, $config = []) - { - $this->bar = $bar; - parent::__construct($config); - } -} diff --git a/tests/unit/framework/di/stubs/Qux.php b/tests/unit/framework/di/stubs/Qux.php deleted file mode 100644 index 4b44866..0000000 --- a/tests/unit/framework/di/stubs/Qux.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @since 2.0 - */ -class Qux extends Object implements QuxInterface -{ - public $a; - - public function __construct($a = 1, $config = []) - { - $this->a = $a; - parent::__construct($config); - } - - public function quxMethod() - { - } -} diff --git a/tests/unit/framework/di/stubs/QuxInterface.php b/tests/unit/framework/di/stubs/QuxInterface.php deleted file mode 100644 index 8a98471..0000000 --- a/tests/unit/framework/di/stubs/QuxInterface.php +++ /dev/null @@ -1,17 +0,0 @@ - - * @since 2.0 - */ -interface QuxInterface -{ - function quxMethod(); -} diff --git a/tests/unit/framework/filters/CompositeAuthTest.php b/tests/unit/framework/filters/CompositeAuthTest.php deleted file mode 100644 index 0092d2c..0000000 --- a/tests/unit/framework/filters/CompositeAuthTest.php +++ /dev/null @@ -1,121 +0,0 @@ - - */ -class TestAuth extends AuthMethod -{ - public function authenticate($user, $request, $response) - { - return $user; - } -} - -class TestController extends Controller -{ - public function actionA() - { - return 'success'; - } - - public function actionB() - { - /** - * this call will execute the actionA in a same instance of TestController - */ - return $this->runAction('a'); - } - - public function actionC() - { - /** - * this call will execute the actionA in a same instance of TestController - */ - return $this->run('a'); - } - - public function actionD() - { - /** - * this call will execute the actionA in a new instance of TestController - */ - return $this->run('test/a'); - } - - public function behaviors() - { - /** - * the CompositeAuth::authenticate() assumes that it is only executed once per the controller's instance - * i believe this is okay as long as we specify in the documentation that if we want to use the authenticate - * method again(this might even be also true to other behaviors that attaches to the beforeAction event), - * that we will have to forward/run into the other action in a way that it will create a new controller instance - */ - return [ - 'authenticator' => [ - 'class' => CompositeAuth::className(), - 'authMethods' => [ - TestAuth::className() - ] - ], - ]; - } -} - -/** - * @group filters - */ -class CompositeAuthTest extends \yiiunit\TestCase -{ - protected function setUp() - { - parent::setUp(); - - $_SERVER['SCRIPT_FILENAME'] = "/index.php"; - $_SERVER['SCRIPT_NAME'] = "/index.php"; - - $appConfig = [ - 'components' => [ - 'user' => [ - 'identityClass' => UserIdentity::className() - ], - ], - 'controllerMap' => [ - 'test' => TestController::className() - ] - ]; - - $this->mockWebApplication($appConfig); - } - - public function testCallingRunWithCompleteRoute() - { - /** @var TestController $controller */ - $controller = Yii::$app->createController('test')[0]; - $this->assertEquals('success', $controller->run('test/d')); - } - - /** - * reproducing the issue specified in https://github.com/yiisoft/yii2/issues/7409 - */ - public function testRunAction() - { - /** @var TestController $controller */ - $controller = Yii::$app->createController('test')[0]; - $this->assertEquals('success', $controller->run('b')); - } - - public function testRunButWithActionIdOnly() - { - /** @var TestController $controller */ - $controller = Yii::$app->createController('test')[0]; - $this->assertEquals('success', $controller->run('c')); - } -} diff --git a/tests/unit/framework/filters/HttpCacheTest.php b/tests/unit/framework/filters/HttpCacheTest.php deleted file mode 100644 index ca5d932..0000000 --- a/tests/unit/framework/filters/HttpCacheTest.php +++ /dev/null @@ -1,79 +0,0 @@ -mockWebApplication(); - } - - public function testDisabled() - { - $httpCache = new HttpCache; - $this->assertTrue($httpCache->beforeAction(null)); - $httpCache->enabled=false; - $this->assertTrue($httpCache->beforeAction(null)); - } - - /** - * @covers yii\filters\HttpCache::validateCache - */ - public function testValidateCache() - { - $httpCache = new HttpCache; - $method = new \ReflectionMethod($httpCache, 'validateCache'); - $method->setAccessible(true); - - unset($_SERVER['HTTP_IF_MODIFIED_SINCE'], $_SERVER['HTTP_IF_NONE_MATCH']); - $this->assertTrue($method->invoke($httpCache, null, null)); - $this->assertFalse($method->invoke($httpCache, 0, null)); - $this->assertFalse($method->invoke($httpCache, 0, '"foo"')); - - $_SERVER['HTTP_IF_MODIFIED_SINCE'] = 'Thu, 01 Jan 1970 00:00:00 GMT'; - $this->assertTrue($method->invoke($httpCache, 0, null)); - $this->assertFalse($method->invoke($httpCache, 1, null)); - - $_SERVER['HTTP_IF_NONE_MATCH'] = '"foo"'; - $this->assertTrue($method->invoke($httpCache, 0, '"foo"')); - $this->assertFalse($method->invoke($httpCache, 0, '"foos"')); - $this->assertTrue($method->invoke($httpCache, 1, '"foo"')); - $this->assertFalse($method->invoke($httpCache, 1, '"foos"')); - $this->assertFalse($method->invoke($httpCache, null, null)); - - $_SERVER['HTTP_IF_NONE_MATCH'] = '*'; - $this->assertFalse($method->invoke($httpCache, 0, '"foo"')); - $this->assertFalse($method->invoke($httpCache, 0, null)); - } - - /** - * @covers yii\filters\HttpCache::generateEtag - */ - public function testGenerateEtag() - { - $httpCache = new HttpCache; - $httpCache->etagSeed = function($action, $params) { - return ''; - }; - $httpCache->beforeAction(null); - $response = Yii::$app->getResponse(); - - $this->assertTrue($response->getHeaders()->offsetExists('ETag')); - - $etag = $response->getHeaders()->get('ETag'); - $this->assertStringStartsWith('"', $etag); - $this->assertStringEndsWith('"', $etag); - } -} diff --git a/tests/unit/framework/helpers/ArrayHelperTest.php b/tests/unit/framework/helpers/ArrayHelperTest.php deleted file mode 100644 index 97592aa..0000000 --- a/tests/unit/framework/helpers/ArrayHelperTest.php +++ /dev/null @@ -1,467 +0,0 @@ -secret; - } -} - -class Post3 extends Object -{ - public $id = 33; - public $subObject; - - public function init() - { - $this->subObject = new Post2(); - } -} - -/** - * @group helpers - */ -class ArrayHelperTest extends TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - public function testToArray() - { - $object = new Post1; - $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object)); - $object = new Post2; - $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object)); - - $object1 = new Post1; - $object2 = new Post2; - $this->assertEquals([ - get_object_vars($object1), - get_object_vars($object2), - ], ArrayHelper::toArray([ - $object1, - $object2, - ])); - - $object = new Post2; - $this->assertEquals([ - 'id' => 123, - 'secret' => 's', - '_content' => 'test', - 'length' => 4, - ], ArrayHelper::toArray($object, [ - $object->className() => [ - 'id', 'secret', - '_content' => 'content', - 'length' => function ($post) { - return strlen($post->content); - } - ] - ])); - - $object = new Post3(); - $this->assertEquals(get_object_vars($object), ArrayHelper::toArray($object, [], false)); - $this->assertEquals([ - 'id' => 33, - 'subObject' => [ - 'id' => 123, - 'content' => 'test', - ], - ], ArrayHelper::toArray($object)); - } - - public function testRemove() - { - $array = ['name' => 'b', 'age' => 3]; - $name = ArrayHelper::remove($array, 'name'); - - $this->assertEquals($name, 'b'); - $this->assertEquals($array, ['age' => 3]); - - $default = ArrayHelper::remove($array, 'nonExisting', 'defaultValue'); - $this->assertEquals('defaultValue', $default); - } - - public function testMultisort() - { - // single key - $array = [ - ['name' => 'b', 'age' => 3], - ['name' => 'a', 'age' => 1], - ['name' => 'c', 'age' => 2], - ]; - ArrayHelper::multisort($array, 'name'); - $this->assertEquals(['name' => 'a', 'age' => 1], $array[0]); - $this->assertEquals(['name' => 'b', 'age' => 3], $array[1]); - $this->assertEquals(['name' => 'c', 'age' => 2], $array[2]); - - // multiple keys - $array = [ - ['name' => 'b', 'age' => 3], - ['name' => 'a', 'age' => 2], - ['name' => 'a', 'age' => 1], - ]; - ArrayHelper::multisort($array, ['name', 'age']); - $this->assertEquals(['name' => 'a', 'age' => 1], $array[0]); - $this->assertEquals(['name' => 'a', 'age' => 2], $array[1]); - $this->assertEquals(['name' => 'b', 'age' => 3], $array[2]); - - // case-insensitive - $array = [ - ['name' => 'a', 'age' => 3], - ['name' => 'b', 'age' => 2], - ['name' => 'B', 'age' => 4], - ['name' => 'A', 'age' => 1], - ]; - - ArrayHelper::multisort($array, ['name', 'age'], SORT_ASC, [SORT_STRING, SORT_REGULAR]); - $this->assertEquals(['name' => 'A', 'age' => 1], $array[0]); - $this->assertEquals(['name' => 'B', 'age' => 4], $array[1]); - $this->assertEquals(['name' => 'a', 'age' => 3], $array[2]); - $this->assertEquals(['name' => 'b', 'age' => 2], $array[3]); - - ArrayHelper::multisort($array, ['name', 'age'], SORT_ASC, [SORT_STRING | SORT_FLAG_CASE, SORT_REGULAR]); - $this->assertEquals(['name' => 'A', 'age' => 1], $array[0]); - $this->assertEquals(['name' => 'a', 'age' => 3], $array[1]); - $this->assertEquals(['name' => 'b', 'age' => 2], $array[2]); - $this->assertEquals(['name' => 'B', 'age' => 4], $array[3]); - } - - public function testMultisortUseSort() - { - // single key - $sort = new Sort([ - 'attributes' => ['name', 'age'], - 'defaultOrder' => ['name' => SORT_ASC], - ]); - $orders = $sort->getOrders(); - - $array = [ - ['name' => 'b', 'age' => 3], - ['name' => 'a', 'age' => 1], - ['name' => 'c', 'age' => 2], - ]; - ArrayHelper::multisort($array, array_keys($orders), array_values($orders)); - $this->assertEquals(['name' => 'a', 'age' => 1], $array[0]); - $this->assertEquals(['name' => 'b', 'age' => 3], $array[1]); - $this->assertEquals(['name' => 'c', 'age' => 2], $array[2]); - - // multiple keys - $sort = new Sort([ - 'attributes' => ['name', 'age'], - 'defaultOrder' => ['name' => SORT_ASC, 'age' => SORT_DESC], - ]); - $orders = $sort->getOrders(); - - $array = [ - ['name' => 'b', 'age' => 3], - ['name' => 'a', 'age' => 2], - ['name' => 'a', 'age' => 1], - ]; - ArrayHelper::multisort($array, array_keys($orders), array_values($orders)); - $this->assertEquals(['name' => 'a', 'age' => 2], $array[0]); - $this->assertEquals(['name' => 'a', 'age' => 1], $array[1]); - $this->assertEquals(['name' => 'b', 'age' => 3], $array[2]); - } - - public function testMerge() - { - $a = [ - 'name' => 'Yii', - 'version' => '1.0', - 'options' => [ - 'namespace' => false, - 'unittest' => false, - ], - 'features' => [ - 'mvc', - ], - ]; - $b = [ - 'version' => '1.1', - 'options' => [ - 'unittest' => true, - ], - 'features' => [ - 'gii', - ], - ]; - $c = [ - 'version' => '2.0', - 'options' => [ - 'namespace' => true, - ], - 'features' => [ - 'debug', - ], - ]; - - $result = ArrayHelper::merge($a, $b, $c); - $expected = [ - 'name' => 'Yii', - 'version' => '2.0', - 'options' => [ - 'namespace' => true, - 'unittest' => true, - ], - 'features' => [ - 'mvc', - 'gii', - 'debug', - ], - ]; - - $this->assertEquals($expected, $result); - } - - public function testIndex() - { - $array = [ - ['id' => '123', 'data' => 'abc'], - ['id' => '345', 'data' => 'def'], - ]; - $result = ArrayHelper::index($array, 'id'); - $this->assertEquals([ - '123' => ['id' => '123', 'data' => 'abc'], - '345' => ['id' => '345', 'data' => 'def'], - ], $result); - - $result = ArrayHelper::index($array, function ($element) { - return $element['data']; - }); - $this->assertEquals([ - 'abc' => ['id' => '123', 'data' => 'abc'], - 'def' => ['id' => '345', 'data' => 'def'], - ], $result); - } - - public function testGetColumn() - { - $array = [ - 'a' => ['id' => '123', 'data' => 'abc'], - 'b' => ['id' => '345', 'data' => 'def'], - ]; - $result = ArrayHelper::getColumn($array, 'id'); - $this->assertEquals(['a' => '123', 'b' => '345'], $result); - $result = ArrayHelper::getColumn($array, 'id', false); - $this->assertEquals(['123', '345'], $result); - - $result = ArrayHelper::getColumn($array, function ($element) { - return $element['data']; - }); - $this->assertEquals(['a' => 'abc', 'b' => 'def'], $result); - $result = ArrayHelper::getColumn($array, function ($element) { - return $element['data']; - }, false); - $this->assertEquals(['abc', 'def'], $result); - } - - public function testMap() - { - $array = [ - ['id' => '123', 'name' => 'aaa', 'class' => 'x'], - ['id' => '124', 'name' => 'bbb', 'class' => 'x'], - ['id' => '345', 'name' => 'ccc', 'class' => 'y'], - ]; - - $result = ArrayHelper::map($array, 'id', 'name'); - $this->assertEquals([ - '123' => 'aaa', - '124' => 'bbb', - '345' => 'ccc', - ], $result); - - $result = ArrayHelper::map($array, 'id', 'name', 'class'); - $this->assertEquals([ - 'x' => [ - '123' => 'aaa', - '124' => 'bbb', - ], - 'y' => [ - '345' => 'ccc', - ], - ], $result); - } - - public function testKeyExists() - { - $array = [ - 'a' => 1, - 'B' => 2, - ]; - $this->assertTrue(ArrayHelper::keyExists('a', $array)); - $this->assertFalse(ArrayHelper::keyExists('b', $array)); - $this->assertTrue(ArrayHelper::keyExists('B', $array)); - $this->assertFalse(ArrayHelper::keyExists('c', $array)); - - $this->assertTrue(ArrayHelper::keyExists('a', $array, false)); - $this->assertTrue(ArrayHelper::keyExists('b', $array, false)); - $this->assertTrue(ArrayHelper::keyExists('B', $array, false)); - $this->assertFalse(ArrayHelper::keyExists('c', $array, false)); - } - - public function valueProvider() - { - return [ - ['name', 'test'], - ['noname', null], - ['noname', 'test', 'test'], - ['post.id', 5], - ['post.id', 5, 'test'], - ['nopost.id', null], - ['nopost.id', 'test', 'test'], - ['post.author.name', 'cebe'], - ['post.author.noname', null], - ['post.author.noname', 'test', 'test'], - ['post.author.profile.title', '1337'], - ['admin.firstname', 'Qiang'], - ['admin.firstname', 'Qiang', 'test'], - ['admin.lastname', 'Xue'], - [ - function ($array, $defaultValue) { - return $array['date'] . $defaultValue; - }, - '31-12-2113test', - 'test' - ], - ]; - } - - /** - * @dataProvider valueProvider - * - * @param $key - * @param $expected - * @param null $default - */ - public function testGetValue($key, $expected, $default = null) - { - $array = [ - 'name' => 'test', - 'date' => '31-12-2113', - 'post' => [ - 'id' => 5, - 'author' => [ - 'name' => 'cebe', - 'profile' => [ - 'title' => '1337', - ], - ], - ], - 'admin.firstname' => 'Qiang', - 'admin.lastname' => 'Xue', - 'admin' => [ - 'lastname' => 'cebe', - ], - ]; - - $this->assertEquals($expected, ArrayHelper::getValue($array, $key, $default)); - } - - public function testIsAssociative() - { - $this->assertFalse(ArrayHelper::isAssociative('test')); - $this->assertFalse(ArrayHelper::isAssociative([])); - $this->assertFalse(ArrayHelper::isAssociative([1, 2, 3])); - $this->assertTrue(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test'])); - $this->assertFalse(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test', 3])); - $this->assertTrue(ArrayHelper::isAssociative(['name' => 1, 'value' => 'test', 3], false)); - } - - public function testIsIndexed() - { - $this->assertFalse(ArrayHelper::isIndexed('test')); - $this->assertTrue(ArrayHelper::isIndexed([])); - $this->assertTrue(ArrayHelper::isIndexed([1, 2, 3])); - $this->assertTrue(ArrayHelper::isIndexed([2 => 'a', 3 => 'b'])); - $this->assertFalse(ArrayHelper::isIndexed([2 => 'a', 3 => 'b'], true)); - } - - public function testHtmlEncode() - { - $array = [ - 'abc' => '123', - '<' => '>', - 'cde' => false, - 3 => 'blank', - [ - '<>' => 'a<>b', - '23' => true, - ] - ]; - $this->assertEquals([ - 'abc' => '123', - '<' => '>', - 'cde' => false, - 3 => 'blank', - [ - '<>' => 'a<>b', - '23' => true, - ] - ], ArrayHelper::htmlEncode($array)); - $this->assertEquals([ - 'abc' => '123', - '<' => '>', - 'cde' => false, - 3 => 'blank', - [ - '<>' => 'a<>b', - '23' => true, - ] - ], ArrayHelper::htmlEncode($array, false)); - } - - public function testHtmlDecode() - { - $array = [ - 'abc' => '123', - '<' => '>', - 'cde' => false, - 3 => 'blank', - [ - '<>' => 'a<>b', - '23' => true, - ] - ]; - $this->assertEquals([ - 'abc' => '123', - '<' => '>', - 'cde' => false, - 3 => 'blank', - [ - '<>' => 'a<>b', - '23' => true, - ] - ], ArrayHelper::htmlDecode($array)); - $this->assertEquals([ - 'abc' => '123', - '<' => '>', - 'cde' => false, - 3 => 'blank', - [ - '<>' => 'a<>b', - '23' => true, - ] - ], ArrayHelper::htmlDecode($array, false)); - } -} diff --git a/tests/unit/framework/helpers/ConsoleTest.php b/tests/unit/framework/helpers/ConsoleTest.php deleted file mode 100644 index 70344df..0000000 --- a/tests/unit/framework/helpers/ConsoleTest.php +++ /dev/null @@ -1,132 +0,0 @@ -assertEquals(str_repeat('a', 25), $output); - } - -/* public function testScreenSize() - { - for ($i = 1; $i < 20; $i++) { - echo implode(', ', Console::getScreenSize(true)) . "\n"; - ob_flush(); - sleep(1); - } - }*/ - - public function ansiFormats() - { - return [ - ['test', 'test'], - [Console::ansiFormat('test', [Console::FG_RED]), 'test'], - ['abc' . Console::ansiFormat('def', [Console::FG_RED]) . 'ghj', 'abcdefghj'], - ['abc' . Console::ansiFormat('def', [Console::FG_RED, Console::BG_GREEN]) . 'ghj', 'abcdefghj'], - ['abc' . Console::ansiFormat('def', [Console::FG_GREEN, Console::FG_RED, Console::BG_GREEN]) . 'ghj', 'abcdefghj'], - ['abc' . Console::ansiFormat('def', [Console::BOLD, Console::BG_GREEN]) . 'ghj', 'abcdefghj'], - - [ - Console::ansiFormat('test', [Console::UNDERLINE, Console::OVERLINED, Console::CROSSED_OUT, Console::FG_GREEN]), - 'test' - ], - - [Console::ansiFormatCode([Console::RESET]) . Console::ansiFormatCode([Console::RESET]), ''], - [Console::ansiFormatCode([Console::RESET]) . Console::ansiFormatCode([Console::RESET]) . 'test', 'test'], - [Console::ansiFormatCode([Console::RESET]) . 'test' . Console::ansiFormatCode([Console::RESET]), 'test'], - - [ - Console::ansiFormatCode([Console::BOLD]) . 'abc' . Console::ansiFormatCode([Console::RESET, Console::FG_GREEN]) . 'ghj' . Console::ansiFormatCode([Console::RESET]), - 'abcghj' - ], - [ - Console::ansiFormatCode([Console::FG_GREEN]) . ' a ' . Console::ansiFormatCode([Console::BOLD]) . 'abc' . Console::ansiFormatCode([Console::RESET]) . 'ghj', - ' a abcghj' - ], - [ - Console::ansiFormat('test', [Console::FG_GREEN, Console::BG_BLUE, Console::NEGATIVE]), - 'test' - ], - [ - Console::ansiFormat('test', [Console::NEGATIVE]), - 'test' - ], - [ - Console::ansiFormat('test', [Console::CONCEALED]), - 'test' - ], - ]; - } - - /** - * @dataProvider ansiFormats - */ - public function testAnsi2Html($ansi, $html) - { - $this->assertEquals($html, Console::ansiToHtml($ansi)); - } -} diff --git a/tests/unit/framework/helpers/FallbackInflector.php b/tests/unit/framework/helpers/FallbackInflector.php deleted file mode 100644 index 0eff0e9..0000000 --- a/tests/unit/framework/helpers/FallbackInflector.php +++ /dev/null @@ -1,21 +0,0 @@ -testFilePath = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . get_class($this); - $this->createDir($this->testFilePath); - if (!file_exists($this->testFilePath)) { - $this->markTestIncomplete('Unit tests runtime directory should have writable permissions!'); - } - } - - public function tearDown() - { - $this->removeDir($this->testFilePath); - } - - /** - * Creates directory. - * @param string $dirName directory full name. - */ - protected function createDir($dirName) - { - if (!file_exists($dirName)) { - mkdir($dirName, 0777, true); - } - } - - /** - * Removes directory. - * @param string $dirName directory full name. - */ - protected function removeDir($dirName) - { - if (!empty($dirName) && is_dir($dirName)) { - if ($handle = opendir($dirName)) { - while (false !== ($entry = readdir($handle))) { - if ($entry != '.' && $entry != '..') { - if (is_dir($dirName . DIRECTORY_SEPARATOR . $entry) === true) { - $this->removeDir($dirName . DIRECTORY_SEPARATOR . $entry); - } else { - unlink($dirName . DIRECTORY_SEPARATOR . $entry); - } - } - } - closedir($handle); - rmdir($dirName); - } - } - } - - /** - * Get file permission mode. - * @param string $file file name. - * @return string permission mode. - */ - protected function getMode($file) - { - return substr(sprintf('%o', fileperms($file)), -4); - } - - /** - * Creates test files structure, - * @param array $items file system objects to be created in format: objectName => objectContent - * Arrays specifies directories, other values - files. - * @param string $basePath structure base file path. - */ - protected function createFileStructure(array $items, $basePath = '') - { - if (empty($basePath)) { - $basePath = $this->testFilePath; - } - foreach ($items as $name => $content) { - $itemName = $basePath . DIRECTORY_SEPARATOR . $name; - if (is_array($content)) { - if (isset($content[0], $content[1]) && $content[0] == 'symlink') { - symlink($content[1], $itemName); - } else { - mkdir($itemName, 0777, true); - $this->createFileStructure($content, $itemName); - } - } else { - file_put_contents($itemName, $content); - } - } - } - - /** - * Asserts that file has specific permission mode. - * @param integer $expectedMode expected file permission mode. - * @param string $fileName file name. - * @param string $message error message - */ - protected function assertFileMode($expectedMode, $fileName, $message = '') - { - $expectedMode = sprintf('%o', $expectedMode); - $this->assertEquals($expectedMode, $this->getMode($fileName), $message); - } - - // Tests : - - public function testCopyDirectory() - { - $srcDirName = 'test_src_dir'; - $files = [ - 'file1.txt' => 'file 1 content', - 'file2.txt' => 'file 2 content', - ]; - $this->createFileStructure([ - $srcDirName => $files - ]); - - $basePath = $this->testFilePath; - $srcDirName = $basePath . DIRECTORY_SEPARATOR . $srcDirName; - $dstDirName = $basePath . DIRECTORY_SEPARATOR . 'test_dst_dir'; - - FileHelper::copyDirectory($srcDirName, $dstDirName); - - $this->assertFileExists($dstDirName, 'Destination directory does not exist!'); - foreach ($files as $name => $content) { - $fileName = $dstDirName . DIRECTORY_SEPARATOR . $name; - $this->assertFileExists($fileName); - $this->assertEquals($content, file_get_contents($fileName), 'Incorrect file content!'); - } - } - - /** - * @depends testCopyDirectory - */ - public function testCopyDirectoryPermissions() - { - if (DIRECTORY_SEPARATOR === '\\') { - $this->markTestSkipped("Can't reliably test it on Windows because fileperms() always return 0777."); - } - - $srcDirName = 'test_src_dir'; - $subDirName = 'test_sub_dir'; - $fileName = 'test_file.txt'; - $this->createFileStructure([ - $srcDirName => [ - $subDirName => [], - $fileName => 'test file content', - ], - ]); - - $basePath = $this->testFilePath; - $srcDirName = $basePath . DIRECTORY_SEPARATOR . $srcDirName; - $dstDirName = $basePath . DIRECTORY_SEPARATOR . 'test_dst_dir'; - - $dirMode = 0755; - $fileMode = 0755; - $options = [ - 'dirMode' => $dirMode, - 'fileMode' => $fileMode, - ]; - FileHelper::copyDirectory($srcDirName, $dstDirName, $options); - - $this->assertFileMode($dirMode, $dstDirName, 'Destination directory has wrong mode!'); - $this->assertFileMode($dirMode, $dstDirName . DIRECTORY_SEPARATOR . $subDirName, 'Copied sub directory has wrong mode!'); - $this->assertFileMode($fileMode, $dstDirName . DIRECTORY_SEPARATOR . $fileName, 'Copied file has wrong mode!'); - } - - public function testRemoveDirectory() - { - $dirName = 'test_dir_for_remove'; - $this->createFileStructure([ - $dirName => [ - 'file1.txt' => 'file 1 content', - 'file2.txt' => 'file 2 content', - 'test_sub_dir' => [ - 'sub_dir_file_1.txt' => 'sub dir file 1 content', - 'sub_dir_file_2.txt' => 'sub dir file 2 content', - ], - ], - ]); - - $basePath = $this->testFilePath; - $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; - - FileHelper::removeDirectory($dirName); - - $this->assertFileNotExists($dirName, 'Unable to remove directory!'); - - // should be silent about non-existing directories - FileHelper::removeDirectory($basePath . DIRECTORY_SEPARATOR . 'nonExisting'); - } - - public function testRemoveDirectorySymlinks1() - { - if (strtolower(substr(PHP_OS, 0, 3)) == 'win') { - $this->markTestSkipped('Cannot test this on MS Windows since symlinks are uncommon for it.'); - } - - $dirName = 'remove-directory-symlinks-1'; - $this->createFileStructure([ - $dirName => [ - 'file' => 'Symlinked file.', - 'directory' => [ - 'standard-file-1' => 'Standard file 1.' - ], - 'symlinks' => [ - 'standard-file-2' => 'Standard file 2.', - 'symlinked-file' => ['symlink', '..' . DIRECTORY_SEPARATOR . 'file'], - 'symlinked-directory' => ['symlink', '..' . DIRECTORY_SEPARATOR . 'directory'], - ], - ], - ]); - - $basePath = $this->testFilePath . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR; - $this->assertFileExists($basePath . 'file'); - $this->assertTrue(is_dir($basePath . 'directory')); - $this->assertFileExists($basePath . 'directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); - $this->assertTrue(is_dir($basePath . 'symlinks')); - $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'standard-file-2'); - $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-file'); - $this->assertTrue(is_dir($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory')); - $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); - - FileHelper::removeDirectory($basePath . 'symlinks'); - - $this->assertFileExists($basePath . 'file'); - $this->assertTrue(is_dir($basePath . 'directory')); - $this->assertFileExists($basePath . 'directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); // symlinked directory still have it's file - $this->assertFalse(is_dir($basePath . 'symlinks')); - $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'standard-file-2'); - $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-file'); - $this->assertFalse(is_dir($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory')); - $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); - } - - public function testRemoveDirectorySymlinks2() - { - if (strtolower(substr(PHP_OS, 0, 3)) == 'win') { - $this->markTestSkipped('Cannot test this on MS Windows since symlinks are uncommon for it.'); - } - - $dirName = 'remove-directory-symlinks-2'; - $this->createFileStructure([ - $dirName => [ - 'file' => 'Symlinked file.', - 'directory' => [ - 'standard-file-1' => 'Standard file 1.' - ], - 'symlinks' => [ - 'standard-file-2' => 'Standard file 2.', - 'symlinked-file' => ['symlink', '..' . DIRECTORY_SEPARATOR . 'file'], - 'symlinked-directory' => ['symlink', '..' . DIRECTORY_SEPARATOR . 'directory'], - ], - ], - ]); - - $basePath = $this->testFilePath . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR; - $this->assertFileExists($basePath . 'file'); - $this->assertTrue(is_dir($basePath . 'directory')); - $this->assertFileExists($basePath . 'directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); - $this->assertTrue(is_dir($basePath . 'symlinks')); - $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'standard-file-2'); - $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-file'); - $this->assertTrue(is_dir($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory')); - $this->assertFileExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); - - FileHelper::removeDirectory($basePath . 'symlinks', ['traverseSymlinks' => true]); - - $this->assertFileExists($basePath . 'file'); - $this->assertTrue(is_dir($basePath . 'directory')); - $this->assertFileNotExists($basePath . 'directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); // symlinked directory doesn't have it's file now - $this->assertFalse(is_dir($basePath . 'symlinks')); - $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'standard-file-2'); - $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-file'); - $this->assertFalse(is_dir($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory')); - $this->assertFileNotExists($basePath . 'symlinks' . DIRECTORY_SEPARATOR . 'symlinked-directory' . DIRECTORY_SEPARATOR . 'standard-file-1'); - } - - public function testFindFiles() - { - $dirName = 'test_dir'; - $this->createFileStructure([ - $dirName => [ - 'file_1.txt' => 'file 1 content', - 'file_2.txt' => 'file 2 content', - 'test_sub_dir' => [ - 'file_1_1.txt' => 'sub dir file 1 content', - 'file_1_2.txt' => 'sub dir file 2 content', - ], - ], - ]); - $basePath = $this->testFilePath; - $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; - $expectedFiles = [ - $dirName . DIRECTORY_SEPARATOR . 'file_1.txt', - $dirName . DIRECTORY_SEPARATOR . 'file_2.txt', - $dirName . DIRECTORY_SEPARATOR . 'test_sub_dir' . DIRECTORY_SEPARATOR . 'file_1_1.txt', - $dirName . DIRECTORY_SEPARATOR . 'test_sub_dir' . DIRECTORY_SEPARATOR . 'file_1_2.txt', - ]; - - $foundFiles = FileHelper::findFiles($dirName); - sort($expectedFiles); - sort($foundFiles); - $this->assertEquals($expectedFiles, $foundFiles); - } - - /** - * @depends testFindFiles - */ - public function testFindFileFilter() - { - $dirName = 'test_dir'; - $passedFileName = 'passed.txt'; - $this->createFileStructure([ - $dirName => [ - $passedFileName => 'passed file content', - 'declined.txt' => 'declined file content', - ], - ]); - $basePath = $this->testFilePath; - $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; - - $options = [ - 'filter' => function ($path) use ($passedFileName) { - return $passedFileName == basename($path); - } - ]; - $foundFiles = FileHelper::findFiles($dirName, $options); - $this->assertEquals([$dirName . DIRECTORY_SEPARATOR . $passedFileName], $foundFiles); - } - - /** - * @depends testFindFiles - */ - public function testFindFilesExclude() - { - $basePath = $this->testFilePath . DIRECTORY_SEPARATOR; - $dirs = ['', 'one', 'one' . DIRECTORY_SEPARATOR . 'two', 'three']; - $files = array_fill_keys(array_map(function ($n) { - return "a.$n"; - }, range(1, 8)), 'file contents'); - - $tree = $files; - $root = $files; - $flat = []; - foreach ($dirs as $dir) { - foreach ($files as $fileName => $contents) { - $flat[] = rtrim($basePath . $dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $fileName; - } - if ($dir === '') { - continue; - } - $parts = explode(DIRECTORY_SEPARATOR, $dir); - $last = array_pop($parts); - $parent = array_pop($parts); - $tree[$last] = $files; - if ($parent !== null) { - $tree[$parent][$last] = &$tree[$last]; - } else { - $root[$last] = &$tree[$last]; - } - } - $this->createFileStructure($root); - - // range - $foundFiles = FileHelper::findFiles($basePath, ['except' => ['a.[2-8]']]); - sort($foundFiles); - $expect = array_values(array_filter($flat, function ($p) { - return substr($p, -3)==='a.1'; - })); - $this->assertEquals($expect, $foundFiles); - - // suffix - $foundFiles = FileHelper::findFiles($basePath, ['except' => ['*.1']]); - sort($foundFiles); - $expect = array_values(array_filter($flat, function ($p) { - return substr($p, -3)!=='a.1'; - })); - $this->assertEquals($expect, $foundFiles); - - // dir - $foundFiles = FileHelper::findFiles($basePath, ['except' => ['/one']]); - sort($foundFiles); - $expect = array_values(array_filter($flat, function ($p) { - return strpos($p, DIRECTORY_SEPARATOR.'one')===false; - })); - $this->assertEquals($expect, $foundFiles); - - // dir contents - $foundFiles = FileHelper::findFiles($basePath, ['except' => ['?*/a.1']]); - sort($foundFiles); - $expect = array_values(array_filter($flat, function ($p) { - return substr($p, -11, 10)==='one'.DIRECTORY_SEPARATOR.'two'.DIRECTORY_SEPARATOR.'a.' || ( - substr($p, -8)!==DIRECTORY_SEPARATOR.'one'.DIRECTORY_SEPARATOR.'a.1' && - substr($p, -10)!==DIRECTORY_SEPARATOR.'three'.DIRECTORY_SEPARATOR.'a.1' - ); - })); - $this->assertEquals($expect, $foundFiles); - } - - /** - * @depends testFindFilesExclude - */ - public function testFindFilesCaseSensitive() - { - $dirName = 'test_dir'; - $this->createFileStructure([ - $dirName => [ - 'lower.txt' => 'lower case filename', - 'upper.TXT' => 'upper case filename', - ], - ]); - $basePath = $this->testFilePath; - $dirName = $basePath . DIRECTORY_SEPARATOR . $dirName; - - $options = [ - 'except' => ['*.txt'], - 'caseSensitive' => false - ]; - $foundFiles = FileHelper::findFiles($dirName, $options); - $this->assertCount(0, $foundFiles); - - $options = [ - 'only' => ['*.txt'], - 'caseSensitive' => false - ]; - $foundFiles = FileHelper::findFiles($dirName, $options); - $this->assertCount(2, $foundFiles); - } - - public function testCreateDirectory() - { - $basePath = $this->testFilePath; - $dirName = $basePath . DIRECTORY_SEPARATOR . 'test_dir_level_1' . DIRECTORY_SEPARATOR . 'test_dir_level_2'; - $this->assertTrue(FileHelper::createDirectory($dirName), 'FileHelper::createDirectory should return true if directory was created!'); - $this->assertFileExists($dirName, 'Unable to create directory recursively!'); - $this->assertTrue(FileHelper::createDirectory($dirName), 'FileHelper::createDirectory should return true for already existing directories!'); - } - - public function testGetMimeTypeByExtension() - { - $magicFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'mime_type.php'; - $mimeTypeMap = [ - 'txa' => 'application/json', - 'txb' => 'another/mime', - ]; - $magicFileContent = ' $mimeType) { - $fileName = 'test.' . $extension; - $this->assertNull(FileHelper::getMimeTypeByExtension($fileName)); - $this->assertEquals($mimeType, FileHelper::getMimeTypeByExtension($fileName, $magicFile)); - } - } - - public function testGetMimeType() - { - $file = $this->testFilePath . DIRECTORY_SEPARATOR . 'mime_type_test.txt'; - file_put_contents($file, 'some text'); - $this->assertEquals('text/plain', FileHelper::getMimeType($file)); - - // see http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type - // JSON/JSONP should not use text/plain - see http://jibbering.com/blog/?p=514 - // with "fileinfo" extension enabled, returned MIME is not quite correctly "text/plain" - // without "fileinfo" it falls back to getMimeTypeByExtension() and returns application/json - $file = $this->testFilePath . DIRECTORY_SEPARATOR . 'mime_type_test.json'; - file_put_contents($file, '{"a": "b"}'); - $this->assertTrue(in_array(FileHelper::getMimeType($file), ['application/json', 'text/plain'])); - } - - public function testNormalizePath() - { - $ds = DIRECTORY_SEPARATOR; - $this->assertEquals("{$ds}a{$ds}b", FileHelper::normalizePath('//a\b/')); - $this->assertEquals("{$ds}b{$ds}c", FileHelper::normalizePath('/a/../b/c')); - $this->assertEquals("{$ds}c", FileHelper::normalizePath('/a\\b/../..///c')); - $this->assertEquals("{$ds}c", FileHelper::normalizePath('/a/.\\b//../../c')); - $this->assertEquals("c", FileHelper::normalizePath('/a/.\\b/../..//../c')); - $this->assertEquals("..{$ds}c", FileHelper::normalizePath('//a/.\\b//..//..//../../c')); - - // relative paths - $this->assertEquals(".", FileHelper::normalizePath('.')); - $this->assertEquals(".", FileHelper::normalizePath('./')); - $this->assertEquals("a", FileHelper::normalizePath('.\\a')); - $this->assertEquals("a{$ds}b", FileHelper::normalizePath('./a\\b')); - $this->assertEquals(".", FileHelper::normalizePath('./a\\../')); - $this->assertEquals("..{$ds}..{$ds}a", FileHelper::normalizePath('../..\\a')); - $this->assertEquals("..{$ds}..{$ds}a", FileHelper::normalizePath('../..\\a/../a')); - $this->assertEquals("..{$ds}..{$ds}b", FileHelper::normalizePath('../..\\a/../b')); - $this->assertEquals("..{$ds}a", FileHelper::normalizePath('./..\\a')); - $this->assertEquals("..{$ds}a", FileHelper::normalizePath('././..\\a')); - $this->assertEquals("..{$ds}a", FileHelper::normalizePath('./..\\a/../a')); - $this->assertEquals("..{$ds}b", FileHelper::normalizePath('./..\\a/../b')); - } - - public function testLocalizedDirectory() - { - $this->createFileStructure([ - 'views' => [ - 'faq.php' => 'English FAQ', - 'de-DE' => [ - 'faq.php' => 'German FAQ', - ], - ], - ]); - $viewFile = $this->testFilePath . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'faq.php'; - $sourceLanguage = 'en-US'; - - // Source language and target language are same. The view path should be unchanged. - $currentLanguage = $sourceLanguage; - $this->assertSame($viewFile, FileHelper::localize($viewFile, $currentLanguage, $sourceLanguage)); - - // Source language and target language are different. The view path should be changed. - $currentLanguage = 'de-DE'; - $this->assertSame( - $this->testFilePath . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . $currentLanguage . DIRECTORY_SEPARATOR . 'faq.php', - FileHelper::localize($viewFile, $currentLanguage, $sourceLanguage) - ); - } - - /** - * @see https://github.com/yiisoft/yii2/issues/3393 - * - * @depends testCopyDirectory - * @depends testFindFiles - */ - public function testCopyDirectoryExclude() - { - $srcDirName = 'test_src_dir'; - $textFiles = [ - 'file1.txt' => 'text file 1 content', - 'file2.txt' => 'text file 2 content', - ]; - $dataFiles = [ - 'file1.dat' => 'data file 1 content', - 'file2.dat' => 'data file 2 content', - ]; - $this->createFileStructure([ - $srcDirName => array_merge($textFiles, $dataFiles) - ]); - - $basePath = $this->testFilePath; - $srcDirName = $basePath . DIRECTORY_SEPARATOR . $srcDirName; - $dstDirName = $basePath . DIRECTORY_SEPARATOR . 'test_dst_dir'; - - FileHelper::copyDirectory($srcDirName, $dstDirName, ['only' => ['*.dat']]); - - $this->assertFileExists($dstDirName, 'Destination directory does not exist!'); - $copiedFiles = FileHelper::findFiles($dstDirName); - $this->assertCount(2, $copiedFiles, 'wrong files count copied'); - - foreach ($dataFiles as $name => $content) { - $fileName = $dstDirName . DIRECTORY_SEPARATOR . $name; - $this->assertFileExists($fileName); - $this->assertEquals($content, file_get_contents($fileName), 'Incorrect file content!'); - } - } -} diff --git a/tests/unit/framework/helpers/FormatConverterTest.php b/tests/unit/framework/helpers/FormatConverterTest.php deleted file mode 100644 index 1bd198d..0000000 --- a/tests/unit/framework/helpers/FormatConverterTest.php +++ /dev/null @@ -1,75 +0,0 @@ -mockApplication([ - 'timeZone' => 'UTC', - 'language' => 'ru-RU', - ]); - } - - protected function tearDown() - { - parent::tearDown(); - IntlTestHelper::resetIntlStatus(); - } - - public function testIntlIcuToPhpShortForm() - { - $this->assertEquals('n/j/y', FormatConverter::convertDateIcuToPhp('short', 'date', 'en-US')); - $this->assertEquals('d.m.y', FormatConverter::convertDateIcuToPhp('short', 'date', 'de-DE')); - } - - public function testEscapedIcuToPhp() - { - $this->assertEquals('l, F j, Y \\a\\t g:i:s a T', FormatConverter::convertDateIcuToPhp('EEEE, MMMM d, y \'at\' h:mm:ss a zzzz')); - $this->assertEquals('\\o\\\'\\c\\l\\o\\c\\k', FormatConverter::convertDateIcuToPhp('\'o\'\'clock\'')); - } - - public function testEscapedIcuToJui() - { - $this->assertEquals('l, F j, Y \\a\\t g:i:s a T', FormatConverter::convertDateIcuToPhp('EEEE, MMMM d, y \'at\' h:mm:ss a zzzz')); - $this->assertEquals('\'o\'\'clock\'', FormatConverter::convertDateIcuToJui('\'o\'\'clock\'')); - } - - public function testIntlOneDigitIcu() - { - $formatter = new Formatter(['locale' => 'en-US']); - $this->assertEquals('24.8.2014', $formatter->asDate('2014-8-24', 'php:d.n.Y')); - $this->assertEquals('24.8.2014', $formatter->asDate('2014-8-24', 'd.M.yyyy')); - } - - public function testOneDigitIcu() - { - $formatter = new Formatter(['locale' => 'en-US']); - $this->assertEquals('24.8.2014', $formatter->asDate('2014-8-24', 'php:d.n.Y')); - $this->assertEquals('24.8.2014', $formatter->asDate('2014-8-24', 'd.M.yyyy')); - } - - public function testIntlUtf8Ru() - { - $this->assertEquals('d M Y \г.', FormatConverter::convertDateIcuToPhp('dd MMM y \'г\'.', 'date', 'ru-RU')); - $this->assertEquals('dd M yy \'г\'.', FormatConverter::convertDateIcuToJui('dd MMM y \'г\'.', 'date', 'ru-RU')); - - $formatter = new Formatter(['locale' => 'ru-RU']); - $this->assertEquals('24 авг 2014 г.', $formatter->asDate('2014-8-24', 'dd MMM y \'г\'.')); - } -} diff --git a/tests/unit/framework/helpers/HtmlTest.php b/tests/unit/framework/helpers/HtmlTest.php deleted file mode 100644 index f8ee237..0000000 --- a/tests/unit/framework/helpers/HtmlTest.php +++ /dev/null @@ -1,658 +0,0 @@ -mockApplication([ - 'components' => [ - 'request' => [ - 'class' => 'yii\web\Request', - 'url' => '/test', - 'enableCsrfValidation' => false, - ], - 'response' => [ - 'class' => 'yii\web\Response', - ], - ], - ]); - } - - public function testEncode() - { - $this->assertEquals("a<>&"'�", Html::encode("a<>&\"'\x80")); - $this->assertEquals('Sam & Dark', Html::encode('Sam & Dark')); - } - - public function testDecode() - { - $this->assertEquals("a<>&\"'", Html::decode("a<>&"'")); - } - - public function testTag() - { - $this->assertEquals('
        ', Html::tag('br')); - $this->assertEquals('', Html::tag('span')); - $this->assertEquals('
        content
        ', Html::tag('div', 'content')); - $this->assertEquals('', Html::tag('input', '', ['type' => 'text', 'name' => 'test', 'value' => '<>'])); - $this->assertEquals('', Html::tag('span', '', ['disabled' => true])); - } - - public function testBeginTag() - { - $this->assertEquals('
        ', Html::beginTag('br')); - $this->assertEquals('', Html::beginTag('span', ['id' => 'test', 'class' => 'title'])); - } - - public function testEndTag() - { - $this->assertEquals('
        ', Html::endTag('br')); - $this->assertEquals('
        ', Html::endTag('span')); - } - - public function testStyle() - { - $content = 'a <>'; - $this->assertEquals("", Html::style($content)); - $this->assertEquals("", Html::style($content, ['type' => 'text/less'])); - } - - public function testScript() - { - $content = 'a <>'; - $this->assertEquals("", Html::script($content)); - $this->assertEquals("", Html::script($content, ['type' => 'text/js'])); - } - - public function testCssFile() - { - $this->assertEquals('', Html::cssFile('http://example.com')); - $this->assertEquals('', Html::cssFile('')); - $this->assertEquals("", Html::cssFile('http://example.com', ['condition' => 'IE 9'])); - } - - public function testJsFile() - { - $this->assertEquals('', Html::jsFile('http://example.com')); - $this->assertEquals('', Html::jsFile('')); - $this->assertEquals("", Html::jsFile('http://example.com', ['condition' => 'IE 9'])); - } - - public function testBeginForm() - { - $this->assertEquals('
        ', Html::beginForm()); - $this->assertEquals('', Html::beginForm('/example', 'get')); - $hiddens = [ - '', - '', - ]; - $this->assertEquals('' . "\n" . implode("\n", $hiddens), Html::beginForm('/example?id=1&title=%3C', 'get')); - } - - public function testEndForm() - { - $this->assertEquals('
        ', Html::endForm()); - } - - public function testA() - { - $this->assertEquals('something<>', Html::a('something<>')); - $this->assertEquals('something', Html::a('something', '/example')); - $this->assertEquals('something', Html::a('something', '')); - $this->assertEquals('http://www.быстроном.рф', Html::a('http://www.быстроном.рф', 'http://www.быстроном.рф')); - } - - public function testMailto() - { - $this->assertEquals('test<>', Html::mailto('test<>')); - $this->assertEquals('test<>', Html::mailto('test<>', 'test>')); - } - - public function testImg() - { - $this->assertEquals('', Html::img('/example')); - $this->assertEquals('', Html::img('')); - $this->assertEquals('something', Html::img('/example', ['alt' => 'something', 'width' => 10])); - } - - public function testLabel() - { - $this->assertEquals('', Html::label('something<>')); - $this->assertEquals('', Html::label('something<>', 'a')); - $this->assertEquals('', Html::label('something<>', 'a', ['class' => 'test'])); - } - - public function testButton() - { - $this->assertEquals('', Html::button()); - $this->assertEquals('', Html::button('content<>', ['name' => 'test', 'value' => 'value'])); - $this->assertEquals('', Html::button('content<>', ['type' => 'submit', 'name' => 'test', 'value' => 'value', 'class' => "t"])); - } - - public function testSubmitButton() - { - $this->assertEquals('', Html::submitButton()); - $this->assertEquals('', Html::submitButton('content<>', ['name' => 'test', 'value' => 'value', 'class' => 't'])); - } - - public function testResetButton() - { - $this->assertEquals('', Html::resetButton()); - $this->assertEquals('', Html::resetButton('content<>', ['name' => 'test', 'value' => 'value', 'class' => 't'])); - } - - public function testInput() - { - $this->assertEquals('', Html::input('text')); - $this->assertEquals('', Html::input('text', 'test', 'value', ['class' => 't'])); - } - - public function testButtonInput() - { - $this->assertEquals('', Html::buttonInput()); - $this->assertEquals('', Html::buttonInput('text', ['name' => 'test', 'class' => 'a'])); - } - - public function testSubmitInput() - { - $this->assertEquals('', Html::submitInput()); - $this->assertEquals('', Html::submitInput('text', ['name' => 'test', 'class' => 'a'])); - } - - public function testResetInput() - { - $this->assertEquals('', Html::resetInput()); - $this->assertEquals('', Html::resetInput('text', ['name' => 'test', 'class' => 'a'])); - } - - public function testTextInput() - { - $this->assertEquals('', Html::textInput('test')); - $this->assertEquals('', Html::textInput('test', 'value', ['class' => 't'])); - } - - public function testHiddenInput() - { - $this->assertEquals('', Html::hiddenInput('test')); - $this->assertEquals('', Html::hiddenInput('test', 'value', ['class' => 't'])); - } - - public function testPasswordInput() - { - $this->assertEquals('', Html::passwordInput('test')); - $this->assertEquals('', Html::passwordInput('test', 'value', ['class' => 't'])); - } - - public function testFileInput() - { - $this->assertEquals('', Html::fileInput('test')); - $this->assertEquals('', Html::fileInput('test', 'value', ['class' => 't'])); - } - - public function testTextarea() - { - $this->assertEquals('', Html::textarea('test')); - $this->assertEquals('', Html::textarea('test', 'value<>', ['class' => 't'])); - } - - public function testRadio() - { - $this->assertEquals('', Html::radio('test')); - $this->assertEquals('', Html::radio('test', true, ['class' => 'a', 'value' => null])); - $this->assertEquals('', Html::radio('test', true, ['class' => 'a', 'uncheck' => '0', 'value' => 2])); - - $this->assertEquals('', Html::radio('test', true, [ - 'class' => 'a', - 'value' => null, - 'label' => 'ccc', - 'labelOptions' => ['class' =>'bbb'], - ])); - $this->assertEquals('', Html::radio('test', true, [ - 'class' => 'a', - 'uncheck' => '0', - 'label' => 'ccc', - 'value' => 2, - ])); - } - - public function testCheckbox() - { - $this->assertEquals('', Html::checkbox('test')); - $this->assertEquals('', Html::checkbox('test', true, ['class' => 'a', 'value' => null])); - $this->assertEquals('', Html::checkbox('test', true, ['class' => 'a', 'uncheck' => '0', 'value' => 2])); - - $this->assertEquals('', Html::checkbox('test', true, [ - 'class' => 'a', - 'value' => null, - 'label' => 'ccc', - 'labelOptions' => ['class' =>'bbb'], - ])); - $this->assertEquals('', Html::checkbox('test', true, [ - 'class' => 'a', - 'uncheck' => '0', - 'label' => 'ccc', - 'value' => 2, - ])); - } - - public function testDropDownList() - { - $expected = << - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::dropDownList('test')); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', null, $this->getDataItems())); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::dropDownList('test', 'value2', $this->getDataItems())); - } - - public function testListBox() - { - $expected = << - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test')); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems(), ['size' => 5])); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems2())); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems2(), ['encodeSpaces' => true])); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems2(), ['encode' => false])); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, $this->getDataItems2(), ['encodeSpaces' => true, 'encode' => false])); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', 'value2', $this->getDataItems())); - $expected = << - - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', ['value1', 'value2'], $this->getDataItems())); - - $expected = << - - -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', null, [], ['multiple' => true])); - $expected = << -EOD; - $this->assertEqualsWithoutLE($expected, Html::listBox('test', '', [], ['unselect' => '0'])); - } - - public function testCheckboxList() - { - $this->assertEquals('
        ', Html::checkboxList('test')); - - $expected = << - -EOD; - $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems())); - - $expected = << - -EOD; - $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems2())); - - $expected = <<

        -
        -EOD; - $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems(), [ - 'separator' => "
        \n", - 'unselect' => '0', - ])); - - $expected = <<0 -1 -EOD; - $this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $this->getDataItems(), [ - 'item' => function ($index, $label, $name, $checked, $value) { - return $index . Html::label($label . ' ' . Html::checkbox($name, $checked, ['value' => $value])); - } - ])); - } - - public function testRadioList() - { - $this->assertEquals('
        ', Html::radioList('test')); - - $expected = << - -EOD; - $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems())); - - $expected = << - -EOD; - $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems2())); - - $expected = <<

        -
        -EOD; - $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems(), [ - 'separator' => "
        \n", - 'unselect' => '0', - ])); - - $expected = <<0 -1 -EOD; - $this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $this->getDataItems(), [ - 'item' => function ($index, $label, $name, $checked, $value) { - return $index . Html::label($label . ' ' . Html::radio($name, $checked, ['value' => $value])); - } - ])); - } - - public function testUl() - { - $data = [ - 1, 'abc', '<>', - ]; - $expected = << -
      23. 1
      24. -
      25. abc
      26. -
      27. <>
      28. - -EOD; - $this->assertEqualsWithoutLE($expected, Html::ul($data)); - $expected = << -
      29. 1
      30. -
      31. abc
      32. -
      33. <>
      34. - -EOD; - $this->assertEqualsWithoutLE($expected, Html::ul($data, [ - 'class' => 'test', - 'item' => function ($item, $index) { - return "
      35. $item
      36. "; - } - ])); - - $this->assertEquals('
          ', Html::ul([], ['class' => 'test'])); - } - - public function testOl() - { - $data = [ - 1, 'abc', '<>', - ]; - $expected = << -
        • 1
        • -
        • abc
        • -
        • <>
        • - -EOD; - $this->assertEqualsWithoutLE($expected, Html::ol($data, [ - 'itemOptions' => ['class' => 'ti'], - ])); - $expected = << -
        • 1
        • -
        • abc
        • -
        • <>
        • - -EOD; - $this->assertEqualsWithoutLE($expected, Html::ol($data, [ - 'class' => 'test', - 'item' => function ($item, $index) { - return "
        • $item
        • "; - } - ])); - - $this->assertEquals('
            ', Html::ol([], ['class' => 'test'])); - } - - public function testRenderOptions() - { - $data = [ - 'value1' => 'label1', - 'group1' => [ - 'value11' => 'label11', - 'group11' => [ - 'value111' => 'label111', - ], - 'group12' => [], - ], - 'value2' => 'label2', - 'group2' => [], - ]; - $expected = <<please select<> - - - - - - - - - - - - - - -EOD; - $attributes = [ - 'prompt' => 'please select<>', - 'options' => [ - 'value111' => ['class' => 'option'], - ], - 'groups' => [ - 'group12' => ['class' => 'group'], - ], - 'encodeSpaces' => true, - ]; - $this->assertEqualsWithoutLE($expected, Html::renderSelectOptions(['value111', 'value1'], $data, $attributes)); - - $attributes = [ - 'prompt' => 'please select<>', - 'options' => [ - 'value111' => ['class' => 'option'], - ], - 'groups' => [ - 'group12' => ['class' => 'group'], - ], - ]; - $this->assertEqualsWithoutLE(str_replace(' ', ' ', $expected), Html::renderSelectOptions(['value111', 'value1'], $data, $attributes)); - } - - public function testRenderAttributes() - { - $this->assertEquals('', Html::renderTagAttributes([])); - $this->assertEquals(' name="test" value="1<>"', Html::renderTagAttributes(['name' => 'test', 'empty' => null, 'value' => '1<>'])); - $this->assertEquals(' checked disabled', Html::renderTagAttributes(['checked' => true, 'disabled' => true, 'hidden' => false])); - } - - public function testAddCssClass() - { - $options = []; - Html::addCssClass($options, 'test'); - $this->assertEquals(['class' => 'test'], $options); - Html::addCssClass($options, 'test'); - $this->assertEquals(['class' => 'test'], $options); - Html::addCssClass($options, 'test2'); - $this->assertEquals(['class' => 'test test2'], $options); - Html::addCssClass($options, 'test'); - $this->assertEquals(['class' => 'test test2'], $options); - Html::addCssClass($options, 'test2'); - $this->assertEquals(['class' => 'test test2'], $options); - Html::addCssClass($options, 'test3'); - $this->assertEquals(['class' => 'test test2 test3'], $options); - Html::addCssClass($options, 'test2'); - $this->assertEquals(['class' => 'test test2 test3'], $options); - } - - public function testRemoveCssClass() - { - $options = ['class' => 'test test2 test3']; - Html::removeCssClass($options, 'test2'); - $this->assertEquals(['class' => 'test test3'], $options); - Html::removeCssClass($options, 'test2'); - $this->assertEquals(['class' => 'test test3'], $options); - Html::removeCssClass($options, 'test'); - $this->assertEquals(['class' => 'test3'], $options); - Html::removeCssClass($options, 'test3'); - $this->assertEquals([], $options); - } - - public function testCssStyleFromArray() - { - $this->assertEquals('width: 100px; height: 200px;', Html::cssStyleFromArray([ - 'width' => '100px', - 'height' => '200px', - ])); - $this->assertNull(Html::cssStyleFromArray([])); - } - - public function testCssStyleToArray() - { - $this->assertEquals([ - 'width' => '100px', - 'height' => '200px', - ], Html::cssStyleToArray('width: 100px; height: 200px;')); - $this->assertEquals([], Html::cssStyleToArray(' ')); - } - - public function testAddCssStyle() - { - $options = ['style' => 'width: 100px; height: 200px;']; - Html::addCssStyle($options, 'width: 110px; color: red;'); - $this->assertEquals('width: 110px; height: 200px; color: red;', $options['style']); - - $options = ['style' => 'width: 100px; height: 200px;']; - Html::addCssStyle($options, ['width' => '110px', 'color' => 'red']); - $this->assertEquals('width: 110px; height: 200px; color: red;', $options['style']); - - $options = ['style' => 'width: 100px; height: 200px;']; - Html::addCssStyle($options, 'width: 110px; color: red;', false); - $this->assertEquals('width: 100px; height: 200px; color: red;', $options['style']); - - $options = []; - Html::addCssStyle($options, 'width: 110px; color: red;'); - $this->assertEquals('width: 110px; color: red;', $options['style']); - - $options = []; - Html::addCssStyle($options, 'width: 110px; color: red;', false); - $this->assertEquals('width: 110px; color: red;', $options['style']); - } - - public function testRemoveCssStyle() - { - $options = ['style' => 'width: 110px; height: 200px; color: red;']; - Html::removeCssStyle($options, 'width'); - $this->assertEquals('height: 200px; color: red;', $options['style']); - Html::removeCssStyle($options, ['height']); - $this->assertEquals('color: red;', $options['style']); - Html::removeCssStyle($options, ['color', 'background']); - $this->assertNull($options['style']); - - $options = []; - Html::removeCssStyle($options, ['color', 'background']); - $this->assertTrue(!array_key_exists('style', $options)); - } - - public function testBooleanAttributes() - { - $this->assertEquals('', Html::input('email', 'mail', null, ['required' => false])); - $this->assertEquals('', Html::input('email', 'mail', null, ['required' => true])); - $this->assertEquals('', Html::input('email', 'mail', null, ['required' => 'hi'])); - } - - public function testDataAttributes() - { - $this->assertEquals('', Html::tag('link', '', ['src' => 'xyz', 'data' => ['a' => 1, 'b' => 'c']])); - $this->assertEquals('', Html::tag('link', '', ['src' => 'xyz', 'ng' => ['a' => 1, 'b' => 'c']])); - $this->assertEquals('', Html::tag('link', '', ['src' => 'xyz', 'data-ng' => ['a' => 1, 'b' => 'c']])); - $this->assertEquals('', Html::tag('link', '', ['src' => ['a' => 1, 'b' => "It's"]])); - } - - protected function getDataItems() - { - return [ - 'value1' => 'text1', - 'value2' => 'text2', - ]; - } - - protected function getDataItems2() - { - return [ - 'value1<>' => 'text1<>', - 'value 2' => 'text 2', - ]; - } -} diff --git a/tests/unit/framework/helpers/InflectorTest.php b/tests/unit/framework/helpers/InflectorTest.php deleted file mode 100644 index 658eef6..0000000 --- a/tests/unit/framework/helpers/InflectorTest.php +++ /dev/null @@ -1,248 +0,0 @@ - 'moves', - 'foot' => 'feet', - 'child' => 'children', - 'human' => 'humans', - 'man' => 'men', - 'staff' => 'staff', - 'tooth' => 'teeth', - 'person' => 'people', - 'mouse' => 'mice', - 'touch' => 'touches', - 'hash' => 'hashes', - 'shelf' => 'shelves', - 'potato' => 'potatoes', - 'bus' => 'buses', - 'test' => 'tests', - 'car' => 'cars', - ]; - - foreach ($testData as $testIn => $testOut) { - $this->assertEquals($testOut, Inflector::pluralize($testIn)); - $this->assertEquals(ucfirst($testOut), ucfirst(Inflector::pluralize($testIn))); - } - } - - public function testSingularize() - { - $testData = [ - 'moves' => 'move', - 'feet' => 'foot', - 'children' => 'child', - 'humans' => 'human', - 'men' => 'man', - 'staff' => 'staff', - 'teeth' => 'tooth', - 'people' => 'person', - 'mice' => 'mouse', - 'touches' => 'touch', - 'hashes' => 'hash', - 'shelves' => 'shelf', - 'potatoes' => 'potato', - 'buses' => 'bus', - 'tests' => 'test', - 'cars' => 'car', - ]; - foreach ($testData as $testIn => $testOut) { - $this->assertEquals($testOut, Inflector::singularize($testIn)); - $this->assertEquals(ucfirst($testOut), ucfirst(Inflector::singularize($testIn))); - } - } - - public function testTitleize() - { - $this->assertEquals("Me my self and i", Inflector::titleize('MeMySelfAndI')); - $this->assertEquals("Me My Self And I", Inflector::titleize('MeMySelfAndI', true)); - } - - public function testCamelize() - { - $this->assertEquals("MeMySelfAndI", Inflector::camelize('me my_self-andI')); - $this->assertEquals("QweQweEwq", Inflector::camelize('qwe qwe^ewq')); - } - - public function testUnderscore() - { - $this->assertEquals("me_my_self_and_i", Inflector::underscore('MeMySelfAndI')); - } - - public function testCamel2words() - { - $this->assertEquals('Camel Case', Inflector::camel2words('camelCase')); - $this->assertEquals('Lower Case', Inflector::camel2words('lower_case')); - $this->assertEquals('Tricky Stuff It Is Testing', Inflector::camel2words(' tricky_stuff.it-is testing... ')); - } - - public function testCamel2id() - { - $this->assertEquals('post-tag', Inflector::camel2id('PostTag')); - $this->assertEquals('post_tag', Inflector::camel2id('PostTag', '_')); - - $this->assertEquals('post-tag', Inflector::camel2id('postTag')); - $this->assertEquals('post_tag', Inflector::camel2id('postTag', '_')); - - $this->assertEquals('foo-ybar', Inflector::camel2id('FooYBar', '-', false)); - $this->assertEquals('foo_ybar', Inflector::camel2id('fooYBar', '_', false)); - - $this->assertEquals('foo-y-bar', Inflector::camel2id('FooYBar', '-', true)); - $this->assertEquals('foo_y_bar', Inflector::camel2id('fooYBar', '_', true)); - } - - public function testId2camel() - { - $this->assertEquals('PostTag', Inflector::id2camel('post-tag')); - $this->assertEquals('PostTag', Inflector::id2camel('post_tag', '_')); - - $this->assertEquals('PostTag', Inflector::id2camel('post-tag')); - $this->assertEquals('PostTag', Inflector::id2camel('post_tag', '_')); - - $this->assertEquals('FooYBar', Inflector::id2camel('foo-y-bar')); - $this->assertEquals('FooYBar', Inflector::id2camel('foo_y_bar', '_')); - } - - public function testHumanize() - { - $this->assertEquals("Me my self and i", Inflector::humanize('me_my_self_and_i')); - $this->assertEquals("Me My Self And I", Inflector::humanize('me_my_self_and_i', true)); - } - - public function testVariablize() - { - $this->assertEquals("customerTable", Inflector::variablize('customer_table')); - } - - public function testTableize() - { - $this->assertEquals("customer_tables", Inflector::tableize('customerTable')); - } - - public function testSlugCommons() - { - $data = [ - '' => '', - 'hello world 123' => 'hello-world-123', - 'remove.!?[]{}…symbols' => 'removesymbols', - 'minus-sign' => 'minus-sign', - 'mdash—sign' => 'mdash-sign', - 'ndash–sign' => 'ndash-sign', - 'áàâéèêíìîóòôúùûã' => 'aaaeeeiiiooouuua', - 'älä lyö ääliö ööliä läikkyy' => 'ala-lyo-aalio-oolia-laikkyy', - ]; - - foreach ($data as $source => $expected) { - if (extension_loaded('intl')) { - $this->assertEquals($expected, FallbackInflector::slug($source)); - } - $this->assertEquals($expected, Inflector::slug($source)); - } - } - - public function testSlugIntl() - { - if (!extension_loaded('intl')) { - $this->markTestSkipped('intl extension is required.'); - } - - // Some test strings are from https://github.com/bergie/midgardmvc_helper_urlize. Thank you, Henri Bergius! - $data = [ - // Korean - '해동검도' => 'haedong-geomdo', - - // Hiragana - 'ひらがな' => 'hiragana', - - // Georgian - 'საქართველო' => 'sakartvelo', - - // Arabic - 'العربي' => 'alrby', - 'عرب' => 'rb', - - // Hebrew - 'עִבְרִית' => 'iberiyt', - - // Turkish - 'Sanırım hepimiz aynı şeyi düşünüyoruz.' => 'sanrm-hepimiz-ayn-seyi-dusunuyoruz', - - // Russian - 'недвижимость' => 'nedvizimost', - 'Контакты' => 'kontakty', - ]; - - foreach ($data as $source => $expected) { - $this->assertEquals($expected, Inflector::slug($source)); - } - } - - public function testSlugPhp() - { - $data = [ - 'we have недвижимость' => 'we-have', - ]; - - foreach ($data as $source => $expected) { - $this->assertEquals($expected, FallbackInflector::slug($source)); - } - } - - public function testClassify() - { - $this->assertEquals("CustomerTable", Inflector::classify('customer_tables')); - } - - public function testOrdinalize() - { - $this->assertEquals('21st', Inflector::ordinalize('21')); - $this->assertEquals('22nd', Inflector::ordinalize('22')); - $this->assertEquals('23rd', Inflector::ordinalize('23')); - $this->assertEquals('24th', Inflector::ordinalize('24')); - $this->assertEquals('25th', Inflector::ordinalize('25')); - $this->assertEquals('111th', Inflector::ordinalize('111')); - $this->assertEquals('113th', Inflector::ordinalize('113')); - } - - public function testSentence() - { - $array = []; - $this->assertEquals('', Inflector::sentence($array)); - - $array = ['Spain']; - $this->assertEquals('Spain', Inflector::sentence($array)); - - $array = ['Spain', 'France']; - $this->assertEquals('Spain and France', Inflector::sentence($array)); - - $array = ['Spain', 'France', 'Italy']; - $this->assertEquals('Spain, France and Italy', Inflector::sentence($array)); - - $array = ['Spain', 'France', 'Italy', 'Germany']; - $this->assertEquals('Spain, France, Italy and Germany', Inflector::sentence($array)); - - $array = ['Spain', 'France']; - $this->assertEquals('Spain or France', Inflector::sentence($array, ' or ')); - - $array = ['Spain', 'France', 'Italy']; - $this->assertEquals('Spain, France or Italy', Inflector::sentence($array, ' or ')); - - $array = ['Spain', 'France']; - $this->assertEquals('Spain and France', Inflector::sentence($array, ' and ', ' or ', ' - ')); - - $array = ['Spain', 'France', 'Italy']; - $this->assertEquals('Spain - France or Italy', Inflector::sentence($array, ' and ', ' or ', ' - ')); - } -} diff --git a/tests/unit/framework/helpers/JsonTest.php b/tests/unit/framework/helpers/JsonTest.php deleted file mode 100644 index 147ccdb..0000000 --- a/tests/unit/framework/helpers/JsonTest.php +++ /dev/null @@ -1,81 +0,0 @@ -assertSame('"1"', Json::encode($data)); - - // simple array encoding - $data = [1, 2]; - $this->assertSame('[1,2]', Json::encode($data)); - $data = ['a' => 1, 'b' => 2]; - $this->assertSame('{"a":1,"b":2}', Json::encode($data)); - - // simple object encoding - $data = new \stdClass(); - $data->a = 1; - $data->b = 2; - $this->assertSame('{"a":1,"b":2}', Json::encode($data)); - - // expression encoding - $expression = 'function () {}'; - $data = new JsExpression($expression); - $this->assertSame($expression, Json::encode($data)); - - // complex data - $expression1 = 'function (a) {}'; - $expression2 = 'function (b) {}'; - $data = [ - 'a' => [ - 1, new JsExpression($expression1) - ], - 'b' => new JsExpression($expression2), - ]; - $this->assertSame("{\"a\":[1,$expression1],\"b\":$expression2}", Json::encode($data)); - - // https://github.com/yiisoft/yii2/issues/957 - $data = (object) null; - $this->assertSame('{}', Json::encode($data)); - - // JsonSerializable - $data = new JsonModel(); - $this->assertSame('{"json":"serializable"}', Json::encode($data)); - } - - public function testDecode() - { - // basic data decoding - $json = '"1"'; - $this->assertSame('1', Json::decode($json)); - - // array decoding - $json = '{"a":1,"b":2}'; - $this->assertSame(['a' => 1, 'b' => 2], Json::decode($json)); - - // exception - $json = '{"a":1,"b":2'; - $this->setExpectedException('yii\base\InvalidParamException'); - Json::decode($json); - } -} - -class JsonModel extends Model implements \JsonSerializable -{ - function jsonSerialize() - { - return ['json' => 'serializable']; - } -} \ No newline at end of file diff --git a/tests/unit/framework/helpers/StringHelperTest.php b/tests/unit/framework/helpers/StringHelperTest.php deleted file mode 100644 index b305aaf..0000000 --- a/tests/unit/framework/helpers/StringHelperTest.php +++ /dev/null @@ -1,239 +0,0 @@ -mockApplication(); - } - - public function testStrlen() - { - $this->assertEquals(4, StringHelper::byteLength('this')); - $this->assertEquals(6, StringHelper::byteLength('это')); - } - - public function testSubstr() - { - $this->assertEquals('th', StringHelper::byteSubstr('this', 0, 2)); - $this->assertEquals('э', StringHelper::byteSubstr('это', 0, 2)); - - $this->assertEquals('abcdef', StringHelper::byteSubstr('abcdef', 0)); - $this->assertEquals('abcdef', StringHelper::byteSubstr('abcdef', 0, null)); - - $this->assertEquals('de', StringHelper::byteSubstr('abcdef', 3, 2)); - $this->assertEquals('def', StringHelper::byteSubstr('abcdef', 3)); - $this->assertEquals('def', StringHelper::byteSubstr('abcdef', 3, null)); - - $this->assertEquals('cd', StringHelper::byteSubstr('abcdef', -4, 2)); - $this->assertEquals('cdef', StringHelper::byteSubstr('abcdef', -4)); - $this->assertEquals('cdef', StringHelper::byteSubstr('abcdef', -4, null)); - - $this->assertEquals('', StringHelper::byteSubstr('abcdef', 4, 0)); - $this->assertEquals('', StringHelper::byteSubstr('abcdef', -4, 0)); - - $this->assertEquals('это', StringHelper::byteSubstr('это', 0)); - $this->assertEquals('это', StringHelper::byteSubstr('это', 0, null)); - - $this->assertEquals('т', StringHelper::byteSubstr('это', 2, 2)); - $this->assertEquals('то', StringHelper::byteSubstr('это', 2)); - $this->assertEquals('то', StringHelper::byteSubstr('это', 2, null)); - - $this->assertEquals('т', StringHelper::byteSubstr('это', -4, 2)); - $this->assertEquals('то', StringHelper::byteSubstr('это', -4)); - $this->assertEquals('то', StringHelper::byteSubstr('это', -4, null)); - - $this->assertEquals('', StringHelper::byteSubstr('это', 4, 0)); - $this->assertEquals('', StringHelper::byteSubstr('это', -4, 0)); - } - - public function testBasename() - { - $this->assertEquals('', StringHelper::basename('')); - - $this->assertEquals('file', StringHelper::basename('file')); - $this->assertEquals('file.test', StringHelper::basename('file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('file.test', '.test')); - - $this->assertEquals('file', StringHelper::basename('/file')); - $this->assertEquals('file.test', StringHelper::basename('/file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('/file.test', '.test')); - - $this->assertEquals('file', StringHelper::basename('/path/to/file')); - $this->assertEquals('file.test', StringHelper::basename('/path/to/file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('/path/to/file.test', '.test')); - - $this->assertEquals('file', StringHelper::basename('\file')); - $this->assertEquals('file.test', StringHelper::basename('\file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('\file.test', '.test')); - - $this->assertEquals('file', StringHelper::basename('C:\file')); - $this->assertEquals('file.test', StringHelper::basename('C:\file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('C:\file.test', '.test')); - - $this->assertEquals('file', StringHelper::basename('C:\path\to\file')); - $this->assertEquals('file.test', StringHelper::basename('C:\path\to\file.test', '.test2')); - $this->assertEquals('file', StringHelper::basename('C:\path\to\file.test', '.test')); - - // mixed paths - $this->assertEquals('file.test', StringHelper::basename('/path\to/file.test')); - $this->assertEquals('file.test', StringHelper::basename('/path/to\file.test')); - $this->assertEquals('file.test', StringHelper::basename('\path/to\file.test')); - - // \ and / in suffix - $this->assertEquals('file', StringHelper::basename('/path/to/filete/st', 'te/st')); - $this->assertEquals('st', StringHelper::basename('/path/to/filete/st', 'te\st')); - $this->assertEquals('file', StringHelper::basename('/path/to/filete\st', 'te\st')); - $this->assertEquals('st', StringHelper::basename('/path/to/filete\st', 'te/st')); - - // http://www.php.net/manual/en/function.basename.php#72254 - $this->assertEquals('foo', StringHelper::basename('/bar/foo/')); - $this->assertEquals('foo', StringHelper::basename('\\bar\\foo\\')); - } - - public function testTruncate() - { - $this->assertEquals('привет, я multibyte...', StringHelper::truncate('привет, я multibyte строка!', 20)); - $this->assertEquals('Не трогаем строку', StringHelper::truncate('Не трогаем строку', 20)); - $this->assertEquals('исполь!!!', StringHelper::truncate('используем восклицательные знаки', 6, '!!!')); - - // With Html - $this->assertEquals('This is a test ...', StringHelper::truncate('This is a test sentance', 14, '...', null, true)); - $this->assertEquals('This is a test ...', StringHelper::truncate('This is a test sentance', 14, '...', null, true)); - } - - public function testTruncateWords() - { - $this->assertEquals('это тестовая multibyte строка', StringHelper::truncateWords('это тестовая multibyte строка', 5)); - $this->assertEquals('это тестовая multibyte...', StringHelper::truncateWords('это тестовая multibyte строка', 3)); - $this->assertEquals('это тестовая multibyte!!!', StringHelper::truncateWords('это тестовая multibyte строка', 3, '!!!')); - $this->assertEquals('это строка с неожиданными...', StringHelper::truncateWords('это строка с неожиданными пробелами', 4)); - - // With Html - $this->assertEquals('This is a test...', StringHelper::truncateWords('This is a test sentance', 4, '...', true)); - $this->assertEquals('This is a test...', StringHelper::truncateWords('This is a test sentance', 4, '...', true)); - } - - /** - * @dataProvider providerStartsWith - */ - public function testStartsWith($result, $string, $with) - { - // case sensitive version check - $this->assertSame($result, StringHelper::startsWith($string, $with)); - // case insensitive version check - $this->assertSame($result, StringHelper::startsWith($string, $with, false)); - } - - /** - * Rules that should work the same for case-sensitive and case-insensitive `startsWith()` - */ - public function providerStartsWith() - { - return [ - // positive check - [true, '', ''], - [true, '', null], - [true, 'string', ''], - [true, ' string', ' '], - [true, 'abc', 'abc'], - [true, 'Bürger', 'Bürger'], - [true, '我Я multibyte', '我Я'], - [true, 'Qנטשופ צרכנות', 'Qנ'], - [true, 'ไทย.idn.icann.org', 'ไ'], - [true, '!?+', "\x21\x3F"], - [true, "\x21?+", '!?'], - // false-positive check - [false, '', ' '], - [false, ' ', ' '], - [false, 'Abc', 'Abcde'], - [false, 'abc', 'abe'], - [false, 'abc', 'b'], - [false, 'abc', 'c'], - ]; - } - - public function testStartsWithCaseSensitive() - { - $this->assertFalse(StringHelper::startsWith('Abc', 'a')); - $this->assertFalse(StringHelper::startsWith('üЯ multibyte', 'Üя multibyte')); - } - - public function testStartsWithCaseInsensitive() - { - $this->assertTrue(StringHelper::startsWith('sTrInG', 'StRiNg', false)); - $this->assertTrue(StringHelper::startsWith('CaSe', 'cAs', false)); - $this->assertTrue(StringHelper::startsWith('HTTP://BÜrger.DE/', 'http://bürger.de', false)); - $this->assertTrue(StringHelper::startsWith('üЯйΨB', 'ÜяЙΨ', false)); - } - - /** - * @dataProvider providerEndsWith - */ - public function testEndsWith($result, $string, $with) - { - // case sensitive version check - $this->assertSame($result, StringHelper::endsWith($string, $with)); - // case insensitive version check - $this->assertSame($result, StringHelper::endsWith($string, $with, false)); - } - - /** - * Rules that should work the same for case-sensitive and case-insensitive `endsWith()` - */ - public function providerEndsWith() - { - return [ - // positive check - [true, '', ''], - [true, '', null], - [true, 'string', ''], - [true, 'string ', ' '], - [true, 'string', 'g'], - [true, 'abc', 'abc'], - [true, 'Bürger', 'Bürger'], - [true, 'Я multibyte строка我!', ' строка我!'], - [true, '+!?', "\x21\x3F"], - [true, "+\x21?", "!\x3F"], - [true, 'נטשופ צרכנות', 'ת'], - // false-positive check - [false, '', ' '], - [false, ' ', ' '], - [false, 'aaa', 'aaaa'], - [false, 'abc', 'abe'], - [false, 'abc', 'a'], - [false, 'abc', 'b'], - ]; - } - - public function testEndsWithCaseSensitive() - { - $this->assertFalse(StringHelper::endsWith('string', 'G')); - $this->assertFalse(StringHelper::endsWith('multibyte строка', 'А')); - } - - public function testEndsWithCaseInsensitive() - { - $this->assertTrue(StringHelper::endsWith('sTrInG', 'StRiNg', false)); - $this->assertTrue(StringHelper::endsWith('string', 'nG', false)); - $this->assertTrue(StringHelper::endsWith('BüЯйΨ', 'ÜяЙΨ', false)); - } - - public function testExplode() - { - $this->assertEquals(['It', 'is', 'a first', 'test'], StringHelper::explode("It, is, a first, test")); - $this->assertEquals(['It', 'is', 'a second', 'test'], StringHelper::explode("It+ is+ a second+ test", '+')); - $this->assertEquals(['Save', '', '', 'empty trimmed string'], StringHelper::explode("Save, ,, empty trimmed string", ',')); - $this->assertEquals(['Здесь', 'multibyte', 'строка'], StringHelper::explode("Здесь我 multibyte我 строка", '我')); - $this->assertEquals(['Disable', ' trim ', 'here but ignore empty'], StringHelper::explode("Disable, trim ,,,here but ignore empty", ',', false, true)); - } -} diff --git a/tests/unit/framework/helpers/UrlTest.php b/tests/unit/framework/helpers/UrlTest.php deleted file mode 100644 index 4630362..0000000 --- a/tests/unit/framework/helpers/UrlTest.php +++ /dev/null @@ -1,208 +0,0 @@ -mockApplication([ - 'components' => [ - 'request' => [ - 'class' => 'yii\web\Request', - 'scriptUrl' => '/base/index.php', - 'hostInfo' => 'http://example.com/', - 'url' => '/base/index.php&r=site%2Fcurrent&id=42' - ], - 'urlManager' => [ - 'class' => 'yii\web\UrlManager', - 'baseUrl' => '/base', - 'scriptUrl' => '/base/index.php', - 'hostInfo' => 'http://example.com/', - ] - ], - ], '\yii\web\Application'); - } - - /** - * Mocks controller action with parameters - * - * @param string $controllerId - * @param string $actionID - * @param string $moduleID - * @param array $params - */ - protected function mockAction($controllerId, $actionID, $moduleID = null, $params = []) - { - \Yii::$app->controller = $controller = new Controller($controllerId, \Yii::$app); - $controller->actionParams = $params; - $controller->action = new Action($actionID, $controller); - - if ($moduleID !== null) { - $controller->module = new Module($moduleID); - } - } - - protected function removeMockedAction() - { - \Yii::$app->controller = null; - } - - public function testToRoute() - { - $this->mockAction('page', 'view', null, ['id' => 10]); - - // If the route is an empty string, the current route will be used; - $this->assertEquals('/base/index.php?r=page%2Fview', Url::toRoute('')); - $this->assertEquals('http://example.com/base/index.php?r=page%2Fview', Url::toRoute('', true)); - $this->assertEquals('https://example.com/base/index.php?r=page%2Fview', Url::toRoute('', 'https')); - - // If the route contains no slashes at all, it is considered to be an action ID of the current controller and - // will be prepended with uniqueId; - $this->assertEquals('/base/index.php?r=page%2Fedit', Url::toRoute('edit')); - $this->assertEquals('/base/index.php?r=page%2Fedit&id=20', Url::toRoute(['edit', 'id' => 20])); - $this->assertEquals('http://example.com/base/index.php?r=page%2Fedit&id=20', Url::toRoute(['edit', 'id' => 20], true)); - $this->assertEquals('https://example.com/base/index.php?r=page%2Fedit&id=20', Url::toRoute(['edit', 'id' => 20], 'https')); - - // If the route has no leading slash, it is considered to be a route relative - // to the current module and will be prepended with the module's uniqueId. - $this->mockAction('default', 'index', 'stats'); - $this->assertEquals('/base/index.php?r=stats%2Fuser%2Fview', Url::toRoute('user/view')); - $this->assertEquals('/base/index.php?r=stats%2Fuser%2Fview&id=42', Url::toRoute(['user/view', 'id' => 42])); - $this->assertEquals('http://example.com/base/index.php?r=stats%2Fuser%2Fview&id=42', Url::toRoute(['user/view', 'id' => 42], true)); - $this->assertEquals('https://example.com/base/index.php?r=stats%2Fuser%2Fview&id=42', Url::toRoute(['user/view', 'id' => 42], 'https')); - - // alias support - \Yii::setAlias('@userView', 'user/view'); - $this->assertEquals('/base/index.php?r=stats%2Fuser%2Fview', Url::toRoute('@userView')); - \Yii::setAlias('@userView', null); - - // In case there is no controller, an exception should be thrown for relative route - $this->removeMockedAction(); - - $this->setExpectedException('yii\base\InvalidParamException'); - Url::toRoute('site/view'); - } - - public function testCurrent() - { - $this->mockAction('page', 'view', null, []); - \Yii::$app->request->setQueryParams(['id' => 10, 'name' => 'test']); - - $this->assertEquals('/base/index.php?r=page%2Fview&id=10&name=test', Url::current()); - - $this->assertEquals('/base/index.php?r=page%2Fview&id=20&name=test', Url::current(['id' => 20])); - - $this->assertEquals('/base/index.php?r=page%2Fview&name=test', Url::current(['id' => null])); - } - - public function testTo() - { - // is an array: the first array element is considered a route, while the rest of the name-value - // pairs are treated as the parameters to be used for URL creation using Url::toRoute. - $this->mockAction('page', 'view', null, ['id' => 10]); - $this->assertEquals('/base/index.php?r=page%2Fedit&id=20', Url::to(['edit', 'id' => 20])); - $this->assertEquals('/base/index.php?r=page%2Fedit', Url::to(['edit'])); - $this->assertEquals('/base/index.php?r=page%2Fview', Url::to([''])); - - // alias support - \Yii::setAlias('@pageEdit', 'edit'); - $this->assertEquals('/base/index.php?r=page%2Fedit&id=20', Url::to(['@pageEdit', 'id' => 20])); - \Yii::setAlias('@pageEdit', null); - - $this->assertEquals('http://example.com/base/index.php?r=page%2Fedit&id=20', Url::to(['edit', 'id' => 20], true)); - $this->assertEquals('http://example.com/base/index.php?r=page%2Fedit', Url::to(['edit'], true)); - $this->assertEquals('http://example.com/base/index.php?r=page%2Fview', Url::to([''], true)); - - $this->assertEquals('https://example.com/base/index.php?r=page%2Fedit&id=20', Url::to(['edit', 'id' => 20], 'https')); - $this->assertEquals('https://example.com/base/index.php?r=page%2Fedit', Url::to(['edit'], 'https')); - $this->assertEquals('https://example.com/base/index.php?r=page%2Fview', Url::to([''], 'https')); - - // is an empty string: the currently requested URL will be returned; - $this->mockAction('page', 'view', null, ['id' => 10]); - $this->assertEquals('/base/index.php&r=site%2Fcurrent&id=42', Url::to('')); - $this->assertEquals('http://example.com/base/index.php&r=site%2Fcurrent&id=42', Url::to('', true)); - $this->assertEquals('https://example.com/base/index.php&r=site%2Fcurrent&id=42', Url::to('', 'https')); - - // is a non-empty string: it will first be processed by [[Yii::getAlias()]]. If the result - // is an absolute URL, it will be returned either without any change or, if schema was specified, with schema - // replaced; Otherwise, the result will be prefixed with [[\yii\web\Request::baseUrl]] and returned. - \Yii::setAlias('@web1', 'http://test.example.com/test/me1'); - \Yii::setAlias('@web2', 'test/me2'); - \Yii::setAlias('@web3', ''); - \Yii::setAlias('@web4', '/test'); - \Yii::setAlias('@web5', '#test'); - - $this->assertEquals('test/me1', Url::to('test/me1')); - $this->assertEquals('javascript:test/me1', Url::to('javascript:test/me1')); - $this->assertEquals('java/script:test/me1', Url::to('java/script:test/me1')); - $this->assertEquals('#test/me1', Url::to('#test/me1')); - $this->assertEquals('.test/me1', Url::to('.test/me1')); - $this->assertEquals('http://example.com/test/me1', Url::to('test/me1', true)); - $this->assertEquals('https://example.com/test/me1', Url::to('test/me1', 'https')); - $this->assertEquals('https://example.com/test/test/me1', Url::to('@web4/test/me1', 'https')); - - $this->assertEquals('/test/me1', Url::to('/test/me1')); - $this->assertEquals('http://example.com/test/me1', Url::to('/test/me1', true)); - $this->assertEquals('https://example.com/test/me1', Url::to('/test/me1', 'https')); - $this->assertEquals('./test/me1', Url::to('./test/me1')); - - $this->assertEquals('http://test.example.com/test/me1', Url::to('@web1')); - $this->assertEquals('http://test.example.com/test/me1', Url::to('@web1', true)); - $this->assertEquals('https://test.example.com/test/me1', Url::to('@web1', 'https')); - - $this->assertEquals('test/me2', Url::to('@web2')); - $this->assertEquals('http://example.com/test/me2', Url::to('@web2', true)); - $this->assertEquals('https://example.com/test/me2', Url::to('@web2', 'https')); - - $this->assertEquals('/base/index.php&r=site%2Fcurrent&id=42', Url::to('@web3')); - $this->assertEquals('http://example.com/base/index.php&r=site%2Fcurrent&id=42', Url::to('@web3', true)); - $this->assertEquals('https://example.com/base/index.php&r=site%2Fcurrent&id=42', Url::to('@web3', 'https')); - - $this->assertEquals('/test', Url::to('@web4')); - $this->assertEquals('http://example.com/test', Url::to('@web4', true)); - $this->assertEquals('https://example.com/test', Url::to('@web4', 'https')); - - $this->assertEquals('#test', Url::to('@web5')); - $this->assertEquals('http://example.com/#test', Url::to('@web5', true)); - $this->assertEquals('https://example.com/#test', Url::to('@web5', 'https')); - - //In case there is no controller, throw an exception - $this->removeMockedAction(); - - $this->setExpectedException('yii\base\InvalidParamException'); - Url::to(['site/view']); - } - - public function testBase() - { - $this->mockAction('page', 'view', null, ['id' => 10]); - $this->assertEquals('/base', Url::base()); - $this->assertEquals('http://example.com/base', Url::base(true)); - $this->assertEquals('https://example.com/base', Url::base('https')); - } - - public function testHome() - { - $this->assertEquals('/base/index.php', Url::home()); - $this->assertEquals('http://example.com/base/index.php', Url::home(true)); - $this->assertEquals('https://example.com/base/index.php', Url::home('https')); - } - - public function testCanonical() - { - $this->mockAction('page', 'view', null, ['id' => 10]); - $this->assertEquals('http://example.com/base/index.php?r=page%2Fview&id=10', Url::canonical()); - $this->removeMockedAction(); - } -} diff --git a/tests/unit/framework/helpers/VarDumperTest.php b/tests/unit/framework/helpers/VarDumperTest.php deleted file mode 100644 index 6faff10..0000000 --- a/tests/unit/framework/helpers/VarDumperTest.php +++ /dev/null @@ -1,108 +0,0 @@ -assertEquals("stdClass#1\n(\n)", ob_get_contents()); - ob_end_clean(); - } - - /** - * Data provider for [[testExport()]] - * @return array test data - */ - public function dataProviderExport() - { - // Regular : - - $data = [ - [ - 'test string', - var_export('test string', true) - ], - [ - 75, - var_export(75, true) - ], - [ - 7.5, - var_export(7.5, true) - ], - [ - null, - 'null' - ], - [ - true, - 'true' - ], - [ - false, - 'false' - ], - [ - [], - '[]' - ], - ]; - - // Arrays : - - $var = [ - 'key1' => 'value1', - 'key2' => 'value2', - ]; - $expectedResult = << 'value1', - 'key2' => 'value2', -] -RESULT; - $data[] = [$var, $expectedResult]; - - $var = [ - 'value1', - 'value2', - ]; - $expectedResult = <<testField = 'Test Value'; - $expectedResult = "unserialize('" . serialize($var) . "')"; - $data[] = [$var, $expectedResult]; - - return $data; - } - - /** - * @dataProvider dataProviderExport - * - * @param mixed $var - * @param string $expectedResult - */ - public function testExport($var, $expectedResult) - { - $exportResult = VarDumper::export($var); - $this->assertEqualsWithoutLE($expectedResult, $exportResult); - $this->assertEquals($var, eval('return ' . $exportResult . ';')); - } -} diff --git a/tests/unit/framework/i18n/FallbackMessageFormatterTest.php b/tests/unit/framework/i18n/FallbackMessageFormatterTest.php deleted file mode 100644 index 5e9780c..0000000 --- a/tests/unit/framework/i18n/FallbackMessageFormatterTest.php +++ /dev/null @@ -1,179 +0,0 @@ - - * @since 2.0 - * @group i18n - */ -class FallbackMessageFormatterTest extends TestCase -{ - const N = 'n'; - const N_VALUE = 42; - const SUBJECT = 'сабж'; - const SUBJECT_VALUE = 'Answer to the Ultimate Question of Life, the Universe, and Everything'; - - public function patterns() - { - return [ - [ - '{'.self::SUBJECT.'} is {'.self::N.'}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - self::SUBJECT => self::SUBJECT_VALUE, - ] - ], - - [ - '{'.self::SUBJECT.'} is {'.self::N.', number}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - self::SUBJECT => self::SUBJECT_VALUE, - ] - ], - - [ - '{'.self::SUBJECT.'} is {'.self::N.', number, integer}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - self::SUBJECT => self::SUBJECT_VALUE, - ] - ], - - // This one was provided by Aura.Intl. Thanks! - [<<<_MSG_ -{gender_of_host, select, - female {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to her party.} - =2 {{host} invites {guest} and one other person to her party.} - other {{host} invites {guest} and # other people to her party.}}} - male {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to his party.} - =2 {{host} invites {guest} and one other person to his party.} - other {{host} invites {guest} and # other people to his party.}}} - other {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to their party.} - =2 {{host} invites {guest} and one other person to their party.} - other {{host} invites {guest} and # other people to their party.}}}} -_MSG_ - , - 'ralph invites beep and 3 other people to his party.', - [ - 'gender_of_host' => 'male', - 'num_guests' => 4, - 'host' => 'ralph', - 'guest' => 'beep' - ] - ], - - [ - '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', - 'Alexander is male and he loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - ], - ], - - // verify pattern in select does not get replaced - [ - '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', - 'Alexander is male and he loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - // following should not be replaced - 'he' => 'wtf', - 'she' => 'wtf', - 'it' => 'wtf', - ] - ], - - // verify pattern in select message gets replaced - [ - '{name} is {gender} and {gender, select, female{she} male{{he}} other{it}} loves Yii!', - 'Alexander is male and wtf loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - 'he' => 'wtf', - 'she' => 'wtf', - ], - ], - - // some parser specific verifications - [ - '{gender} and {gender, select, female{she} male{{he}} other{it}} loves {nr} is {gender}!', - 'male and wtf loves 42 is male!', - [ - 'nr' => 42, - 'gender' => 'male', - 'he' => 'wtf', - 'she' => 'wtf', - ], - ], - ]; - } - - /** - * @dataProvider patterns - */ - public function testNamedArguments($pattern, $expected, $args) - { - $formatter = new FallbackMessageFormatter(); - $result = $formatter->fallbackFormat($pattern, $args, 'en-US'); - $this->assertEquals($expected, $result, $formatter->getErrorMessage()); - } - - public function testInsufficientArguments() - { - $expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; - - $formatter = new FallbackMessageFormatter(); - $result = $formatter->fallbackFormat('{'.self::SUBJECT.'} is {'.self::N.'}', [ - self::N => self::N_VALUE, - ], 'en-US'); - - $this->assertEquals($expected, $result); - } - - public function testNoParams() - { - $pattern = '{'.self::SUBJECT.'} is '.self::N; - - $formatter = new FallbackMessageFormatter(); - $result = $formatter->fallbackFormat($pattern, [], 'en-US'); - $this->assertEquals($pattern, $result, $formatter->getErrorMessage()); - } - - public function testGridViewMessage() - { - $pattern = 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.'; - $formatter = new FallbackMessageFormatter(); - $result = $formatter->fallbackFormat($pattern, ['begin' => 1, 'end' => 5, 'totalCount' => 10], 'en-US'); - $this->assertEquals('Showing 1-5 of 10 items.', $result); - } -} - -class FallbackMessageFormatter extends MessageFormatter -{ - public function fallbackFormat($pattern, $args, $locale) - { - return parent::fallbackFormat($pattern, $args, $locale); - } -} diff --git a/tests/unit/framework/i18n/FormatterDateTest.php b/tests/unit/framework/i18n/FormatterDateTest.php deleted file mode 100644 index 410ee3d..0000000 --- a/tests/unit/framework/i18n/FormatterDateTest.php +++ /dev/null @@ -1,575 +0,0 @@ -mockApplication([ - 'timeZone' => 'UTC', - 'language' => 'ru-RU', - ]); - $this->formatter = new Formatter(['locale' => 'en-US']); - } - - protected function tearDown() - { - parent::tearDown(); - IntlTestHelper::resetIntlStatus(); - $this->formatter = null; - } - - - public function testFormat() - { - $value = time(); - $this->assertSame(date('M j, Y', $value), $this->formatter->format($value, 'date')); - $this->assertSame(date('M j, Y', $value), $this->formatter->format($value, 'DATE')); - $this->assertSame(date('Y/m/d', $value), $this->formatter->format($value, ['date', 'php:Y/m/d'])); - $this->setExpectedException('\yii\base\InvalidParamException'); - $this->assertSame(date('Y-m-d', $value), $this->formatter->format($value, 'data')); - } - - public function testIntlAsDate() - { - $this->testAsDate(); - } - - public function testAsDate() - { - $value = time(); - $this->assertSame(date('M j, Y', $value), $this->formatter->asDate($value)); - $this->assertSame(date('Y/m/d', $value), $this->formatter->asDate($value, 'php:Y/m/d')); - $this->assertSame(date('m/d/Y', $value), $this->formatter->asDate($value, 'MM/dd/yyyy')); - $this->assertSame(date('n/j/y', $value), $this->formatter->asDate($value, 'short')); - $this->assertSame(date('F j, Y', $value), $this->formatter->asDate($value, 'long')); - - $value = new DateTime(); - $this->assertSame(date('M j, Y', $value->getTimestamp()), $this->formatter->asDate($value)); - $this->assertSame(date('Y/m/d', $value->getTimestamp()), $this->formatter->asDate($value, 'php:Y/m/d')); - $this->assertSame(date('m/d/Y', $value->getTimestamp()), $this->formatter->asDate($value, 'MM/dd/yyyy')); - $this->assertSame(date('n/j/y', $value->getTimestamp()), $this->formatter->asDate($value, 'short')); - $this->assertSame(date('F j, Y', $value->getTimestamp()), $this->formatter->asDate($value, 'long')); - - if (version_compare(PHP_VERSION, '5.5.0', '>=')) { - $value = new \DateTimeImmutable(); - $this->assertSame(date('M j, Y', $value->getTimestamp()), $this->formatter->asDate($value)); - $this->assertSame(date('Y/m/d', $value->getTimestamp()), $this->formatter->asDate($value, 'php:Y/m/d')); - $this->assertSame(date('m/d/Y', $value->getTimestamp()), $this->formatter->asDate($value, 'MM/dd/yyyy')); - $this->assertSame(date('n/j/y', $value->getTimestamp()), $this->formatter->asDate($value, 'short')); - $this->assertSame(date('F j, Y', $value->getTimestamp()), $this->formatter->asDate($value, 'long')); - } - - // empty input - $this->assertSame('Jan 1, 1970', $this->formatter->asDate('')); - $this->assertSame('Jan 1, 1970', $this->formatter->asDate(0)); - $this->assertSame('Jan 1, 1970', $this->formatter->asDate(false)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDate(null)); - } - - public function testIntlAsTime() - { - $this->testAsTime(); - - // empty input - $this->formatter->locale = 'de-DE'; - $this->assertSame('00:00:00', $this->formatter->asTime('')); - $this->assertSame('00:00:00', $this->formatter->asTime(0)); - $this->assertSame('00:00:00', $this->formatter->asTime(false)); - } - - public function testAsTime() - { - $value = time(); - $this->assertSame(date('g:i:s A', $value), $this->formatter->asTime($value)); - $this->assertSame(date('h:i:s A', $value), $this->formatter->asTime($value, 'php:h:i:s A')); - - $value = new DateTime(); - $this->assertSame(date('g:i:s A', $value->getTimestamp()), $this->formatter->asTime($value)); - $this->assertSame(date('h:i:s A', $value->getTimestamp()), $this->formatter->asTime($value, 'php:h:i:s A')); - - if (version_compare(PHP_VERSION, '5.5.0', '>=')) { - $value = new \DateTimeImmutable(); - $this->assertSame(date('g:i:s A', $value->getTimestamp()), $this->formatter->asTime($value)); - $this->assertSame(date('h:i:s A', $value->getTimestamp()), $this->formatter->asTime($value, 'php:h:i:s A')); - } - - // empty input - $this->assertSame('12:00:00 AM', $this->formatter->asTime('')); - $this->assertSame('12:00:00 AM', $this->formatter->asTime(0)); - $this->assertSame('12:00:00 AM', $this->formatter->asTime(false)); - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asTime(null)); - } - - public function testIntlAsDatetime() - { - $this->testAsDatetime(); - - // empty input - $this->formatter->locale = 'de-DE'; - $this->assertSame('01.01.1970 00:00:00', $this->formatter->asDatetime('')); - $this->assertSame('01.01.1970 00:00:00', $this->formatter->asDatetime(0)); - $this->assertSame('01.01.1970 00:00:00', $this->formatter->asDatetime(false)); - } - - public function testAsDatetime() - { - $value = time(); - $this->assertSame(date('M j, Y g:i:s A', $value), $this->formatter->asDatetime($value)); - $this->assertSame(date('Y/m/d h:i:s A', $value), $this->formatter->asDatetime($value, 'php:Y/m/d h:i:s A')); - - $value = new DateTime(); - $this->assertSame(date('M j, Y g:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value)); - $this->assertSame(date('Y/m/d h:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value, 'php:Y/m/d h:i:s A')); - - if (version_compare(PHP_VERSION, '5.5.0', '>=')) { - $value = new \DateTimeImmutable(); - $this->assertSame(date('M j, Y g:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value)); - $this->assertSame(date('Y/m/d h:i:s A', $value->getTimestamp()), $this->formatter->asDatetime($value, 'php:Y/m/d h:i:s A')); - } - - // empty input - $this->assertSame('Jan 1, 1970 12:00:00 AM', $this->formatter->asDatetime('')); - $this->assertSame('Jan 1, 1970 12:00:00 AM', $this->formatter->asDatetime(0)); - $this->assertSame('Jan 1, 1970 12:00:00 AM', $this->formatter->asDatetime(false)); - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDatetime(null)); - } - - public function testIntlAsTimestamp() - { - $this->testAsTimestamp(); - } - - public function testAsTimestamp() - { - $value = time(); - $this->assertSame("$value", $this->formatter->asTimestamp($value)); - $this->assertSame("$value", $this->formatter->asTimestamp((string) $value)); - - $this->assertSame("$value", $this->formatter->asTimestamp(date('Y-m-d H:i:s', $value))); - - // empty input - $this->assertSame("0", $this->formatter->asTimestamp(0)); - $this->assertSame("0", $this->formatter->asTimestamp(false)); - $this->assertSame("0", $this->formatter->asTimestamp("")); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asTimestamp(null)); - } - - public function testIntlDateRangeLow() - { - // intl does not support high date ranges on 32bit systems, the implementation uses a fallback to PHP formatter - $this->testDateRangeLow(); - } - - /** - * Test for dates before 1970 - * https://github.com/yiisoft/yii2/issues/3126 - */ - public function testDateRangeLow() - { - // http://en.wikipedia.org/wiki/Year_2038_problem - $this->assertSame('13-12-1901', $this->formatter->asDate('1901-12-13', 'dd-MM-yyyy')); - $this->assertSame('12-12-1901', $this->formatter->asDate('1901-12-12', 'dd-MM-yyyy')); - - $this->assertSame('12-08-1922', $this->formatter->asDate('1922-08-12', 'dd-MM-yyyy')); - $this->assertSame('14-01-1732', $this->formatter->asDate('1732-01-14', 'dd-MM-yyyy')); - } - - public function testIntlDateRangeHigh() - { - // intl does not support high date ranges on 32bit systems, the implementation uses a fallback to PHP formatter - $this->testDateRangeHigh(); - } - - /** - * Test for dates after 2038 - * https://github.com/yiisoft/yii2/issues/3126 - */ - public function testDateRangeHigh() - { - // http://en.wikipedia.org/wiki/Year_2038_problem - $this->assertSame('19-01-2038', $this->formatter->asDate('2038-01-19', 'dd-MM-yyyy')); - $this->assertSame('20-01-2038', $this->formatter->asDate('2038-01-20', 'dd-MM-yyyy')); - - $this->assertSame('17-12-2048', $this->formatter->asDate('2048-12-17', 'dd-MM-yyyy')); - $this->assertSame('17-12-3048', $this->formatter->asDate('3048-12-17', 'dd-MM-yyyy')); - $this->assertSame('31-12-9999', $this->formatter->asDate('9999-12-31', 'dd-MM-yyyy')); - } - - private function buildDateSubIntervals($referenceDate, $intervals) - { - $date = new DateTime($referenceDate); - foreach ($intervals as $interval) { - $date->sub($interval); - } - return $date; - } - - public function testIntlAsRelativeTime() - { - $this->testAsRelativeTime(); - } - - public function testAsRelativeTime() - { - $interval_1_second = new DateInterval("PT1S"); - $interval_244_seconds = new DateInterval("PT244S"); - $interval_1_minute = new DateInterval("PT1M"); - $interval_33_minutes = new DateInterval("PT33M"); - $interval_1_hour = new DateInterval("PT1H"); - $interval_6_hours = new DateInterval("PT6H"); - $interval_1_day = new DateInterval("P1D"); - $interval_89_days = new DateInterval("P89D"); - $interval_1_month = new DateInterval("P1M"); - $interval_5_months = new DateInterval("P5M"); - $interval_1_year = new DateInterval("P1Y"); - $interval_12_years = new DateInterval("P12Y"); - - // Pass a DateInterval - $this->assertSame('a second ago', $this->formatter->asRelativeTime($interval_1_second)); - $this->assertSame('244 seconds ago', $this->formatter->asRelativeTime($interval_244_seconds)); - $this->assertSame('a minute ago', $this->formatter->asRelativeTime($interval_1_minute)); - $this->assertSame('33 minutes ago', $this->formatter->asRelativeTime($interval_33_minutes)); - $this->assertSame('an hour ago', $this->formatter->asRelativeTime($interval_1_hour)); - $this->assertSame('6 hours ago', $this->formatter->asRelativeTime($interval_6_hours)); - $this->assertSame('a day ago', $this->formatter->asRelativeTime($interval_1_day)); - $this->assertSame('89 days ago', $this->formatter->asRelativeTime($interval_89_days)); - $this->assertSame('a month ago', $this->formatter->asRelativeTime($interval_1_month)); - $this->assertSame('5 months ago', $this->formatter->asRelativeTime($interval_5_months)); - $this->assertSame('a year ago', $this->formatter->asRelativeTime($interval_1_year)); - $this->assertSame('12 years ago', $this->formatter->asRelativeTime($interval_12_years)); - - // Pass a DateInterval string -> isn't possible - // $this->assertSame('a year ago', $this->formatter->asRelativeTime('2007-03-01T13:00:00Z/2008-05-11T15:30:00Z')); - // $this->assertSame('a year ago', $this->formatter->asRelativeTime('2007-03-01T13:00:00Z/P1Y2M10DT2H30M')); - // $this->assertSame('a year ago', $this->formatter->asRelativeTime('P1Y2M10DT2H30M/2008-05-11T15:30:00Z')); - // $this->assertSame('a year ago', $this->formatter->asRelativeTime('P1Y2M10DT2H30M')); - // $this->assertSame('94 months ago', $this->formatter->asRelativeTime('P94M')); - - // Force the reference time and pass a past DateTime - $dateNow = new DateTime('2014-03-13'); - $this->assertSame('a second ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_second]), $dateNow)); - $this->assertSame('4 minutes ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_244_seconds]), $dateNow)); - $this->assertSame('a minute ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_minute]), $dateNow)); - $this->assertSame('33 minutes ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_33_minutes]), $dateNow)); - $this->assertSame('an hour ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_hour]), $dateNow)); - $this->assertSame('6 hours ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_6_hours]), $dateNow)); - $this->assertSame('a day ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_day]), $dateNow)); - $this->assertSame('2 months ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_89_days]), $dateNow)); - $this->assertSame('a month ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_month]), $dateNow)); - $this->assertSame('5 months ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_5_months]), $dateNow)); - $this->assertSame('a year ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_year]), $dateNow)); - $this->assertSame('12 years ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_12_years]), $dateNow)); - - // Tricky 31-days month stuff - // See: http://www.gnu.org/software/tar/manual/html_section/Relative-items-in-date-strings.html - $dateNow = new DateTime('2014-03-31'); - $dateThen = new DateTime('2014-03-03'); - $this->assertSame('28 days ago', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-31', [$interval_1_month]), $dateNow)); - $this->assertSame('28 days ago', $this->formatter->asRelativeTime($dateThen, $dateNow)); - $dateThen = new DateTime('2014-02-28'); - $this->assertSame('a month ago', $this->formatter->asRelativeTime($dateThen, $dateNow)); - - // Invert all the DateIntervals - $interval_1_second->invert = true; - $interval_244_seconds->invert = true; - $interval_1_minute->invert = true; - $interval_33_minutes->invert = true; - $interval_1_hour->invert = true; - $interval_6_hours->invert = true; - $interval_1_day->invert = true; - $interval_89_days->invert = true; - $interval_1_month->invert = true; - $interval_5_months->invert = true; - $interval_1_year->invert = true; - $interval_12_years->invert = true; - - // Pass a inverted DateInterval - $this->assertSame('in a second', $this->formatter->asRelativeTime($interval_1_second)); - $this->assertSame('in 244 seconds', $this->formatter->asRelativeTime($interval_244_seconds)); - $this->assertSame('in a minute', $this->formatter->asRelativeTime($interval_1_minute)); - $this->assertSame('in 33 minutes', $this->formatter->asRelativeTime($interval_33_minutes)); - $this->assertSame('in an hour', $this->formatter->asRelativeTime($interval_1_hour)); - $this->assertSame('in 6 hours', $this->formatter->asRelativeTime($interval_6_hours)); - $this->assertSame('in a day', $this->formatter->asRelativeTime($interval_1_day)); - $this->assertSame('in 89 days', $this->formatter->asRelativeTime($interval_89_days)); - $this->assertSame('in a month', $this->formatter->asRelativeTime($interval_1_month)); - $this->assertSame('in 5 months', $this->formatter->asRelativeTime($interval_5_months)); - $this->assertSame('in a year', $this->formatter->asRelativeTime($interval_1_year)); - $this->assertSame('in 12 years', $this->formatter->asRelativeTime($interval_12_years)); - - // Pass a inverted DateInterval string - // $this->assertSame('in a year', $this->formatter->asRelativeTime('2008-05-11T15:30:00Z/2007-03-01T13:00:00Z')); - - // Force the reference time and pass a future DateTime - $dateNow = new DateTime('2014-03-13'); - $this->assertSame('in a second', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_second]), $dateNow)); - $this->assertSame('in 4 minutes', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_244_seconds]), $dateNow)); - $this->assertSame('in a minute', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_minute]), $dateNow)); - $this->assertSame('in 33 minutes', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_33_minutes]), $dateNow)); - $this->assertSame('in an hour', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_hour]), $dateNow)); - $this->assertSame('in 6 hours', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_6_hours]), $dateNow)); - $this->assertSame('in a day', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_day]), $dateNow)); - $this->assertSame('in 2 months', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_89_days]), $dateNow)); - $this->assertSame('in a month', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_month]), $dateNow)); - $this->assertSame('in 5 months', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_5_months]), $dateNow)); - $this->assertSame('in a year', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_1_year]), $dateNow)); - $this->assertSame('in 12 years', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-13', [$interval_12_years]), $dateNow)); - - // Tricky 31-days month stuff - // See: http://www.gnu.org/software/tar/manual/html_section/Relative-items-in-date-strings.html - $dateNow = new DateTime('2014-03-03'); - $dateThen = new DateTime('2014-03-31'); - $this->assertSame('in a month', $this->formatter->asRelativeTime($this->buildDateSubIntervals('2014-03-03', [$interval_1_month]), $dateNow)); - $this->assertSame('in 28 days', $this->formatter->asRelativeTime($dateThen, $dateNow)); - - // just now - $this->assertSame("just now", $this->formatter->asRelativeTime($t = time(), $t)); - $this->assertSame("just now", $this->formatter->asRelativeTime(0, 0)); - - // empty input - $this->assertSame("just now", $this->formatter->asRelativeTime(false, 0)); - $this->assertSame("just now", $this->formatter->asRelativeTime("", 0)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asRelativeTime(null)); - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asRelativeTime(null, time())); - } - - public function dateInputs() - { - return [ - ['2015-01-01 00:00:00', '2014-13-01 00:00:00'], - [false, 'asdfg', 'yii\base\InvalidParamException'], -// [(string)strtotime('now'), 'now'], // fails randomly - ]; - } - - /** - * @dataProvider dateInputs - */ - public function testIntlDateInput($expected, $value, $expectedException = null) - { - $this->testDateInput($expected, $value, $expectedException); - } - - /** - * @dataProvider dateInputs - */ - public function testDateInput($expected, $value, $expectedException = null) - { - if ($expectedException !== null) { - $this->setExpectedException($expectedException); - } - $this->assertSame($expected, $this->formatter->asDate($value, 'yyyy-MM-dd HH:mm:ss')); - $this->assertSame($expected, $this->formatter->asTime($value, 'yyyy-MM-dd HH:mm:ss')); - $this->assertSame($expected, $this->formatter->asDatetime($value, 'yyyy-MM-dd HH:mm:ss')); - } - - - public function provideTimezones() - { - return [ - ['UTC'], - ['Europe/Berlin'], - ['America/Jamaica'], - ]; - } - - /** - * provide default timezones times input date value - */ - public function provideTimesAndTz() - { - $utc = new \DateTimeZone('UTC'); - $berlin = new \DateTimeZone('Europe/Berlin'); - $result = []; - foreach($this->provideTimezones() as $tz) { - $result[] = [$tz[0], 1407674460, 1388580060]; - $result[] = [$tz[0], '2014-08-10 12:41:00', '2014-01-01 12:41:00']; - $result[] = [$tz[0], '2014-08-10 12:41:00 UTC', '2014-01-01 12:41:00 UTC']; - $result[] = [$tz[0], '2014-08-10 14:41:00 Europe/Berlin', '2014-01-01 13:41:00 Europe/Berlin']; - $result[] = [$tz[0], '2014-08-10 14:41:00 CEST', '2014-01-01 13:41:00 CET']; - $result[] = [$tz[0], '2014-08-10 14:41:00+0200', '2014-01-01 13:41:00+0100']; - $result[] = [$tz[0], '2014-08-10 14:41:00+02:00', '2014-01-01 13:41:00+01:00']; - $result[] = [$tz[0], '2014-08-10 14:41:00 +0200', '2014-01-01 13:41:00 +0100']; - $result[] = [$tz[0], '2014-08-10 14:41:00 +02:00', '2014-01-01 13:41:00 +01:00']; - $result[] = [$tz[0], '2014-08-10T14:41:00+02:00', '2014-01-01T13:41:00+01:00']; // ISO 8601 - $result[] = [$tz[0], new DateTime('2014-08-10 12:41:00', $utc), new DateTime('2014-01-01 12:41:00', $utc)]; - $result[] = [$tz[0], new DateTime('2014-08-10 14:41:00', $berlin), new DateTime('2014-01-01 13:41:00', $berlin)]; - if (version_compare(PHP_VERSION, '5.5.0', '>=')) { - $result[] = [$tz[0], new \DateTimeImmutable('2014-08-10 12:41:00', $utc), new \DateTimeImmutable('2014-01-01 12:41:00', $utc)]; - $result[] = [$tz[0], new \DateTimeImmutable('2014-08-10 14:41:00', $berlin), new \DateTimeImmutable('2014-01-01 13:41:00', $berlin)]; - } - } - return $result; - } - - /** - * Test timezones with input date and time in other timezones - * @dataProvider provideTimesAndTz - */ - public function testIntlTimezoneInput($defaultTz, $inputTimeDst, $inputTimeNonDst) - { - $this->testTimezoneInput($defaultTz, $inputTimeDst, $inputTimeNonDst); - } - - /** - * Test timezones with input date and time in other timezones - * @dataProvider provideTimesAndTz - */ - public function testTimezoneInput($defaultTz, $inputTimeDst, $inputTimeNonDst) - { - date_default_timezone_set($defaultTz); // formatting has to be independent of the default timezone set by PHP - $this->formatter->datetimeFormat = 'yyyy-MM-dd HH:mm:ss'; - $this->formatter->dateFormat = 'yyyy-MM-dd'; - $this->formatter->timeFormat = 'HH:mm:ss'; - - // daylight saving time - $this->formatter->timeZone = 'UTC'; - $this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime($inputTimeDst)); - $this->assertSame('2014-08-10', $this->formatter->asDate($inputTimeDst)); - $this->assertSame('12:41:00', $this->formatter->asTime($inputTimeDst)); - $this->assertSame('1407674460', $this->formatter->asTimestamp($inputTimeDst)); - $this->formatter->timeZone = 'Europe/Berlin'; - $this->assertSame('2014-08-10 14:41:00', $this->formatter->asDatetime($inputTimeDst)); - $this->assertSame('2014-08-10', $this->formatter->asDate($inputTimeDst)); - $this->assertSame('14:41:00', $this->formatter->asTime($inputTimeDst)); - $this->assertSame('1407674460', $this->formatter->asTimestamp($inputTimeDst)); - - // non daylight saving time - $this->formatter->timeZone = 'UTC'; - $this->assertSame('2014-01-01 12:41:00', $this->formatter->asDatetime($inputTimeNonDst)); - $this->assertSame('2014-01-01', $this->formatter->asDate($inputTimeNonDst)); - $this->assertSame('12:41:00', $this->formatter->asTime($inputTimeNonDst)); - $this->assertSame('1388580060', $this->formatter->asTimestamp($inputTimeNonDst)); - $this->formatter->timeZone = 'Europe/Berlin'; - $this->assertSame('2014-01-01 13:41:00', $this->formatter->asDatetime($inputTimeNonDst)); - $this->assertSame('2014-01-01', $this->formatter->asDate($inputTimeNonDst)); - $this->assertSame('13:41:00', $this->formatter->asTime($inputTimeNonDst)); - $this->assertSame('1388580060', $this->formatter->asTimestamp($inputTimeNonDst)); - - // tests for relative time - if ($inputTimeDst !== 1407674460 && !is_object($inputTimeDst)) { - $this->assertSame('3 hours ago', $this->formatter->asRelativeTime($inputTimeDst, $relativeTime = str_replace(['14:41', '12:41'], ['17:41', '15:41'], $inputTimeDst))); - $this->assertSame('in 3 hours', $this->formatter->asRelativeTime($relativeTime, $inputTimeDst)); - $this->assertSame('3 hours ago', $this->formatter->asRelativeTime($inputTimeNonDst, $relativeTime = str_replace(['13:41', '12:41'], ['16:41', '15:41'], $inputTimeNonDst))); - $this->assertSame('in 3 hours', $this->formatter->asRelativeTime($relativeTime, $inputTimeNonDst)); - } - } - - - /** - * Test timezones with input date and time in other timezones - */ - public function testTimezoneInputNonDefault() - { - $this->formatter->datetimeFormat = 'yyyy-MM-dd HH:mm:ss'; - $this->formatter->dateFormat = 'yyyy-MM-dd'; - $this->formatter->timeFormat = 'HH:mm:ss'; - - $this->formatter->timeZone = 'UTC'; - $this->formatter->defaultTimeZone = 'UTC'; - $this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00')); - $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00')); - $this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00')); - $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 12:41:00')); - - $this->assertSame('2014-08-10 10:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00 Europe/Berlin')); - $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00 Europe/Berlin')); - $this->assertSame('10:41:00', $this->formatter->asTime('2014-08-10 12:41:00 Europe/Berlin')); - $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00 Europe/Berlin')); - - $this->formatter->timeZone = 'Europe/Berlin'; - $this->formatter->defaultTimeZone = 'Europe/Berlin'; - $this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00')); - $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00')); - $this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00')); - $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00')); - - $this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00 Europe/Berlin')); - $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00 Europe/Berlin')); - $this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00 Europe/Berlin')); - $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00 Europe/Berlin')); - - $this->formatter->timeZone = 'UTC'; - $this->formatter->defaultTimeZone = 'Europe/Berlin'; - $this->assertSame('2014-08-10 10:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00')); - $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00')); - $this->assertSame('10:41:00', $this->formatter->asTime('2014-08-10 12:41:00')); - $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 14:41:00')); - - $this->assertSame('2014-08-10 12:41:00', $this->formatter->asDatetime('2014-08-10 12:41:00 UTC')); - $this->assertSame('2014-08-10', $this->formatter->asDate('2014-08-10 12:41:00 UTC')); - $this->assertSame('12:41:00', $this->formatter->asTime('2014-08-10 12:41:00 UTC')); - $this->assertSame('1407674460', $this->formatter->asTimestamp('2014-08-10 12:41:00 UTC')); - } - - - public function testDateOnlyValues() - { - date_default_timezone_set('Pacific/Kiritimati'); - // timzones with exactly 24h difference, ensure this test does not fail on a certain time - $this->formatter->defaultTimeZone = 'Pacific/Kiritimati'; // always UTC+14 - $this->formatter->timeZone = 'Pacific/Honolulu'; // always UTC-10 - - // when timezone conversion is made on this date, it will result in 2014-07-31 to be returned. - // ensure this does not happen on date only values - $this->assertSame('2014-08-01', $this->formatter->asDate('2014-08-01', 'yyyy-MM-dd')); - - date_default_timezone_set('Pacific/Honolulu'); - $this->formatter->defaultTimeZone = 'Pacific/Honolulu'; // always UTC-10 - $this->formatter->timeZone = 'Pacific/Kiritimati'; // always UTC+14 - $this->assertSame('2014-08-01', $this->formatter->asDate('2014-08-01', 'yyyy-MM-dd')); - } - - /** - * https://github.com/yiisoft/yii2/issues/6263 - * - * it is a PHP bug: https://bugs.php.net/bug.php?id=45543 - * Fixed in this commit: https://github.com/php/php-src/commit/22dba2f5f3211efe6c3b9bb24734c811ca64c68c#diff-7b738accc3d60f74c259da18588ddc5dL2996 - * Fixed in PHP >5.4.26 and >5.5.10. http://3v4l.org/mlZX7 - * - * @dataProvider provideTimezones - */ - public function testIssue6263($dtz) - { - $this->formatter->defaultTimeZone = $dtz; - - $this->formatter->timeZone = 'UTC'; - $this->assertEquals('24.11.2014 11:48:53', $this->formatter->format(1416829733, ['date', 'php:d.m.Y H:i:s'])); - $this->formatter->timeZone = 'Europe/Berlin'; - $this->assertEquals('24.11.2014 12:48:53', $this->formatter->format(1416829733, ['date', 'php:d.m.Y H:i:s'])); - - $this->assertFalse(DateTime::createFromFormat('Y-m-d', 1416829733)); - $this->assertFalse(DateTime::createFromFormat('Y-m-d', '2014-05-08 12:48:53')); - $this->assertFalse(DateTime::createFromFormat('Y-m-d H:i:s', 1416829733)); - $this->assertFalse(DateTime::createFromFormat('Y-m-d H:i:s', '2014-05-08')); - } - -} diff --git a/tests/unit/framework/i18n/FormatterNumberTest.php b/tests/unit/framework/i18n/FormatterNumberTest.php deleted file mode 100644 index e07a392..0000000 --- a/tests/unit/framework/i18n/FormatterNumberTest.php +++ /dev/null @@ -1,509 +0,0 @@ -mockApplication([ - 'timeZone' => 'UTC', - 'language' => 'ru-RU', - ]); - $this->formatter = new Formatter(['locale' => 'en-US']); - } - - protected function tearDown() - { - parent::tearDown(); - IntlTestHelper::resetIntlStatus(); - $this->formatter = null; - } - - /** - * Provides some configuration that should not affect Integer formatter - */ - public function differentConfigProvider() - { - // make this test not break when intl is not installed - if (!extension_loaded('intl')) { - return []; - } - - return [ - [[ - 'numberFormatterOptions' => [ - NumberFormatter::MIN_FRACTION_DIGITS => 2, - ], - ]], - [[ - 'numberFormatterOptions' => [ - NumberFormatter::MAX_FRACTION_DIGITS => 2, - ], - ]], - [[ - 'numberFormatterOptions' => [ - NumberFormatter::FRACTION_DIGITS => 2, - ], - ]], - [[ - 'numberFormatterOptions' => [ - NumberFormatter::MIN_FRACTION_DIGITS => 2, - NumberFormatter::MAX_FRACTION_DIGITS => 4, - ], - ]], - ]; - } - - - /** - * @dataProvider differentConfigProvider - */ - public function testIntlAsInteger($config) - { - // configure formatter with different configs that should not affect integer format - Yii::configure($this->formatter, $config); - $this->testAsInteger(); - } - - public function testAsInteger() - { - $this->assertSame("123", $this->formatter->asInteger(123)); - $this->assertSame("123", $this->formatter->asInteger(123.23)); - $this->assertSame("123", $this->formatter->asInteger(123.53)); - $this->assertSame("0", $this->formatter->asInteger(0)); - $this->assertSame("-123", $this->formatter->asInteger(-123.23)); - $this->assertSame("-123", $this->formatter->asInteger(-123.53)); - - $this->assertSame("123,456", $this->formatter->asInteger(123456)); - $this->assertSame("123,456", $this->formatter->asInteger(123456.789)); - - // empty input - $this->assertSame("0", $this->formatter->asInteger(false)); - $this->assertSame("0", $this->formatter->asInteger("")); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asInteger(null)); - } - - /** - * @expectedException \yii\base\InvalidParamException - */ - public function testAsIntegerException() - { - $this->formatter->asInteger('a'); - } - - /** - * @expectedException \yii\base\InvalidParamException - */ - public function testAsIntegerException2() - { - $this->formatter->asInteger('-123abc'); - } - - public function testIntlAsDecimal() - { - $value = 123.12; - $this->assertSame("123.12", $this->formatter->asDecimal($value, 2)); - $this->assertSame("123.1", $this->formatter->asDecimal($value, 1)); - $this->assertSame("123", $this->formatter->asDecimal($value, 0)); - - $value = 123; - $this->assertSame("123", $this->formatter->asDecimal($value)); - $this->assertSame("123.00", $this->formatter->asDecimal($value, 2)); - $this->formatter->decimalSeparator = ','; - $this->formatter->thousandSeparator = '.'; - $value = 123.12; - $this->assertSame("123,12", $this->formatter->asDecimal($value)); - $this->assertSame("123,1", $this->formatter->asDecimal($value, 1)); - $this->assertSame("123", $this->formatter->asDecimal($value, 0)); - $value = 123123.123; - $this->assertSame("123.123", $this->formatter->asDecimal($value, 0)); - $this->assertSame("123.123,12", $this->formatter->asDecimal($value, 2)); - $this->formatter->thousandSeparator = ''; - $this->assertSame("123123,1", $this->formatter->asDecimal($value, 1)); - $this->formatter->thousandSeparator = ' '; - $this->assertSame("12 31 23,1", $this->formatter->asDecimal($value, 1, [\NumberFormatter::GROUPING_SIZE => 2])); - - $value = 123123.123; - $this->formatter->decimalSeparator = ','; - $this->formatter->thousandSeparator = ' '; - $this->assertSame("123 123", $this->formatter->asDecimal($value, 0)); - $this->assertSame("123 123,12", $this->formatter->asDecimal($value, 2)); - - $this->formatter->decimalSeparator = null; - $this->formatter->thousandSeparator = null; - $value = '-123456.123'; - $this->assertSame("-123,456.123", $this->formatter->asDecimal($value)); - - // empty input - $this->assertSame("0", $this->formatter->asInteger(false)); - $this->assertSame("0", $this->formatter->asInteger("")); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDecimal(null)); - } - - public function testAsDecimal() - { - $value = 123.12; - $this->assertSame("123.12", $this->formatter->asDecimal($value)); - $this->assertSame("123.1", $this->formatter->asDecimal($value, 1)); - $this->assertSame("123", $this->formatter->asDecimal($value, 0)); - $value = 123; - $this->assertSame("123.00", $this->formatter->asDecimal($value)); - $this->formatter->decimalSeparator = ','; - $this->formatter->thousandSeparator = '.'; - $value = 123.12; - $this->assertSame("123,12", $this->formatter->asDecimal($value)); - $this->assertSame("123,1", $this->formatter->asDecimal($value, 1)); - $this->assertSame("123", $this->formatter->asDecimal($value, 0)); - $value = 123123.123; - $this->assertSame("123.123,12", $this->formatter->asDecimal($value)); - - $value = 123123.123; - $this->assertSame("123.123,12", $this->formatter->asDecimal($value)); - $this->assertSame("123.123,12", $this->formatter->asDecimal($value, 2)); - $this->formatter->decimalSeparator = ','; - $this->formatter->thousandSeparator = ' '; - $this->assertSame("123 123,12", $this->formatter->asDecimal($value)); - $this->assertSame("123 123,12", $this->formatter->asDecimal($value, 2)); - $this->formatter->thousandSeparator = ''; - $this->assertSame("123123,12", $this->formatter->asDecimal($value)); - $this->assertSame("123123,12", $this->formatter->asDecimal($value, 2)); - - $this->formatter->decimalSeparator = null; - $this->formatter->thousandSeparator = null; - $value = '-123456.123'; - $this->assertSame("-123,456.123", $this->formatter->asDecimal($value, 3)); - - // empty input - $this->assertSame("0", $this->formatter->asInteger(false)); - $this->assertSame("0", $this->formatter->asInteger("")); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asDecimal(null)); - } - - public function testIntlAsPercent() - { - $this->testAsPercent(); - } - - public function testAsPercent() - { - $this->assertSame('12,300%', $this->formatter->asPercent(123)); - $this->assertSame('12,300%', $this->formatter->asPercent('123')); - $this->assertSame("12%", $this->formatter->asPercent(0.1234)); - $this->assertSame("12%", $this->formatter->asPercent('0.1234')); - $this->assertSame("-1%", $this->formatter->asPercent(-0.009343)); - $this->assertSame("-1%", $this->formatter->asPercent('-0.009343')); - - // empty input - $this->assertSame("0", $this->formatter->asInteger(false)); - $this->assertSame("0", $this->formatter->asInteger("")); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asPercent(null)); - } - - public function testIntlAsCurrency() - { - $this->formatter->locale = 'en-US'; - $this->assertSame('$123.00', $this->formatter->asCurrency('123')); - $this->assertSame('$123,456.00', $this->formatter->asCurrency('123456')); - $this->assertSame('$0.00', $this->formatter->asCurrency('0')); - - $this->formatter->locale = 'en-US'; - $this->formatter->currencyCode = 'USD'; - $this->assertSame('$123.00', $this->formatter->asCurrency('123')); - $this->assertSame('$123,456.00', $this->formatter->asCurrency('123456')); - $this->assertSame('$0.00', $this->formatter->asCurrency('0')); - // Starting from ICU 52.1, negative currency value will be formatted as -$123,456.12 - // see: http://source.icu-project.org/repos/icu/icu/tags/release-52-1/source/data/locales/en.txt -// $value = '-123456.123'; -// $this->assertSame("($123,456.12)", $this->formatter->asCurrency($value)); - - $this->formatter->locale = 'de-DE'; - $this->formatter->currencyCode = null; - $this->assertSame('123,00 €', $this->formatter->asCurrency('123')); - $this->formatter->currencyCode = 'USD'; - $this->assertSame('123,00 $', $this->formatter->asCurrency('123')); - $this->formatter->currencyCode = 'EUR'; - $this->assertSame('123,00 €', $this->formatter->asCurrency('123')); - - // empty input - $this->assertSame("0", $this->formatter->asInteger(false)); - $this->assertSame("0", $this->formatter->asInteger("")); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asCurrency(null)); - } - - /** - * https://github.com/yiisoft/yii2/pull/5261 - */ - public function testIntlIssue5261() - { - $this->formatter->locale = 'en-US'; - $this->formatter->numberFormatterOptions = [ - \NumberFormatter::FRACTION_DIGITS => 0 - ]; - $this->formatter->numberFormatterTextOptions = [ - \NumberFormatter::CURRENCY_CODE => 'EUR' - ]; - $this->assertSame('€100', $this->formatter->asCurrency(100, 'EUR')); - } - - public function testAsCurrency() - { - $this->formatter->currencyCode = 'USD'; - $this->assertSame('USD 123.00', $this->formatter->asCurrency('123')); - $this->assertSame('USD 0.00', $this->formatter->asCurrency('0')); - $this->assertSame('USD -123.45', $this->formatter->asCurrency('-123.45')); - $this->assertSame('USD -123.45', $this->formatter->asCurrency(-123.45)); - - $this->formatter->currencyCode = 'EUR'; - $this->assertSame('EUR 123.00', $this->formatter->asCurrency('123')); - $this->assertSame('EUR 0.00', $this->formatter->asCurrency('0')); - $this->assertSame('EUR -123.45', $this->formatter->asCurrency('-123.45')); - $this->assertSame('EUR -123.45', $this->formatter->asCurrency(-123.45)); - - // empty input - $this->assertSame("0", $this->formatter->asInteger(false)); - $this->assertSame("0", $this->formatter->asInteger("")); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asCurrency(null)); - } - - public function testIntlAsScientific() - { - $value = '123'; - $this->assertSame('1.23E2', $this->formatter->asScientific($value)); - $value = '123456'; - $this->assertSame("1.23456E5", $this->formatter->asScientific($value)); - $value = '-123456.123'; - $this->assertSame("-1.23456123E5", $this->formatter->asScientific($value)); - - // empty input - $this->assertSame("0", $this->formatter->asInteger(false)); - $this->assertSame("0", $this->formatter->asInteger("")); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asScientific(null)); - } - - public function testAsScientific() - { - $value = '123'; - $this->assertSame('1.23E+2', $this->formatter->asScientific($value, 2)); - $value = '123456'; - $this->assertSame("1.234560E+5", $this->formatter->asScientific($value)); - $value = '-123456.123'; - $this->assertSame("-1.234561E+5", $this->formatter->asScientific($value)); - - // empty input - $this->assertSame("0", $this->formatter->asInteger(false)); - $this->assertSame("0", $this->formatter->asInteger("")); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asScientific(null)); - } - - public function testIntlAsSpellout() - { - $this->assertSame('one hundred twenty-three', $this->formatter->asSpellout(123)); - - $this->formatter->locale = 'de_DE'; - $this->assertSame('ein­hundert­drei­und­zwanzig', $this->formatter->asSpellout(123)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asSpellout(null)); - } - - public function testIntlAsOrdinal() - { - $this->assertSame('0th', $this->formatter->asOrdinal(0)); - $this->assertSame('1st', $this->formatter->asOrdinal(1)); - $this->assertSame('2nd', $this->formatter->asOrdinal(2)); - $this->assertSame('3rd', $this->formatter->asOrdinal(3)); - $this->assertSame('5th', $this->formatter->asOrdinal(5)); - - $this->formatter->locale = 'de_DE'; - $this->assertSame('0.', $this->formatter->asOrdinal(0)); - $this->assertSame('1.', $this->formatter->asOrdinal(1)); - $this->assertSame('2.', $this->formatter->asOrdinal(2)); - $this->assertSame('3.', $this->formatter->asOrdinal(3)); - $this->assertSame('5.', $this->formatter->asOrdinal(5)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asOrdinal(null)); - } - - public function testIntlAsShortSize() - { - $this->formatter->numberFormatterOptions = [ - \NumberFormatter::MIN_FRACTION_DIGITS => 0, - \NumberFormatter::MAX_FRACTION_DIGITS => 2, - ]; - - // tests for base 1000 - $this->formatter->sizeFormatBase = 1000; - $this->assertSame("999 B", $this->formatter->asShortSize(999)); - $this->assertSame("999 B", $this->formatter->asShortSize('999')); - $this->assertSame("1.05 MB", $this->formatter->asShortSize(1024 * 1024)); - $this->assertSame("1 KB", $this->formatter->asShortSize(1000)); - $this->assertSame("1.02 KB", $this->formatter->asShortSize(1023)); - $this->assertNotEquals("3 PB", $this->formatter->asShortSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB - // tests for base 1024 - $this->formatter->sizeFormatBase = 1024; - $this->assertSame("1 KiB", $this->formatter->asShortSize(1024)); - $this->assertSame("1 MiB", $this->formatter->asShortSize(1024 * 1024)); - // https://github.com/yiisoft/yii2/issues/4960 - $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); - $this->assertSame("5 GiB", $this->formatter->asShortSize(5 * 1024 * 1024 * 1024)); - $this->assertNotEquals("5 PiB", $this->formatter->asShortSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB - //$this->assertSame("1 YiB", $this->formatter->asShortSize(pow(2, 80))); - $this->assertSame("2 GiB", $this->formatter->asShortSize(2147483647)); // round 1.999 up to 2 - $this->formatter->decimalSeparator = ','; - $this->formatter->numberFormatterOptions = []; - $this->assertSame("1,001 KiB", $this->formatter->asShortSize(1025, 3)); - - // empty values - $this->assertSame('0 B', $this->formatter->asShortSize(0)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asShortSize(null)); - } - - public function testAsShortSize() - { - // tests for base 1000 - $this->formatter->sizeFormatBase = 1000; - $this->assertSame("999 B", $this->formatter->asShortSize(999)); - $this->assertSame("999 B", $this->formatter->asShortSize('999')); - $this->assertSame("1.05 MB", $this->formatter->asShortSize(1024 * 1024)); - $this->assertSame("1.0486 MB", $this->formatter->asShortSize(1024 * 1024, 4)); - $this->assertSame("1.00 KB", $this->formatter->asShortSize(1000)); - $this->assertSame("1.02 KB", $this->formatter->asShortSize(1023)); - $this->assertNotEquals("3 PB", $this->formatter->asShortSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB - // tests for base 1024 - $this->formatter->sizeFormatBase = 1024; - $this->assertSame("1.00 KiB", $this->formatter->asShortSize(1024)); - $this->assertSame("1.00 MiB", $this->formatter->asShortSize(1024 * 1024)); - // https://github.com/yiisoft/yii2/issues/4960 - $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); - $this->assertSame("5.00 GiB", $this->formatter->asShortSize(5 * 1024 * 1024 * 1024)); - $this->assertNotEquals("5.00 PiB", $this->formatter->asShortSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB - //$this->assertSame("1 YiB", $this->formatter->asShortSize(pow(2, 80))); - $this->assertSame("2.00 GiB", $this->formatter->asShortSize(2147483647)); // round 1.999 up to 2 - $this->formatter->decimalSeparator = ','; - $this->assertSame("1,001 KiB", $this->formatter->asShortSize(1025, 3)); - - // empty values - $this->assertSame('0 B', $this->formatter->asShortSize(0)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asShortSize(null)); - } - - public function testIntlAsSize() - { - $this->formatter->numberFormatterOptions = [ - \NumberFormatter::MIN_FRACTION_DIGITS => 0, - \NumberFormatter::MAX_FRACTION_DIGITS => 2, - ]; - - // tests for base 1000 - $this->formatter->sizeFormatBase = 1000; - $this->assertSame("999 bytes", $this->formatter->asSize(999)); - $this->assertSame("999 bytes", $this->formatter->asSize('999')); - $this->assertSame("1.05 megabytes", $this->formatter->asSize(1024 * 1024)); - $this->assertSame("1 kilobyte", $this->formatter->asSize(1000)); - $this->assertSame("1.02 kilobytes", $this->formatter->asSize(1023)); - $this->assertSame("3 gigabytes", $this->formatter->asSize(3 * 1000 * 1000 * 1000)); - $this->assertNotEquals("3 PB", $this->formatter->asSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB - // tests for base 1024 - $this->formatter->sizeFormatBase = 1024; - $this->assertSame("1 kibibyte", $this->formatter->asSize(1024)); - $this->assertSame("1 mebibyte", $this->formatter->asSize(1024 * 1024)); - $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); - $this->assertSame("5 gibibytes", $this->formatter->asSize(5 * 1024 * 1024 * 1024)); - $this->assertNotEquals("5 pibibytes", $this->formatter->asSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB - $this->assertSame("2 gibibytes", $this->formatter->asSize(2147483647)); // round 1.999 up to 2 - $this->formatter->decimalSeparator = ','; - $this->formatter->numberFormatterOptions = []; - $this->assertSame("1,001 kibibytes", $this->formatter->asSize(1025, 3)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asSize(null)); - } - - public function testAsSize() - { - // tests for base 1000 - $this->formatter->sizeFormatBase = 1000; - $this->assertSame("999 bytes", $this->formatter->asSize(999)); - $this->assertSame("999 bytes", $this->formatter->asSize('999')); - $this->assertSame("1.05 megabytes", $this->formatter->asSize(1024 * 1024)); - $this->assertSame("1.0486 megabytes", $this->formatter->asSize(1024 * 1024, 4)); - $this->assertSame("1.00 kilobyte", $this->formatter->asSize(1000)); - $this->assertSame("1.02 kilobytes", $this->formatter->asSize(1023)); - $this->assertSame("3.00 gigabytes", $this->formatter->asSize(3 * 1000 * 1000 * 1000)); - $this->assertNotEquals("3 PB", $this->formatter->asSize(3 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)); // this is 3 EB not 3 PB - // tests for base 1024 - $this->formatter->sizeFormatBase = 1024; - $this->assertSame("1.00 kibibyte", $this->formatter->asSize(1024)); - $this->assertSame("1.00 mebibyte", $this->formatter->asSize(1024 * 1024)); - $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); - $this->assertSame("5.00 gibibytes", $this->formatter->asSize(5 * 1024 * 1024 * 1024)); - $this->assertNotEquals("5.00 pibibytes", $this->formatter->asSize(5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)); // this is 5 EiB not 5 PiB - $this->assertSame("2.00 gibibytes", $this->formatter->asSize(2147483647)); // round 1.999 up to 2 - $this->formatter->decimalSeparator = ','; - $this->formatter->numberFormatterOptions = []; - $this->assertSame("1,001 kibibytes", $this->formatter->asSize(1025, 3)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asSize(null)); - } - - public function testIntlAsSizeConfiguration() - { - $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); - $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); - $this->formatter->thousandSeparator = '.'; - $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); - $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); - } - - /** - * https://github.com/yiisoft/yii2/issues/4960 - */ - public function testAsSizeConfiguration() - { - $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); - $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); - $this->formatter->thousandSeparator = '.'; - $this->assertSame("1023 bytes", $this->formatter->asSize(1023)); - $this->assertSame("1023 B", $this->formatter->asShortSize(1023)); - } -} diff --git a/tests/unit/framework/i18n/FormatterTest.php b/tests/unit/framework/i18n/FormatterTest.php deleted file mode 100644 index 4751d3b..0000000 --- a/tests/unit/framework/i18n/FormatterTest.php +++ /dev/null @@ -1,194 +0,0 @@ -mockApplication([ - 'timeZone' => 'UTC', - 'language' => 'ru-RU', - ]); - $this->formatter = new Formatter(['locale' => 'en-US']); - } - - protected function tearDown() - { - parent::tearDown(); - IntlTestHelper::resetIntlStatus(); - $this->formatter = null; - } - - - public function testFormat() - { - $value = time(); - $this->assertSame(date('M j, Y', $value), $this->formatter->format($value, 'date')); - $this->assertSame(date('M j, Y', $value), $this->formatter->format($value, 'DATE')); - $this->assertSame(date('Y/m/d', $value), $this->formatter->format($value, ['date', 'php:Y/m/d'])); - $this->setExpectedException('\yii\base\InvalidParamException'); - $this->assertSame(date('Y-m-d', $value), $this->formatter->format($value, 'data')); - } - - public function testLocale() - { - // locale is configured explicitly - $f = new Formatter(['locale' => 'en-US']); - $this->assertEquals('en-US', $f->locale); - - // if not, take from application - $f = new Formatter(); - $this->assertEquals('ru-RU', $f->locale); - } - - - public function testAsRaw() - { - $value = '123'; - $this->assertSame($value, $this->formatter->asRaw($value)); - $value = 123; - $this->assertSame($value, $this->formatter->asRaw($value)); - $value = '<>'; - $this->assertSame($value, $this->formatter->asRaw($value)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asRaw(null)); - } - - public function testAsText() - { - $value = '123'; - $this->assertSame($value, $this->formatter->asText($value)); - $value = 123; - $this->assertSame("$value", $this->formatter->asText($value)); - $value = '<>'; - $this->assertSame('<>', $this->formatter->asText($value)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asText(null)); - } - - public function testAsNtext() - { - $value = '123'; - $this->assertSame($value, $this->formatter->asNtext($value)); - $value = 123; - $this->assertSame("$value", $this->formatter->asNtext($value)); - $value = '<>'; - $this->assertSame('<>', $this->formatter->asNtext($value)); - $value = "123\n456"; - $this->assertSame("123
            \n456", $this->formatter->asNtext($value)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asNtext(null)); - } - - public function testAsParagraphs() - { - $value = '123'; - $this->assertSame("

            $value

            ", $this->formatter->asParagraphs($value)); - $value = 123; - $this->assertSame("

            $value

            ", $this->formatter->asParagraphs($value)); - $value = '<>'; - $this->assertSame('

            <>

            ', $this->formatter->asParagraphs($value)); - $value = "123\n456"; - $this->assertSame("

            123\n456

            ", $this->formatter->asParagraphs($value)); - $value = "123\n\n456"; - $this->assertSame("

            123

            \n

            456

            ", $this->formatter->asParagraphs($value)); - $value = "123\n\n\n456"; - $this->assertSame("

            123

            \n

            456

            ", $this->formatter->asParagraphs($value)); - $value = "123\r\n456"; - $this->assertSame("

            123\r\n456

            ", $this->formatter->asParagraphs($value)); - $value = "123\r\n\r\n456"; - $this->assertSame("

            123

            \n

            456

            ", $this->formatter->asParagraphs($value)); - $value = "123\r\n\r\n\r\n456"; - $this->assertSame("

            123

            \n

            456

            ", $this->formatter->asParagraphs($value)); - $value = "123\r456"; - $this->assertSame("

            123\r456

            ", $this->formatter->asParagraphs($value)); - $value = "123\r\r456"; - $this->assertSame("

            123

            \n

            456

            ", $this->formatter->asParagraphs($value)); - $value = "123\r\r\r456"; - $this->assertSame("

            123

            \n

            456

            ", $this->formatter->asParagraphs($value)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asParagraphs(null)); - } - - public function testAsHtml() - { - // todo: dependency on HtmlPurifier - } - - public function testAsEmail() - { - $value = 'test@sample.com'; - $this->assertSame("$value", $this->formatter->asEmail($value)); - $value = 'test@sample.com'; - $this->assertSame("$value", $this->formatter->asEmail($value, ['target' => '_blank'])); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asEmail(null)); - } - - public function testAsUrl() - { - $value = 'http://www.yiiframework.com/'; - $this->assertSame("$value", $this->formatter->asUrl($value)); - $value = 'https://www.yiiframework.com/'; - $this->assertSame("$value", $this->formatter->asUrl($value)); - $value = 'www.yiiframework.com/'; - $this->assertSame("$value", $this->formatter->asUrl($value)); - $value = 'https://www.yiiframework.com/?name=test&value=5"'; - $this->assertSame("https://www.yiiframework.com/?name=test&value=5"", $this->formatter->asUrl($value)); - $value = 'http://www.yiiframework.com/'; - $this->assertSame("$value", $this->formatter->asUrl($value, ['target' => '_blank'])); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asUrl(null)); - } - - public function testAsImage() - { - $value = 'http://sample.com/img.jpg'; - $this->assertSame("\"\"", $this->formatter->asImage($value)); - $value = 'http://sample.com/img.jpg'; - $alt = "Hello!"; - $this->assertSame("\"$alt\"", $this->formatter->asImage($value, ['alt' => $alt])); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asImage(null)); - } - - public function testAsBoolean() - { - $this->assertSame('Yes', $this->formatter->asBoolean(true)); - $this->assertSame('No', $this->formatter->asBoolean(false)); - $this->assertSame('Yes', $this->formatter->asBoolean("111")); - $this->assertSame('No', $this->formatter->asBoolean("")); - $this->assertSame('No', $this->formatter->asBoolean(0)); - - // null display - $this->assertSame($this->formatter->nullDisplay, $this->formatter->asBoolean(null)); - } -} diff --git a/tests/unit/framework/i18n/GettextMessageSourceTest.php b/tests/unit/framework/i18n/GettextMessageSourceTest.php deleted file mode 100644 index cb586de..0000000 --- a/tests/unit/framework/i18n/GettextMessageSourceTest.php +++ /dev/null @@ -1,16 +0,0 @@ -markTestIncomplete(); - } -} diff --git a/tests/unit/framework/i18n/GettextMoFileTest.php b/tests/unit/framework/i18n/GettextMoFileTest.php deleted file mode 100644 index b9ef897..0000000 --- a/tests/unit/framework/i18n/GettextMoFileTest.php +++ /dev/null @@ -1,98 +0,0 @@ -load($moFilePath, 'context1'); - $context2 = $moFile->load($moFilePath, 'context2'); - - // item count - $this->assertCount(3, $context1); - $this->assertCount(2, $context2); - - // original messages - $this->assertArrayNotHasKey("Missing\n\r\t\"translation.", $context1); - $this->assertArrayHasKey("Aliquam tempus elit vel purus molestie placerat. In sollicitudin tincidunt\naliquet. Integer tincidunt gravida tempor. In convallis blandit dui vel malesuada.\nNunc vel sapien nunc, a pretium nulla.", $context1); - $this->assertArrayHasKey("String number two.", $context1); - $this->assertArrayHasKey("Nunc vel sapien nunc, a pretium nulla.\nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.", $context1); - - $this->assertArrayHasKey("The other\n\ncontext.\n", $context2); - $this->assertArrayHasKey("test1\\ntest2\n\\\ntest3", $context2); - - // translated messages - $this->assertFalse(in_array("", $context1)); - $this->assertTrue(in_array("Олицетворение однократно. Представленный лексико-семантический анализ является\nпсихолингвистическим в своей основе, но механизм сочленений полидисперсен. Впечатление\nоднократно. Различное расположение выбирает сюжетный механизм сочленений.", $context1)); - $this->assertTrue(in_array('Строка номер два.', $context1)); - $this->assertTrue(in_array('Короткий перевод.', $context1)); - - $this->assertTrue(in_array("Другой\n\nконтекст.\n", $context2)); - $this->assertTrue(in_array("тест1\\nтест2\n\\\nтест3", $context2)); - } - - public function testSave() - { - // initial data - $s = chr(4); - $messages = [ - 'Hello!' => 'Привет!', - "context1{$s}Hello?" => 'Привет?', - 'Hello!?' => '', - "context1{$s}Hello!?!" => '', - "context2{$s}\"Quotes\"" => '"Кавычки"', - "context2{$s}\nNew lines\n" => "\nПереносы строк\n", - "context2{$s}\tTabs\t" => "\tТабы\t", - "context2{$s}\rCarriage returns\r" => "\rВозвраты кареток\r", - ]; - - // create temporary directory and dump messages - $poFileDirectory = __DIR__ . '/../../runtime/i18n'; - if (!is_dir($poFileDirectory)) { - mkdir($poFileDirectory); - } - if (is_file($poFileDirectory . '/test.mo')) { - unlink($poFileDirectory . '/test.mo'); - } - - $moFile = new GettextMoFile(); - $moFile->save($poFileDirectory . '/test.mo', $messages); - - // load messages - $context1 = $moFile->load($poFileDirectory . '/test.mo', 'context1'); - $context2 = $moFile->load($poFileDirectory . '/test.mo', 'context2'); - - // context1 - $this->assertCount(2, $context1); - - $this->assertArrayHasKey('Hello?', $context1); - $this->assertTrue(in_array('Привет?', $context1)); - - $this->assertArrayHasKey('Hello!?!', $context1); - $this->assertTrue(in_array('', $context1)); - - // context2 - $this->assertCount(4, $context2); - - $this->assertArrayHasKey("\"Quotes\"", $context2); - $this->assertTrue(in_array('"Кавычки"', $context2)); - - $this->assertArrayHasKey("\nNew lines\n", $context2); - $this->assertTrue(in_array("\nПереносы строк\n", $context2)); - - $this->assertArrayHasKey("\tTabs\t", $context2); - $this->assertTrue(in_array("\tТабы\t", $context2)); - - $this->assertArrayHasKey("\rCarriage returns\r", $context2); - $this->assertTrue(in_array("\rВозвраты кареток\r", $context2)); - } -} diff --git a/tests/unit/framework/i18n/GettextPoFileTest.php b/tests/unit/framework/i18n/GettextPoFileTest.php deleted file mode 100644 index 42aa24a..0000000 --- a/tests/unit/framework/i18n/GettextPoFileTest.php +++ /dev/null @@ -1,98 +0,0 @@ -load($poFilePath, 'context1'); - $context2 = $poFile->load($poFilePath, 'context2'); - - // item count - $this->assertCount(4, $context1); - $this->assertCount(2, $context2); - - // original messages - $this->assertArrayHasKey("Missing\n\r\t\"translation.", $context1); - $this->assertArrayHasKey("Aliquam tempus elit vel purus molestie placerat. In sollicitudin tincidunt\naliquet. Integer tincidunt gravida tempor. In convallis blandit dui vel malesuada.\nNunc vel sapien nunc, a pretium nulla.", $context1); - $this->assertArrayHasKey("String number two.", $context1); - $this->assertArrayHasKey("Nunc vel sapien nunc, a pretium nulla.\nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.", $context1); - - $this->assertArrayHasKey("The other\n\ncontext.\n", $context2); - $this->assertArrayHasKey("test1\\\ntest2\n\\\\\ntest3", $context2); - - // translated messages - $this->assertTrue(in_array("", $context1)); - $this->assertTrue(in_array("Олицетворение однократно. Представленный лексико-семантический анализ является\nпсихолингвистическим в своей основе, но механизм сочленений полидисперсен. Впечатление\nоднократно. Различное расположение выбирает сюжетный механизм сочленений.", $context1)); - $this->assertTrue(in_array('Строка номер два.', $context1)); - $this->assertTrue(in_array('Короткий перевод.', $context1)); - - $this->assertTrue(in_array("Другой\n\nконтекст.\n", $context2)); - $this->assertTrue(in_array("тест1\\\nтест2\n\\\\\nтест3", $context2)); - } - - public function testSave() - { - // initial data - $s = chr(4); - $messages = [ - 'Hello!' => 'Привет!', - "context1{$s}Hello?" => 'Привет?', - 'Hello!?' => '', - "context1{$s}Hello!?!" => '', - "context2{$s}\"Quotes\"" => '"Кавычки"', - "context2{$s}\nNew lines\n" => "\nПереносы строк\n", - "context2{$s}\tTabs\t" => "\tТабы\t", - "context2{$s}\rCarriage returns\r" => "\rВозвраты кареток\r", - ]; - - // create temporary directory and dump messages - $poFileDirectory = __DIR__ . '/../../runtime/i18n'; - if (!is_dir($poFileDirectory)) { - mkdir($poFileDirectory); - } - if (is_file($poFileDirectory . '/test.po')) { - unlink($poFileDirectory . '/test.po'); - } - - $poFile = new GettextPoFile(); - $poFile->save($poFileDirectory . '/test.po', $messages); - - // load messages - $context1 = $poFile->load($poFileDirectory . '/test.po', 'context1'); - $context2 = $poFile->load($poFileDirectory . '/test.po', 'context2'); - - // context1 - $this->assertCount(2, $context1); - - $this->assertArrayHasKey('Hello?', $context1); - $this->assertTrue(in_array('Привет?', $context1)); - - $this->assertArrayHasKey('Hello!?!', $context1); - $this->assertTrue(in_array('', $context1)); - - // context2 - $this->assertCount(4, $context2); - - $this->assertArrayHasKey("\"Quotes\"", $context2); - $this->assertTrue(in_array('"Кавычки"', $context2)); - - $this->assertArrayHasKey("\nNew lines\n", $context2); - $this->assertTrue(in_array("\nПереносы строк\n", $context2)); - - $this->assertArrayHasKey("\tTabs\t", $context2); - $this->assertTrue(in_array("\tТабы\t", $context2)); - - $this->assertArrayHasKey("\rCarriage returns\r", $context2); - $this->assertTrue(in_array("\rВозвраты кареток\r", $context2)); - } -} diff --git a/tests/unit/framework/i18n/I18NTest.php b/tests/unit/framework/i18n/I18NTest.php deleted file mode 100644 index f6c4d2c..0000000 --- a/tests/unit/framework/i18n/I18NTest.php +++ /dev/null @@ -1,177 +0,0 @@ - - * @since 2.0 - * @group i18n - */ -class I18NTest extends TestCase -{ - /** - * @var I18N - */ - public $i18n; - - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - $this->i18n = new I18N([ - 'translations' => [ - 'test' => new PhpMessageSource([ - 'basePath' => '@yiiunit/data/i18n/messages', - ]) - ] - ]); - } - - public function testTranslate() - { - $msg = 'The dog runs fast.'; - - // source = target. Should be returned as is. - $this->assertEquals('The dog runs fast.', $this->i18n->translate('test', $msg, [], 'en')); - - // exact match - $this->assertEquals('Der Hund rennt schnell.', $this->i18n->translate('test', $msg, [], 'de-DE')); - - // fallback to just language code with absent exact match - $this->assertEquals('Собака бегает быстро.', $this->i18n->translate('test', $msg, [], 'ru-RU')); - - // fallback to just langauge code with present exact match - $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); - } - - public function testDefaultSource() - { - $i18n = new I18N([ - 'translations' => [ - '*' => new PhpMessageSource([ - 'basePath' => '@yiiunit/data/i18n/messages', - 'fileMap' => [ - 'test' => 'test.php', - 'foo' => 'test.php', - ], - ]) - ] - ]); - - $msg = 'The dog runs fast.'; - - // source = target. Should be returned as is. - $this->assertEquals($msg, $i18n->translate('test', $msg, [], 'en')); - - // exact match - $this->assertEquals('Der Hund rennt schnell.', $i18n->translate('test', $msg, [], 'de-DE')); - $this->assertEquals('Der Hund rennt schnell.', $i18n->translate('foo', $msg, [], 'de-DE')); - $this->assertEquals($msg, $i18n->translate('bar', $msg, [], 'de-DE')); - - // fallback to just language code with absent exact match - $this->assertEquals('Собака бегает быстро.', $i18n->translate('test', $msg, [], 'ru-RU')); - - // fallback to just langauge code with present exact match - $this->assertEquals('Hallo Welt!', $i18n->translate('test', 'Hello world!', [], 'de-DE')); - } - - public function testTranslateParams() - { - $msg = 'His speed is about {n} km/h.'; - $params = ['n' => 42]; - $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en-US')); - $this->assertEquals('Seine Geschwindigkeit beträgt 42 km/h.', $this->i18n->translate('test', $msg, $params, 'de-DE')); - } - - public function testTranslateParams2() - { - if (!extension_loaded("intl")) { - $this->markTestSkipped("intl not installed. Skipping."); - } - $msg = 'His name is {name} and his speed is about {n, number} km/h.'; - $params = [ - 'n' => 42, - 'name' => 'DA VINCI', // http://petrix.com/dognames/d.html - ]; - $this->assertEquals('His name is DA VINCI and his speed is about 42 km/h.', $this->i18n->translate('test', $msg, $params, 'en-US')); - $this->assertEquals('Er heißt DA VINCI und ist 42 km/h schnell.', $this->i18n->translate('test', $msg, $params, 'de-DE')); - } - - public function testSpecialParams() - { - $msg = 'His speed is about {0} km/h.'; - - $this->assertEquals('His speed is about 0 km/h.', $this->i18n->translate('test', $msg, 0, 'en-US')); - $this->assertEquals('His speed is about 42 km/h.', $this->i18n->translate('test', $msg, 42, 'en-US')); - $this->assertEquals('His speed is about {0} km/h.', $this->i18n->translate('test', $msg, null, 'en-US')); - $this->assertEquals('His speed is about {0} km/h.', $this->i18n->translate('test', $msg, [], 'en-US')); - } - - /** - * When translation is missing source language should be used for formatting. - * https://github.com/yiisoft/yii2/issues/2209 - */ - public function testMissingTranslationFormatting() - { - $this->assertEquals('1 item', $this->i18n->translate('test', '{0, number} {0, plural, one{item} other{items}}', 1, 'hu')); - } - - /** - * https://github.com/yiisoft/yii2/issues/7093 - */ - public function testRussianPlurals() - { - $this->assertEquals('На диване лежит 6 кошек!', $this->i18n->translate('test', 'There {n, plural, =0{no cats} =1{one cat} other{are # cats}} on lying on the sofa!', ['n' => 6], 'ru')); - } - - public function testUsingSourceLanguageForMissingTranslation() - { - \Yii::$app->sourceLanguage = 'ru'; - \Yii::$app->language = 'en'; - - $msg = '{n, plural, =0{Нет комментариев} =1{# комментарий} one{# комментарий} few{# комментария} many{# комментариев} other{# комментария}}'; - $this->assertEquals('5 комментариев', \Yii::t('app', $msg, ['n' => 5])); - $this->assertEquals('3 комментария', \Yii::t('app', $msg, ['n' => 3])); - $this->assertEquals('1 комментарий', \Yii::t('app', $msg, ['n' => 1])); - $this->assertEquals('21 комментарий', \Yii::t('app', $msg, ['n' => 21])); - $this->assertEquals('Нет комментариев', \Yii::t('app', $msg, ['n' => 0])); - } - - /** - * https://github.com/yiisoft/yii2/issues/2519 - */ - public function testMissingTranslationEvent() - { - $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); - $this->assertEquals('Missing translation message.', $this->i18n->translate('test', 'Missing translation message.', [], 'de-DE')); - $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); - - Event::on(PhpMessageSource::className(), PhpMessageSource::EVENT_MISSING_TRANSLATION, function ($event) {}); - $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); - $this->assertEquals('Missing translation message.', $this->i18n->translate('test', 'Missing translation message.', [], 'de-DE')); - $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); - Event::off(PhpMessageSource::className(), PhpMessageSource::EVENT_MISSING_TRANSLATION); - - Event::on(PhpMessageSource::className(), PhpMessageSource::EVENT_MISSING_TRANSLATION, function ($event) { - if ($event->message == 'New missing translation message.') { - $event->translatedMessage = 'TRANSLATION MISSING HERE!'; - } - }); - $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); - $this->assertEquals('Another missing translation message.', $this->i18n->translate('test', 'Another missing translation message.', [], 'de-DE')); - $this->assertEquals('Missing translation message.', $this->i18n->translate('test', 'Missing translation message.', [], 'de-DE')); - $this->assertEquals('TRANSLATION MISSING HERE!', $this->i18n->translate('test', 'New missing translation message.', [], 'de-DE')); - $this->assertEquals('Hallo Welt!', $this->i18n->translate('test', 'Hello world!', [], 'de-DE')); - Event::off(PhpMessageSource::className(), PhpMessageSource::EVENT_MISSING_TRANSLATION); - } -} diff --git a/tests/unit/framework/i18n/IntlTestHelper.php b/tests/unit/framework/i18n/IntlTestHelper.php deleted file mode 100644 index d9a4eb7..0000000 --- a/tests/unit/framework/i18n/IntlTestHelper.php +++ /dev/null @@ -1,77 +0,0 @@ -getName(false), 'testIntl', 8) === 0) { - if (!extension_loaded('intl')) { - $test->markTestSkipped('intl extension is not installed.'); - } - static::$enableIntl = true; - } else { - static::$enableIntl = false; - } - } - - public static function resetIntlStatus() - { - static::$enableIntl = null; - } - } -} - -namespace yii\i18n { - use yiiunit\framework\i18n\IntlTestHelper; - - if (!function_exists('yii\i18n\extension_loaded')) { - function extension_loaded($name) - { - if ($name === 'intl' && IntlTestHelper::$enableIntl !== null) { - return IntlTestHelper::$enableIntl; - } - return \extension_loaded($name); - } - } -} - -namespace yii\helpers { - use yiiunit\framework\i18n\IntlTestHelper; - - if (!function_exists('yii\helpers\extension_loaded')) { - function extension_loaded($name) - { - if ($name === 'intl' && IntlTestHelper::$enableIntl !== null) { - return IntlTestHelper::$enableIntl; - } - return \extension_loaded($name); - } - } -} - -namespace yii\validators { - use yiiunit\framework\i18n\IntlTestHelper; - - if (!function_exists('yii\validators\extension_loaded')) { - function extension_loaded($name) - { - if ($name === 'intl' && IntlTestHelper::$enableIntl !== null) { - return IntlTestHelper::$enableIntl; - } - return \extension_loaded($name); - } - } -} diff --git a/tests/unit/framework/i18n/MessageFormatterTest.php b/tests/unit/framework/i18n/MessageFormatterTest.php deleted file mode 100644 index 85f0c52..0000000 --- a/tests/unit/framework/i18n/MessageFormatterTest.php +++ /dev/null @@ -1,337 +0,0 @@ - - * @since 2.0 - * @group i18n - */ -class MessageFormatterTest extends TestCase -{ - const N = 'n'; - const N_VALUE = 42; - const SUBJECT = 'сабж'; - const SUBJECT_VALUE = 'Answer to the Ultimate Question of Life, the Universe, and Everything'; - - public function patterns() - { - return [ - [ - '{'.self::SUBJECT.'} is {'.self::N.', number}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - self::SUBJECT => self::SUBJECT_VALUE, - ] - ], - - [ - '{'.self::SUBJECT.'} is {'.self::N.', number, integer}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - self::SUBJECT => self::SUBJECT_VALUE, - ] - ], - - // This one was provided by Aura.Intl. Thanks! - [<<<_MSG_ -{gender_of_host, select, - female {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to her party.} - =2 {{host} invites {guest} and one other person to her party.} - other {{host} invites {guest} and # other people to her party.}}} - male {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to his party.} - =2 {{host} invites {guest} and one other person to his party.} - other {{host} invites {guest} and # other people to his party.}}} - other {{num_guests, plural, offset:1 - =0 {{host} does not give a party.} - =1 {{host} invites {guest} to their party.} - =2 {{host} invites {guest} and one other person to their party.} - other {{host} invites {guest} and # other people to their party.}}}} -_MSG_ - , - 'ralph invites beep and 3 other people to his party.', - [ - 'gender_of_host' => 'male', - 'num_guests' => 4, - 'host' => 'ralph', - 'guest' => 'beep' - ], - defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.8', '<'), - 'select format is available in ICU > 4.4 and plural format with =X selector is avilable since 4.8' - ], - - [ - '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', - 'Alexander is male and he loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - ], - defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), - 'select format is available in ICU > 4.4' - ], - - // verify pattern in select does not get replaced - [ - '{name} is {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', - 'Alexander is male and he loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - // following should not be replaced - 'he' => 'wtf', - 'she' => 'wtf', - 'it' => 'wtf', - ], - defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), - 'select format is available in ICU > 4.4' - ], - - // verify pattern in select message gets replaced - [ - '{name} is {gender} and {gender, select, female{she} male{{he}} other{it}} loves Yii!', - 'Alexander is male and wtf loves Yii!', - [ - 'name' => 'Alexander', - 'gender' => 'male', - 'he' => 'wtf', - 'she' => 'wtf', - ], - defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.8', '<'), - 'parameters in select format do not seem to work in ICU < 4.8' - ], - - // some parser specific verifications - [ - '{gender} and {gender, select, female{she} male{{he}} other{it}} loves {nr, number} is {gender}!', - 'male and wtf loves 42 is male!', - [ - 'nr' => 42, - 'gender' => 'male', - 'he' => 'wtf', - 'she' => 'wtf', - ], - defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '4.4.2', '<'), - 'select format is available in ICU > 4.4' - ], - - // test ICU version compatibility - [ - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', - [], - ], - [ - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', - 'Showing 1-10 of 12 items.', - [// A - 'begin' => 1, - 'end' => 10, - 'count' => 10, - 'totalCount' => 12, - 'page' => 1, - 'pageCount' => 2, - ] - ], - [ - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', - 'Showing 1-1 of 1 item.', - [// B - 'begin' => 1, - 'end' => 1, - 'count' => 1, - 'totalCount' => 1, - 'page' => 1, - 'pageCount' => 1, - ] - ], - [ - 'Showing {begin, number}-{end, number} of {totalCount, number} {totalCount, plural, one{item} other{items}}.', - 'Showing 0-0 of 0 items.', - [// C - 'begin' => 0, - 'end' => 0, - 'count' => 0, - 'totalCount' => 0, - 'page' => 1, - 'pageCount' => 1, - ] - ], - [ - 'Total {count, number} {count, plural, one{item} other{items}}.', - 'Total {count, number} {count, plural, one{item} other{items}}.', - [] - ], - [ - 'Total {count, number} {count, plural, one{item} other{items}}.', - 'Total 1 item.', - [ - 'count' => 1, - ] - ], - [ - 'Total {count, number} {count, plural, one{item} other{items}}.', - 'Total 1 item.', - [ - 'begin' => 5, - 'count' => 1, - 'end' => 10, - ] - ], - [ - '{0, plural, one {offer} other {offers}}', - '{0, plural, one {offer} other {offers}}', - [], - ], - [ - '{0, plural, one {offer} other {offers}}', - 'offers', - [0], - ], - [ - '{0, plural, one {offer} other {offers}}', - 'offer', - [1], - ], - [ - '{0, plural, one {offer} other {offers}}', - 'offers', - [13], - ], - ]; - } - - public function parsePatterns() - { - return [ - [ - self::SUBJECT_VALUE.' is {0, number}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - 0 => self::N_VALUE, - ] - ], - - [ - self::SUBJECT_VALUE.' is {'.self::N.', number}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - ] - ], - - [ - self::SUBJECT_VALUE.' is {'.self::N.', number, integer}', // pattern - self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected - [ // params - self::N => self::N_VALUE, - ] - ], - - [ - "{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree", - "4,560 monkeys on 123 trees make 37.073 monkeys per tree", - [ - 0 => 4560, - 1 => 123, - 2 => 37.073 - ], - 'en-US' - ], - - [ - "{0,number,integer} Affen auf {1,number,integer} Bäumen sind {2,number} Affen pro Baum", - "4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum", - [ - 0 => 4560, - 1 => 123, - 2 => 37.073 - ], - 'de', - ], - - [ - "{monkeyCount,number,integer} monkeys on {trees,number,integer} trees make {monkeysPerTree,number} monkeys per tree", - "4,560 monkeys on 123 trees make 37.073 monkeys per tree", - [ - 'monkeyCount' => 4560, - 'trees' => 123, - 'monkeysPerTree' => 37.073 - ], - 'en-US' - ], - - [ - "{monkeyCount,number,integer} Affen auf {trees,number,integer} Bäumen sind {monkeysPerTree,number} Affen pro Baum", - "4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum", - [ - 'monkeyCount' => 4560, - 'trees' => 123, - 'monkeysPerTree' => 37.073 - ], - 'de', - ], - ]; - } - - /** - * @dataProvider patterns - */ - public function testNamedArguments($pattern, $expected, $args, $skip = false, $skipMessage = '') - { - if ($skip) { - $this->markTestSkipped($skipMessage); - } - $formatter = new MessageFormatter(); - $result = $formatter->format($pattern, $args, 'en-US'); - $this->assertEquals($expected, $result, $formatter->getErrorMessage()); - } - - /** - * @dataProvider parsePatterns - */ - public function testParseNamedArguments($pattern, $expected, $args, $locale = 'en-US') - { - if (!extension_loaded("intl")) { - $this->markTestSkipped("intl not installed. Skipping."); - } - - $formatter = new MessageFormatter(); - $result = $formatter->parse($pattern, $expected, $locale); - $this->assertEquals($args, $result, $formatter->getErrorMessage() . ' Pattern: ' . $pattern); - } - - public function testInsufficientArguments() - { - $expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; - - $formatter = new MessageFormatter(); - $result = $formatter->format('{'.self::SUBJECT.'} is {'.self::N.', number}', [ - self::N => self::N_VALUE, - ], 'en-US'); - - $this->assertEquals($expected, $result, $formatter->getErrorMessage()); - } - - public function testNoParams() - { - $pattern = '{'.self::SUBJECT.'} is '.self::N; - $formatter = new MessageFormatter(); - $result = $formatter->format($pattern, [], 'en-US'); - $this->assertEquals($pattern, $result, $formatter->getErrorMessage()); - } -} diff --git a/tests/unit/framework/log/DbTargetTest.php b/tests/unit/framework/log/DbTargetTest.php deleted file mode 100644 index 5ff7fe8..0000000 --- a/tests/unit/framework/log/DbTargetTest.php +++ /dev/null @@ -1,142 +0,0 @@ - 'Migrator', - 'basePath' => '@yiiunit', - 'controllerMap' => [ - 'migrate' => EchoMigrateController::className(), - ], - 'components' => [ - 'db' => static::getConnection(), - 'log' => [ - 'targets' => [ - [ - 'class' => 'yii\log\DbTarget', - 'levels' => ['warning'], - 'logTable' => self::$logTable, - ], - ], - ], - ], - ]); - } - - ob_start(); - $result = Yii::$app->runAction($route, $params); - echo "Result is " . $result; - if ($result !== \yii\console\Controller::EXIT_CODE_NORMAL) { - ob_end_flush(); - } else { - ob_end_clean(); - } - } - - public static function setUpBeforeClass() - { - parent::setUpBeforeClass(); - $databases = static::getParam('databases'); - static::$database = $databases[static::$driverName]; - $pdo_database = 'pdo_' . static::$driverName; - - if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) { - static::markTestSkipped('pdo and ' . $pdo_database . ' extension are required.'); - } - - static::runConsoleAction('migrate/up', ['migrationPath' => '@yii/log/migrations/', 'interactive' => false]); - } - - public static function tearDownAfterClass() - { - static::runConsoleAction('migrate/down', ['migrationPath' => '@yii/log/migrations/', 'interactive' => false]); - if (static::$db) { - static::$db->close(); - } - Yii::$app = null; - parent::tearDownAfterClass(); - } - - protected function tearDown() - { - parent::tearDown(); - self::getConnection()->createCommand()->truncateTable(self::$logTable)->execute(); - } - - /** - * @throws \yii\base\InvalidParamException - * @throws \yii\db\Exception - * @throws \yii\base\InvalidConfigException - * @return \yii\db\Connection - */ - public static function getConnection() - { - if (static::$db == null) { - $db = new Connection; - $db->dsn = static::$database['dsn']; - if (isset(static::$database['username'])) { - $db->username = static::$database['username']; - $db->password = static::$database['password']; - } - if (isset(static::$database['attributes'])) { - $db->attributes = static::$database['attributes']; - } - if (!$db->isActive) { - $db->open(); - } - static::$db = $db; - } - return static::$db; - } - - /** - * Tests that precision isn't lost for log timestamps - * @see https://github.com/yiisoft/yii2/issues/7384 - */ - public function testTimestamp() - { - $logger = Yii::getLogger(); - - $time = 1424865393.0105; - - // forming message data manually in order to set time - $messsageData = [ - 'test', - Logger::LEVEL_WARNING, - 'test', - $time, - [] - ]; - - $logger->messages[] = $messsageData; - $logger->flush(true); - - $query = (new Query())->select('log_time')->from(self::$logTable)->where(['category' => 'test']); - $loggedTime = $query->createCommand(self::getConnection())->queryScalar(); - static::assertEquals($time, $loggedTime); - } -} \ No newline at end of file diff --git a/tests/unit/framework/log/FileTargetTest.php b/tests/unit/framework/log/FileTargetTest.php deleted file mode 100644 index 122fdee..0000000 --- a/tests/unit/framework/log/FileTargetTest.php +++ /dev/null @@ -1,105 +0,0 @@ - - */ - -namespace yiiunit\framework\log; - -use yii\helpers\FileHelper; -use yii\log\Dispatcher; -use yii\log\Logger; -use Yii; -use yiiunit\TestCase; - -/** - * @group log - */ -class FileTargetTest extends TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - public function booleanDataProvider() - { - return [ - [true], - [false] - ]; - } - - /** - * @dataProvider booleanDataProvider - */ - public function testRotate($rotateByCopy) - { - $logFile = Yii::getAlias('@yiiunit/runtime/log/filetargettest.log'); - FileHelper::removeDirectory(dirname($logFile)); - mkdir(dirname($logFile), 0777, true); - - $logger = new Logger(); - $dispatcher = new Dispatcher([ - 'logger' => $logger, - 'targets' => [ - 'file' => [ - 'class' => 'yii\log\FileTarget', - 'logFile' => $logFile, - 'levels' => ['warning'], - 'maxFileSize' => 1024, // 1 MB - 'maxLogFiles' => 1, // one file for rotation and one normal log file - 'logVars' => [], - 'rotateByCopy' => $rotateByCopy - ] - ] - ]); - - // one file - - $logger->log(str_repeat('x', 1024), Logger::LEVEL_WARNING); - $logger->flush(true); - - clearstatcache(); - - $this->assertTrue(file_exists($logFile)); - $this->assertFalse(file_exists($logFile . '.1')); - $this->assertFalse(file_exists($logFile . '.2')); - $this->assertFalse(file_exists($logFile . '.3')); - $this->assertFalse(file_exists($logFile . '.4')); - - // exceed max size - for($i = 0; $i < 1024; $i++) { - $logger->log(str_repeat('x', 1024), Logger::LEVEL_WARNING); - } - $logger->flush(true); - - // first rotate - - $logger->log(str_repeat('x', 1024), Logger::LEVEL_WARNING); - $logger->flush(true); - - clearstatcache(); - - $this->assertTrue(file_exists($logFile)); - $this->assertTrue(file_exists($logFile . '.1')); - $this->assertFalse(file_exists($logFile . '.2')); - $this->assertFalse(file_exists($logFile . '.3')); - $this->assertFalse(file_exists($logFile . '.4')); - - // second rotate - - for($i = 0; $i < 1024; $i++) { - $logger->log(str_repeat('x', 1024), Logger::LEVEL_WARNING); - } - $logger->flush(true); - - clearstatcache(); - - $this->assertTrue(file_exists($logFile)); - $this->assertTrue(file_exists($logFile . '.1')); - $this->assertFalse(file_exists($logFile . '.2')); - $this->assertFalse(file_exists($logFile . '.3')); - $this->assertFalse(file_exists($logFile . '.4')); - } -} \ No newline at end of file diff --git a/tests/unit/framework/log/LoggerTest.php b/tests/unit/framework/log/LoggerTest.php deleted file mode 100644 index 44fd5b4..0000000 --- a/tests/unit/framework/log/LoggerTest.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ - -namespace yiiunit\framework\log; - -use yii\log\Logger; -use yiiunit\TestCase; - -/** - * @group log - */ -class LoggerTest extends TestCase -{ - - public function testLog() - { - $logger = new Logger(); - - $logger->log('test1', Logger::LEVEL_INFO); - $this->assertEquals(1, count($logger->messages)); - $this->assertEquals('test1', $logger->messages[0][0]); - $this->assertEquals(Logger::LEVEL_INFO, $logger->messages[0][1]); - $this->assertEquals('application', $logger->messages[0][2]); - - $logger->log('test2', Logger::LEVEL_ERROR, 'category'); - $this->assertEquals(2, count($logger->messages)); - $this->assertEquals('test2', $logger->messages[1][0]); - $this->assertEquals(Logger::LEVEL_ERROR, $logger->messages[1][1]); - $this->assertEquals('category', $logger->messages[1][2]); - } -} diff --git a/tests/unit/framework/log/MySQLTargetTest.php b/tests/unit/framework/log/MySQLTargetTest.php deleted file mode 100644 index fd5e242..0000000 --- a/tests/unit/framework/log/MySQLTargetTest.php +++ /dev/null @@ -1,10 +0,0 @@ - - */ - -namespace yiiunit\framework\log; - -use yii\log\Dispatcher; -use yii\log\Logger; -use yii\log\Target; -use yiiunit\TestCase; - -/** - * @group log - */ -class TargetTest extends TestCase -{ - public static $messages; - - public function filters() - { - return [ - [[], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']], - - [['levels' => 0], ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']], - [ - ['levels' => Logger::LEVEL_INFO | Logger::LEVEL_WARNING | Logger::LEVEL_ERROR | Logger::LEVEL_TRACE], - ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] - ], - [['levels' => ['error']], ['B', 'G', 'H']], - [['levels' => Logger::LEVEL_ERROR], ['B', 'G', 'H']], - [['levels' => ['error', 'warning']], ['B', 'C', 'G', 'H']], - [['levels' => Logger::LEVEL_ERROR | Logger::LEVEL_WARNING], ['B', 'C', 'G', 'H']], - - [['categories' => ['application']], ['A', 'B', 'C', 'D', 'E']], - [['categories' => ['application*']], ['A', 'B', 'C', 'D', 'E', 'F']], - [['categories' => ['application.*']], ['F']], - [['categories' => ['application.components']], []], - [['categories' => ['application.components.Test']], ['F']], - [['categories' => ['application.components.*']], ['F']], - [['categories' => ['application.*', 'yii.db.*']], ['F', 'G', 'H']], - [['categories' => ['application.*', 'yii.db.*'], 'except' => ['yii.db.Command.*']], ['F', 'G']], - - [['categories' => ['application', 'yii.db.*'], 'levels' => Logger::LEVEL_ERROR], ['B', 'G', 'H']], - [['categories' => ['application'], 'levels' => Logger::LEVEL_ERROR], ['B']], - [['categories' => ['application'], 'levels' => Logger::LEVEL_ERROR | Logger::LEVEL_WARNING], ['B', 'C']], - ]; - } - - /** - * @dataProvider filters - */ - public function testFilter($filter, $expected) - { - static::$messages = []; - - $logger = new Logger; - $dispatcher = new Dispatcher([ - 'logger' => $logger, - 'targets' => [new TestTarget(array_merge($filter, ['logVars' => []]))], - 'flushInterval' => 1, - ]); - $logger->log('testA', Logger::LEVEL_INFO); - $logger->log('testB', Logger::LEVEL_ERROR); - $logger->log('testC', Logger::LEVEL_WARNING); - $logger->log('testD', Logger::LEVEL_TRACE); - $logger->log('testE', Logger::LEVEL_INFO, 'application'); - $logger->log('testF', Logger::LEVEL_INFO, 'application.components.Test'); - $logger->log('testG', Logger::LEVEL_ERROR, 'yii.db.Command'); - $logger->log('testH', Logger::LEVEL_ERROR, 'yii.db.Command.whatever'); - - $this->assertEquals(count($expected), count(static::$messages)); - $i = 0; - foreach ($expected as $e) { - $this->assertEquals('test' . $e, static::$messages[$i++][0]); - } - } -} - -class TestTarget extends Target -{ - public $exportInterval = 1; - - /** - * Exports log [[messages]] to a specific destination. - * Child classes must implement this method. - */ - public function export() - { - TargetTest::$messages = array_merge(TargetTest::$messages, $this->messages); - $this->messages = []; - } -} diff --git a/tests/unit/framework/mail/BaseMailerTest.php b/tests/unit/framework/mail/BaseMailerTest.php deleted file mode 100644 index b6d166f..0000000 --- a/tests/unit/framework/mail/BaseMailerTest.php +++ /dev/null @@ -1,449 +0,0 @@ -mockApplication([ - 'components' => [ - 'mailer' => $this->createTestMailComponent(), - ] - ]); - $filePath = $this->getTestFilePath(); - if (!file_exists($filePath)) { - FileHelper::createDirectory($filePath); - } - } - - public function tearDown() - { - $filePath = $this->getTestFilePath(); - if (file_exists($filePath)) { - FileHelper::removeDirectory($filePath); - } - } - - /** - * @return string test file path. - */ - protected function getTestFilePath() - { - return Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . basename(get_class($this)) . '_' . getmypid(); - } - - /** - * @return Mailer test email component instance. - */ - protected function createTestMailComponent() - { - $component = new Mailer(); - $component->viewPath = $this->getTestFilePath(); - - return $component; - } - - /** - * @return Mailer mailer instance - */ - protected function getTestMailComponent() - { - return Yii::$app->get('mailer'); - } - - // Tests : - - public function testSetupView() - { - $mailer = new Mailer(); - - $view = new View(); - $mailer->setView($view); - $this->assertEquals($view, $mailer->getView(), 'Unable to setup view!'); - - $viewConfig = [ - 'params' => [ - 'param1' => 'value1', - 'param2' => 'value2', - ] - ]; - $mailer->setView($viewConfig); - $view = $mailer->getView(); - $this->assertTrue(is_object($view), 'Unable to setup view via config!'); - $this->assertEquals($viewConfig['params'], $view->params, 'Unable to configure view via config array!'); - } - - /** - * @depends testSetupView - */ - public function testGetDefaultView() - { - $mailer = new Mailer(); - $view = $mailer->getView(); - $this->assertTrue(is_object($view), 'Unable to get default view!'); - } - - public function testCreateMessage() - { - $mailer = new Mailer(); - $message = $mailer->compose(); - $this->assertTrue(is_object($message), 'Unable to create message instance!'); - $this->assertEquals($mailer->messageClass, get_class($message), 'Invalid message class!'); - } - - /** - * @depends testCreateMessage - */ - public function testDefaultMessageConfig() - { - $mailer = new Mailer(); - - $notPropertyConfig = [ - 'charset' => 'utf-16', - 'from' => 'from@domain.com', - 'to' => 'to@domain.com', - 'cc' => 'cc@domain.com', - 'bcc' => 'bcc@domain.com', - 'subject' => 'Test subject', - 'textBody' => 'Test text body', - 'htmlBody' => 'Test HTML body', - ]; - $propertyConfig = [ - 'id' => 'test-id', - 'encoding' => 'test-encoding', - ]; - $messageConfig = array_merge($notPropertyConfig, $propertyConfig); - $mailer->messageConfig = $messageConfig; - - $message = $mailer->compose(); - - foreach ($notPropertyConfig as $name => $value) { - $this->assertEquals($value, $message->{'_' . $name}); - } - foreach ($propertyConfig as $name => $value) { - $this->assertEquals($value, $message->$name); - } - } - - /** - * @depends testGetDefaultView - */ - public function testRender() - { - $mailer = $this->getTestMailComponent(); - - $viewName = 'test_view'; - $viewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $viewName . '.php'; - $viewFileContent = ''; - file_put_contents($viewFileName, $viewFileContent); - - $params = [ - 'testParam' => 'test output' - ]; - $renderResult = $mailer->render($viewName, $params); - $this->assertEquals($params['testParam'], $renderResult); - } - - /** - * @depends testRender - */ - public function testRenderLayout() - { - $mailer = $this->getTestMailComponent(); - - $filePath = $this->getTestFilePath(); - - $viewName = 'test_view2'; - $viewFileName = $filePath . DIRECTORY_SEPARATOR . $viewName . '.php'; - $viewFileContent = 'view file content'; - file_put_contents($viewFileName, $viewFileContent); - - $layoutName = 'test_layout'; - $layoutFileName = $filePath . DIRECTORY_SEPARATOR . $layoutName . '.php'; - $layoutFileContent = 'Begin Layout End Layout'; - file_put_contents($layoutFileName, $layoutFileContent); - - $renderResult = $mailer->render($viewName, [], $layoutName); - $this->assertEquals('Begin Layout ' . $viewFileContent . ' End Layout', $renderResult); - } - - /** - * @depends testCreateMessage - * @depends testRender - */ - public function testCompose() - { - $mailer = $this->getTestMailComponent(); - $mailer->htmlLayout = false; - $mailer->textLayout = false; - - $htmlViewName = 'test_html_view'; - $htmlViewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $htmlViewName . '.php'; - $htmlViewFileContent = 'HTML view file content'; - file_put_contents($htmlViewFileName, $htmlViewFileContent); - - $textViewName = 'test_text_view'; - $textViewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $textViewName . '.php'; - $textViewFileContent = 'Plain text view file content'; - file_put_contents($textViewFileName, $textViewFileContent); - - $message = $mailer->compose([ - 'html' => $htmlViewName, - 'text' => $textViewName, - ]); - $this->assertEquals($htmlViewFileContent, $message->_htmlBody, 'Unable to render html!'); - $this->assertEquals($textViewFileContent, $message->_textBody, 'Unable to render text!'); - - $message = $mailer->compose($htmlViewName); - $this->assertEquals($htmlViewFileContent, $message->_htmlBody, 'Unable to render html by direct view!'); - $this->assertEquals(strip_tags($htmlViewFileContent), $message->_textBody, 'Unable to render text by direct view!'); - } - - public function htmlAndPlainProvider() - { - return [ - [ - 1, - 'HTML view file content http://yiifresh.com/index.php?r=site%2Freset-password&token=abcdef', - 'HTML view file content http://yiifresh.com/index.php?r=site%2Freset-password&token=abcdef', - ], - [ - 2, <<TEST - - -

            First paragraph - second line - - http://yiifresh.com/index.php?r=site%2Freset-password&token=abcdef - -

            - -

            Test Lorem ipsum...

            - - -HTML -, <<getTestMailComponent(); - $mailer->htmlLayout = false; - $mailer->textLayout = false; - - $htmlViewName = 'test_html_view' . $i; // $i is needed to generate different view files to ensure it works on HHVM - $htmlViewFileName = $this->getTestFilePath() . DIRECTORY_SEPARATOR . $htmlViewName . '.php'; - file_put_contents($htmlViewFileName, $htmlViewFileContent); - - $message = $mailer->compose([ - 'html' => $htmlViewName, - ]); - $this->assertEqualsWithoutLE($htmlViewFileContent, $message->_htmlBody, 'Unable to render html!'); - $this->assertEqualsWithoutLE($expectedTextRendering, $message->_textBody, 'Unable to render text!'); - } - - public function testUseFileTransport() - { - $mailer = new Mailer(); - $this->assertFalse($mailer->useFileTransport); - $this->assertEquals('@runtime/mail', $mailer->fileTransportPath); - - $mailer->fileTransportPath = '@yiiunit/runtime/mail'; - $mailer->useFileTransport = true; - $mailer->fileTransportCallback = function () { - return 'message.txt'; - }; - $message = $mailer->compose() - ->setTo('to@example.com') - ->setFrom('from@example.com') - ->setSubject('test subject') - ->setTextBody('text body' . microtime(true)); - $this->assertTrue($mailer->send($message)); - $file = Yii::getAlias($mailer->fileTransportPath) . '/message.txt'; - $this->assertTrue(is_file($file)); - $this->assertEquals($message->toString(), file_get_contents($file)); - } - - public function testBeforeSendEvent() - { - $message = new Message(); - - $mailerMock = $this->getMockBuilder('yiiunit\framework\mail\Mailer')->setMethods(['beforeSend', 'afterSend'])->getMock(); - $mailerMock->expects($this->once())->method('beforeSend')->with($message)->will($this->returnValue(true)); - $mailerMock->expects($this->once())->method('afterSend')->with($message, true); - $mailerMock->send($message); - } -} - -/** - * Test Mailer class - */ -class Mailer extends BaseMailer -{ - public $messageClass = 'yiiunit\framework\mail\Message'; - public $sentMessages = []; - - protected function sendMessage($message) - { - $this->sentMessages[] = $message; - - return true; - } -} - -/** - * Test Message class - */ -class Message extends BaseMessage -{ - public $id; - public $encoding; - public $_charset; - public $_from; - public $_replyTo; - public $_to; - public $_cc; - public $_bcc; - public $_subject; - public $_textBody; - public $_htmlBody; - - public function getCharset() - { - return $this->_charset; - } - - public function setCharset($charset) - { - $this->_charset = $charset; - - return $this; - } - - public function getFrom() - { - return $this->_from; - } - - public function setFrom($from) - { - $this->_from = $from; - - return $this; - } - - public function getTo() - { - return $this->_to; - } - - public function setTo($to) - { - $this->_to = $to; - - return $this; - } - - public function getCc() - { - return $this->_cc; - } - - public function setCc($cc) - { - $this->_cc = $cc; - - return $this; - } - - public function getBcc() - { - return $this->_bcc; - } - - public function setBcc($bcc) - { - $this->_bcc = $bcc; - - return $this; - } - - public function getSubject() - { - return $this->_subject; - } - - public function setSubject($subject) - { - $this->_subject = $subject; - - return $this; - } - - public function getReplyTo() - { - return $this->_replyTo; - } - - public function setReplyTo($replyTo) - { - $this->_replyTo = $replyTo; - - return $this; - } - - public function setTextBody($text) - { - $this->_textBody = $text; - - return $this; - } - - public function setHtmlBody($html) - { - $this->_htmlBody = $html; - - return $this; - } - - public function attachContent($content, array $options = []) {} - - public function attach($fileName, array $options = []) {} - - public function embed($fileName, array $options = []) {} - - public function embedContent($content, array $options = []) {} - - public function toString() - { - $mailer = $this->mailer; - $this->mailer = null; - $s = var_export($this, true); - $this->mailer = $mailer; - return $s; - } -} diff --git a/tests/unit/framework/mail/BaseMessageTest.php b/tests/unit/framework/mail/BaseMessageTest.php deleted file mode 100644 index 539b730..0000000 --- a/tests/unit/framework/mail/BaseMessageTest.php +++ /dev/null @@ -1,153 +0,0 @@ -mockApplication([ - 'components' => [ - 'mailer' => $this->createTestEmailComponent() - ] - ]); - } - - /** - * @return Mailer test email component instance. - */ - protected function createTestEmailComponent() - { - $component = new TestMailer(); - - return $component; - } - - /** - * @return TestMailer mailer instance. - */ - protected function getMailer() - { - return Yii::$app->get('mailer'); - } - - // Tests : - - public function testSend() - { - $mailer = $this->getMailer(); - $message = $mailer->compose(); - $message->send($mailer); - $this->assertEquals($message, $mailer->sentMessages[0], 'Unable to send message!'); - } - - public function testToString() - { - $mailer = $this->getMailer(); - $message = $mailer->compose(); - $this->assertEquals($message->toString(), '' . $message); - } -} - -/** - * Test Mailer class - */ -class TestMailer extends BaseMailer -{ - public $messageClass = 'yiiunit\framework\mail\TestMessage'; - public $sentMessages = []; - - protected function sendMessage($message) - { - $this->sentMessages[] = $message; - } -} - -/** - * Test Message class - */ -class TestMessage extends BaseMessage -{ - public $text; - public $html; - - public function getCharset() - { - return ''; - } - - public function setCharset($charset) {} - - public function getFrom() - { - return ''; - } - - public function setFrom($from) {} - - public function getReplyTo() - { - return ''; - } - - public function setReplyTo($replyTo) {} - - public function getTo() - { - return ''; - } - - public function setTo($to) {} - - public function getCc() - { - return ''; - } - - public function setCc($cc) {} - - public function getBcc() - { - return ''; - } - - public function setBcc($bcc) {} - - public function getSubject() - { - return ''; - } - - public function setSubject($subject) {} - - public function setTextBody($text) - { - $this->text = $text; - } - - public function setHtmlBody($html) - { - $this->html = $html; - } - - public function attachContent($content, array $options = []) {} - - public function attach($fileName, array $options = []) {} - - public function embed($fileName, array $options = []) {} - - public function embedContent($content, array $options = []) {} - - public function toString() - { - return get_class($this); - } -} diff --git a/tests/unit/framework/rbac/AuthorRule.php b/tests/unit/framework/rbac/AuthorRule.php deleted file mode 100644 index fa4e794..0000000 --- a/tests/unit/framework/rbac/AuthorRule.php +++ /dev/null @@ -1,21 +0,0 @@ - 'Migrator', - 'basePath' => '@yiiunit', - 'controllerMap' => [ - 'migrate' => EchoMigrateController::className(), - ], - 'components' => [ - 'db' => static::getConnection(), - 'authManager' => '\yii\rbac\DbManager', - ], - ]); - } - - ob_start(); - $result = Yii::$app->runAction($route, $params); - echo "Result is " . $result; - if ($result !== Controller::EXIT_CODE_NORMAL) { - ob_end_flush(); - } else { - ob_end_clean(); - } - } - - public static function setUpBeforeClass() - { - parent::setUpBeforeClass(); - $databases = static::getParam('databases'); - static::$database = $databases[static::$driverName]; - $pdo_database = 'pdo_' . static::$driverName; - - if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) { - static::markTestSkipped('pdo and ' . $pdo_database . ' extension are required.'); - } - - static::runConsoleAction('migrate/up', ['migrationPath' => '@yii/rbac/migrations/', 'interactive' => false]); - } - - public static function tearDownAfterClass() - { - static::runConsoleAction('migrate/down', ['migrationPath' => '@yii/rbac/migrations/', 'interactive' => false]); - if (static::$db) { - static::$db->close(); - } - Yii::$app = null; - parent::tearDownAfterClass(); - } - - protected function setUp() - { - parent::setUp(); - $this->auth = $this->createManager(); - } - - protected function tearDown() - { - parent::tearDown(); - $this->auth->removeAll(); - } - - /** - * @throws \yii\base\InvalidParamException - * @throws \yii\db\Exception - * @throws \yii\base\InvalidConfigException - * @return \yii\db\Connection - */ - public static function getConnection() - { - if (static::$db == null) { - $db = new Connection; - $db->dsn = static::$database['dsn']; - if (isset(static::$database['username'])) { - $db->username = static::$database['username']; - $db->password = static::$database['password']; - } - if (isset(static::$database['attributes'])) { - $db->attributes = static::$database['attributes']; - } - if (!$db->isActive) { - $db->open(); - } - static::$db = $db; - } - return static::$db; - } - - /** - * @return \yii\rbac\ManagerInterface - */ - protected function createManager() - { - return new DbManager(['db' => $this->getConnection()]); - } -} diff --git a/tests/unit/framework/rbac/ExposedPhpManager.php b/tests/unit/framework/rbac/ExposedPhpManager.php deleted file mode 100644 index bf7c111..0000000 --- a/tests/unit/framework/rbac/ExposedPhpManager.php +++ /dev/null @@ -1,37 +0,0 @@ - item - /** - * @var array - */ - public $children = []; // itemName, childName => child - /** - * @var \yii\rbac\Assignment[] - */ - public $assignments = []; // userId, itemName => assignment - /** - * @var \yii\rbac\Rule[] - */ - public $rules = []; // ruleName => rule - - public function load() - { - parent::load(); - } - - public function save() - { - parent::save(); - } -} \ No newline at end of file diff --git a/tests/unit/framework/rbac/ManagerTestCase.php b/tests/unit/framework/rbac/ManagerTestCase.php deleted file mode 100644 index 0acc791..0000000 --- a/tests/unit/framework/rbac/ManagerTestCase.php +++ /dev/null @@ -1,289 +0,0 @@ -auth->createRole('admin'); - $this->assertTrue($role instanceof Role); - $this->assertEquals(Item::TYPE_ROLE, $role->type); - $this->assertEquals('admin', $role->name); - } - - public function testCreatePermission() - { - $permission = $this->auth->createPermission('edit post'); - $this->assertTrue($permission instanceof Permission); - $this->assertEquals(Item::TYPE_PERMISSION, $permission->type); - $this->assertEquals('edit post', $permission->name); - } - - public function testAdd() - { - $role = $this->auth->createRole('admin'); - $role->description = 'administrator'; - $this->assertTrue($this->auth->add($role)); - - $permission = $this->auth->createPermission('edit post'); - $permission->description = 'edit a post'; - $this->assertTrue($this->auth->add($permission)); - - $rule = new AuthorRule(['name' => 'is author', 'reallyReally' => true]); - $this->assertTrue($this->auth->add($rule)); - - // todo: check duplication of name - } - - public function testGetChildren() - { - $user = $this->auth->createRole('user'); - $this->auth->add($user); - $this->assertCount(0, $this->auth->getChildren($user->name)); - - $changeName = $this->auth->createPermission('changeName'); - $this->auth->add($changeName); - $this->auth->addChild($user, $changeName); - $this->assertCount(1, $this->auth->getChildren($user->name)); - } - - public function testGetRule() - { - $this->prepareData(); - - $rule = $this->auth->getRule('isAuthor'); - $this->assertInstanceOf('yii\rbac\Rule', $rule); - $this->assertEquals('isAuthor', $rule->name); - - $rule = $this->auth->getRule('nonExisting'); - $this->assertNull($rule); - } - - public function testAddRule() - { - $this->prepareData(); - - $ruleName = 'isReallyReallyAuthor'; - $rule = new AuthorRule(['name' => $ruleName, 'reallyReally' => true]); - $this->auth->add($rule); - - $rule = $this->auth->getRule($ruleName); - $this->assertEquals($ruleName, $rule->name); - $this->assertEquals(true, $rule->reallyReally); - } - - public function testUpdateRule() - { - $this->prepareData(); - - $rule = $this->auth->getRule('isAuthor'); - $rule->name = "newName"; - $rule->reallyReally = false; - $this->auth->update('isAuthor', $rule); - - $rule = $this->auth->getRule('isAuthor'); - $this->assertEquals(null, $rule); - - $rule = $this->auth->getRule('newName'); - $this->assertEquals("newName", $rule->name); - $this->assertEquals(false, $rule->reallyReally); - - $rule->reallyReally = true; - $this->auth->update('newName', $rule); - - $rule = $this->auth->getRule('newName'); - $this->assertEquals(true, $rule->reallyReally); - } - - public function testGetRules() - { - $this->prepareData(); - - $rule = new AuthorRule(['name' => 'isReallyReallyAuthor', 'reallyReally' => true]); - $this->auth->add($rule); - - $rules = $this->auth->getRules(); - - $ruleNames = []; - foreach ($rules as $rule) { - $ruleNames[] = $rule->name; - } - - $this->assertContains('isReallyReallyAuthor', $ruleNames); - $this->assertContains('isAuthor', $ruleNames); - } - - public function testRemoveRule() - { - $this->prepareData(); - - $this->auth->remove($this->auth->getRule('isAuthor')); - $rules = $this->auth->getRules(); - - $this->assertEmpty($rules); - } - - public function testCheckAccess() - { - $this->prepareData(); - - $testSuites = [ - 'reader A' => [ - 'createPost' => false, - 'readPost' => true, - 'updatePost' => false, - 'updateAnyPost' => false, - ], - 'author B' => [ - 'createPost' => true, - 'readPost' => true, - 'updatePost' => true, - 'updateAnyPost' => false, - ], - 'admin C' => [ - 'createPost' => true, - 'readPost' => true, - 'updatePost' => false, - 'updateAnyPost' => true, - ], - ]; - - $params = ['authorID' => 'author B']; - - foreach ($testSuites as $user => $tests) { - foreach ($tests as $permission => $result) { - $this->assertEquals($result, $this->auth->checkAccess($user, $permission, $params), "Checking $user can $permission"); - } - } - } - - protected function prepareData() - { - $rule = new AuthorRule; - $this->auth->add($rule); - - $createPost = $this->auth->createPermission('createPost'); - $createPost->description = 'create a post'; - $this->auth->add($createPost); - - $readPost = $this->auth->createPermission('readPost'); - $readPost->description = 'read a post'; - $this->auth->add($readPost); - - $updatePost = $this->auth->createPermission('updatePost'); - $updatePost->description = 'update a post'; - $updatePost->ruleName = $rule->name; - $this->auth->add($updatePost); - - $updateAnyPost = $this->auth->createPermission('updateAnyPost'); - $updateAnyPost->description = 'update any post'; - $this->auth->add($updateAnyPost); - - $reader = $this->auth->createRole('reader'); - $this->auth->add($reader); - $this->auth->addChild($reader, $readPost); - - $author = $this->auth->createRole('author'); - $this->auth->add($author); - $this->auth->addChild($author, $createPost); - $this->auth->addChild($author, $updatePost); - $this->auth->addChild($author, $reader); - - $admin = $this->auth->createRole('admin'); - $this->auth->add($admin); - $this->auth->addChild($admin, $author); - $this->auth->addChild($admin, $updateAnyPost); - - $this->auth->assign($reader, 'reader A'); - $this->auth->assign($author, 'author B'); - $this->auth->assign($admin, 'admin C'); - } - - public function testGetPermissionsByRole() - { - $this->prepareData(); - $roles = $this->auth->getPermissionsByRole('admin'); - $expectedPermissions = ['createPost', 'updatePost', 'readPost', 'updateAnyPost']; - $this->assertEquals(count($roles), count($expectedPermissions)); - foreach ($expectedPermissions as $permission) { - $this->assertTrue($roles[$permission] instanceof Permission); - } - } - - public function testGetPermissionsByUser() - { - $this->prepareData(); - $roles = $this->auth->getPermissionsByUser('author B'); - $expectedPermissions = ['createPost', 'updatePost', 'readPost']; - $this->assertEquals(count($roles), count($expectedPermissions)); - foreach ($expectedPermissions as $permission) { - $this->assertTrue($roles[$permission] instanceof Permission); - } - } - - public function testGetRolesByUser() - { - $this->prepareData(); - $roles = $this->auth->getRolesByUser('reader A'); - $this->assertTrue(reset($roles) instanceof Role); - $this->assertEquals($roles['reader']->name, 'reader'); - } - - public function testAssignMultipleRoles() - { - $this->prepareData(); - - $reader = $this->auth->getRole('reader'); - $author = $this->auth->getRole('author'); - $this->auth->assign($reader, 'readingAuthor'); - $this->auth->assign($author, 'readingAuthor'); - - $this->auth = $this->createManager(); - - $roles = $this->auth->getRolesByUser('readingAuthor'); - $roleNames = []; - foreach ($roles as $role) { - $roleNames[] = $role->name; - } - - $this->assertContains('reader', $roleNames, 'Roles should contain reader. Currently it has: ' . implode(', ', $roleNames)); - $this->assertContains('author', $roleNames, 'Roles should contain author. Currently it has: ' . implode(', ', $roleNames)); - } - - public function testAssignmentsToIntegerId() - { - $this->prepareData(); - - $reader = $this->auth->getRole('reader'); - $author = $this->auth->getRole('author'); - $this->auth->assign($reader, 42); - $this->auth->assign($author, 1337); - $this->auth->assign($reader, 1337); - - $this->auth = $this->createManager(); - - $this->assertEquals(0, count($this->auth->getAssignments(0))); - $this->assertEquals(1, count($this->auth->getAssignments(42))); - $this->assertEquals(2, count($this->auth->getAssignments(1337))); - } -} diff --git a/tests/unit/framework/rbac/MySQLManagerCacheTest.php b/tests/unit/framework/rbac/MySQLManagerCacheTest.php deleted file mode 100644 index 615b137..0000000 --- a/tests/unit/framework/rbac/MySQLManagerCacheTest.php +++ /dev/null @@ -1,24 +0,0 @@ - $this->getConnection(), - 'cache' => new FileCache(['cachePath' => '@yiiunit/runtime/cache']), - ]); - } -} diff --git a/tests/unit/framework/rbac/MySQLManagerTest.php b/tests/unit/framework/rbac/MySQLManagerTest.php deleted file mode 100644 index d64c0cd..0000000 --- a/tests/unit/framework/rbac/MySQLManagerTest.php +++ /dev/null @@ -1,12 +0,0 @@ -getRuntimePath() . '/rbac-items.php'; - } - - protected function getAssignmentFile() - { - return Yii::$app->getRuntimePath() . '/rbac-assignments.php'; - } - - protected function getRuleFile() - { - return Yii::$app->getRuntimePath() . '/rbac-rules.php'; - } - - protected function removeDataFiles() - { - @unlink($this->getItemFile()); - @unlink($this->getAssignmentFile()); - @unlink($this->getRuleFile()); - } - - /** - * @inheritdoc - */ - protected function createManager() - { - return new ExposedPhpManager([ - 'itemFile' => $this->getItemFile(), - 'assignmentFile' => $this->getAssignmentFile(), - 'ruleFile' => $this->getRuleFile(), - ]); - } - - protected function setUp() - { - static::$filemtime = null; - static::$time = null; - parent::setUp(); - - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('PhpManager is not compatible with HHVM.'); - } - - $this->mockApplication(); - $this->removeDataFiles(); - $this->auth = $this->createManager(); - } - - protected function tearDown() - { - $this->removeDataFiles(); - static::$filemtime = null; - static::$time = null; - parent::tearDown(); - } - - public function testSaveLoad() - { - static::$time = static::$filemtime = \time(); - - $this->prepareData(); - $items = $this->auth->items; - $children = $this->auth->children; - $assignments = $this->auth->assignments; - $rules = $this->auth->rules; - $this->auth->save(); - - $this->auth = $this->createManager(); - $this->auth->load(); - - $this->assertEquals($items, $this->auth->items); - $this->assertEquals($children, $this->auth->children); - $this->assertEquals($assignments, $this->auth->assignments); - $this->assertEquals($rules, $this->auth->rules); - } - - public function testUpdateItemName() - { - $this->prepareData(); - - $name = 'readPost'; - $permission = $this->auth->getPermission($name); - $permission->name = 'UPDATED-NAME'; - $this->assertTrue($this->auth->update($name, $permission), 'You should be able to update name.'); - } - - public function testUpdateDescription() { - $this->prepareData(); - $name = 'readPost'; - $permission = $this->auth->getPermission($name); - $permission->description = 'UPDATED-DESCRIPTION'; - $this->assertTrue($this->auth->update($name, $permission), 'You should be able to save w/o changing name.'); - } - - /** - * @expectedException \yii\base\InvalidParamException - */ - public function testOverwriteName() - { - $this->prepareData(); - $name = 'readPost'; - $permission = $this->auth->getPermission($name); - $permission->name = 'createPost'; - $this->auth->update($name, $permission); - } -} diff --git a/tests/unit/framework/rbac/SqliteManagerTest.php b/tests/unit/framework/rbac/SqliteManagerTest.php deleted file mode 100644 index 2b77fd0..0000000 --- a/tests/unit/framework/rbac/SqliteManagerTest.php +++ /dev/null @@ -1,12 +0,0 @@ - [ - 'name' => 'Requirement 1', - 'mandatory' => true, - 'condition' => true, - 'by' => 'Requirement 1', - 'memo' => 'Requirement 1', - ], - 'requirementError' => [ - 'name' => 'Requirement 2', - 'mandatory' => true, - 'condition' => false, - 'by' => 'Requirement 2', - 'memo' => 'Requirement 2', - ], - 'requirementWarning' => [ - 'name' => 'Requirement 3', - 'mandatory' => false, - 'condition' => false, - 'by' => 'Requirement 3', - 'memo' => 'Requirement 3', - ], - ]; - - $checkResult = $requirementsChecker->check($requirements)->getResult(); - $summary = $checkResult['summary']; - - $this->assertEquals(count($requirements), $summary['total'], 'Wrong summary total!'); - $this->assertEquals(1, $summary['errors'], 'Wrong summary errors!'); - $this->assertEquals(1, $summary['warnings'], 'Wrong summary warnings!'); - - $checkedRequirements = $checkResult['requirements']; - $requirementsKeys = array_flip(array_keys($requirements)); - - $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['error'], 'Passed requirement has an error!'); - $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['warning'], 'Passed requirement has a warning!'); - - $this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementError']]['error'], 'Error requirement has no error!'); - - $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementWarning']]['error'], 'Error requirement has an error!'); - $this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementWarning']]['warning'], 'Error requirement has no warning!'); - } - - /** - * @depends testCheck - */ - public function testCheckEval() - { - $requirementsChecker = new YiiRequirementChecker(); - - $requirements = [ - 'requirementPass' => [ - 'name' => 'Requirement 1', - 'mandatory' => true, - 'condition' => 'eval:2>1', - 'by' => 'Requirement 1', - 'memo' => 'Requirement 1', - ], - 'requirementError' => [ - 'name' => 'Requirement 2', - 'mandatory' => true, - 'condition' => 'eval:2<1', - 'by' => 'Requirement 2', - 'memo' => 'Requirement 2', - ], - ]; - - $checkResult = $requirementsChecker->check($requirements)->getResult(); - $checkedRequirements = $checkResult['requirements']; - $requirementsKeys = array_flip(array_keys($requirements)); - - $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['error'], 'Passed requirement has an error!'); - $this->assertEquals(false, $checkedRequirements[$requirementsKeys['requirementPass']]['warning'], 'Passed requirement has a warning!'); - - $this->assertEquals(true, $checkedRequirements[$requirementsKeys['requirementError']]['error'], 'Error requirement has no error!'); - } - - /** - * @depends testCheck - */ - public function testCheckChained() - { - $requirementsChecker = new YiiRequirementChecker(); - - $requirements1 = [ - [ - 'name' => 'Requirement 1', - 'mandatory' => true, - 'condition' => true, - 'by' => 'Requirement 1', - 'memo' => 'Requirement 1', - ], - ]; - $requirements2 = [ - [ - 'name' => 'Requirement 2', - 'mandatory' => true, - 'condition' => true, - 'by' => 'Requirement 2', - 'memo' => 'Requirement 2', - ], - ]; - $checkResult = $requirementsChecker->check($requirements1)->check($requirements2)->getResult(); - - $mergedRequirements = array_merge($requirements1, $requirements2); - - $this->assertEquals(count($mergedRequirements), $checkResult['summary']['total'], 'Wrong total checks count!'); - foreach ($mergedRequirements as $key => $mergedRequirement) { - $this->assertEquals($mergedRequirement['name'], $checkResult['requirements'][$key]['name'], 'Wrong requirements list!'); - } - } - - public function testCheckPhpExtensionVersion() - { - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('Can not test this on HHVM.'); - } - - $requirementsChecker = new YiiRequirementChecker(); - - $this->assertFalse($requirementsChecker->checkPhpExtensionVersion('some_unexisting_php_extension', '0.1'), 'No fail while checking unexisting extension!'); - $this->assertTrue($requirementsChecker->checkPhpExtensionVersion('pdo', '1.0'), 'Unable to check PDO version!'); - } - - /** - * Data provider for [[testGetByteSize()]]. - * @return array - */ - public function dataProviderGetByteSize() - { - return [ - ['456', 456], - ['5K', 5*1024], - ['16KB', 16*1024], - ['4M', 4*1024*1024], - ['14MB', 14*1024*1024], - ['7G', 7*1024*1024*1024], - ['12GB', 12*1024*1024*1024], - ]; - } - - /** - * @dataProvider dataProviderGetByteSize - * - * @param string $verboseValue verbose value. - * @param integer $expectedByteSize expected byte size. - */ - public function testGetByteSize($verboseValue, $expectedByteSize) - { - $requirementsChecker = new YiiRequirementChecker(); - - $this->assertEquals($expectedByteSize, $requirementsChecker->getByteSize($verboseValue), "Wrong byte size for '{$verboseValue}'!"); - } - - /** - * Data provider for [[testCompareByteSize()]] - * @return array - */ - public function dataProviderCompareByteSize() - { - return [ - ['2M', '2K', '>', true], - ['2M', '2K', '>=', true], - ['1K', '1024', '==', true], - ['10M', '11M', '<', true], - ['10M', '11M', '<=', true], - ]; - } - - /** - * @depends testGetByteSize - * @dataProvider dataProviderCompareByteSize - * - * @param string $a first value. - * @param string $b second value. - * @param string $compare comparison. - * @param boolean $expectedComparisonResult expected comparison result. - */ - public function testCompareByteSize($a, $b, $compare, $expectedComparisonResult) - { - $requirementsChecker = new YiiRequirementChecker(); - $this->assertEquals($expectedComparisonResult, $requirementsChecker->compareByteSize($a, $b, $compare), "Wrong compare '{$a}{$compare}{$b}'"); - } -} diff --git a/tests/unit/framework/test/ActiveFixtureTest.php b/tests/unit/framework/test/ActiveFixtureTest.php deleted file mode 100644 index b73f4ff..0000000 --- a/tests/unit/framework/test/ActiveFixtureTest.php +++ /dev/null @@ -1,96 +0,0 @@ -unloadFixtures(); - $this->loadFixtures(); - } - - public function tearDown() - { - } - - public function fixtures() - { - return [ - 'customers' => CustomerFixture::className(), - ]; - } - - public function globalFixtures() - { - return [ - InitDbFixture::className(), - ]; - } -} - -/** - * - * @author Qiang Xue - * @since 2.0 - */ -class ActiveFixtureTest extends DatabaseTestCase -{ - public function setUp() - { - parent::setUp(); - \Yii::$app->set('db', $this->getConnection()); - ActiveRecord::$db = $this->getConnection(); - } - - public function tearDown() - { - parent::tearDown(); - } - - public function testGetData() - { - $test = new MyDbTestCase(); - $test->setUp(); - $fixture = $test->getFixture('customers'); - $this->assertEquals(CustomerFixture::className(), get_class($fixture)); - $this->assertEquals(2, count($fixture)); - $this->assertEquals(1, $fixture['customer1']['id']); - $this->assertEquals('customer1@example.com', $fixture['customer1']['email']); - $this->assertEquals(2, $fixture['customer2']['id']); - $this->assertEquals('customer2@example.com', $fixture['customer2']['email']); - $test->tearDown(); - } - - public function testGetModel() - { - $test = new MyDbTestCase(); - $test->setUp(); - $fixture = $test->getFixture('customers'); - $this->assertEquals(Customer::className(), get_class($fixture->getModel('customer1'))); - $this->assertEquals(1, $fixture->getModel('customer1')->id); - $this->assertEquals('customer1@example.com', $fixture->getModel('customer1')->email); - $this->assertEquals(2, $fixture->getModel('customer2')->id); - $this->assertEquals('customer2@example.com', $fixture->getModel('customer2')->email); - $test->tearDown(); - } -} diff --git a/tests/unit/framework/test/ArrayFixtureTest.php b/tests/unit/framework/test/ArrayFixtureTest.php deleted file mode 100644 index 994dd9f..0000000 --- a/tests/unit/framework/test/ArrayFixtureTest.php +++ /dev/null @@ -1,58 +0,0 @@ -_fixture = new ArrayFixture(); - } - - public function testLoadUnloadParticularFile() - { - $this->_fixture->dataFile = '@yiiunit/framework/test/data/array_fixture.php'; - $this->assertEmpty($this->_fixture->data, 'fixture data should be empty'); - - $this->_fixture->load(); - - $this->assertCount(2, $this->_fixture->data, 'fixture data should match needed total count'); - $this->assertEquals('customer1', $this->_fixture['customer1']['name'], 'first fixture data should match'); - $this->assertEquals('customer2@example.com', $this->_fixture['customer2']['email'], 'second fixture data should match'); - } - - public function testNothingToLoad() - { - $this->_fixture->dataFile = false; - $this->assertEmpty($this->_fixture->data, 'fixture data should be empty'); - - $this->_fixture->load(); - $this->assertEmpty($this->_fixture->data, 'fixture data should not be loaded'); - } - - /** - * @expectedException \yii\base\InvalidConfigException - */ - public function testWrongDataFileException() - { - $this->_fixture->dataFile = 'wrong/fixtures/data/path/alias'; - $this->_fixture->load(); - } - -} diff --git a/tests/unit/framework/test/FixtureTest.php b/tests/unit/framework/test/FixtureTest.php deleted file mode 100644 index 9284d99..0000000 --- a/tests/unit/framework/test/FixtureTest.php +++ /dev/null @@ -1,169 +0,0 @@ -loadFixtures(); - } - - public function tearDown() - { - $this->unloadFixtures(); - } - - public function fetchFixture($name) - { - return $this->getFixture($name); - } - - public function fixtures() - { - switch ($this->scenario) { - case 0: return []; - case 1: return [ - 'fixture1' => Fixture1::className(), - ]; - case 2: return [ - 'fixture2' => Fixture2::className(), - ]; - case 3: return [ - 'fixture3' => Fixture3::className(), - ]; - case 4: return [ - 'fixture1' => Fixture1::className(), - 'fixture2' => Fixture2::className(), - ]; - case 5: return [ - 'fixture2' => Fixture2::className(), - 'fixture3' => Fixture3::className(), - ]; - case 6: return [ - 'fixture1' => Fixture1::className(), - 'fixture3' => Fixture3::className(), - ]; - case 7: - default: return [ - 'fixture1' => Fixture1::className(), - 'fixture2' => Fixture2::className(), - 'fixture3' => Fixture3::className(), - ]; - } - } -} - -class FixtureTest extends TestCase -{ - public function testDependencies() - { - foreach ($this->getDependencyTests() as $scenario => $result) { - $test = new MyTestCase(); - $test->scenario = $scenario; - $test->setUp(); - foreach ($result as $name => $loaded) { - $this->assertEquals($loaded, $test->fetchFixture($name) !== null, "Verifying scenario $scenario fixture $name"); - } - } - } - - public function testLoadSequence() - { - foreach ($this->getLoadSequenceTests() as $scenario => $result) { - $test = new MyTestCase(); - $test->scenario = $scenario; - MyTestCase::$load = ''; - MyTestCase::$unload = ''; - $test->setUp(); - $this->assertEquals($result[0], MyTestCase::$load, "Verifying scenario $scenario load sequence"); - $test->tearDown(); - $this->assertEquals($result[1], MyTestCase::$unload, "Verifying scenario $scenario unload sequence"); - } - } - - protected function getDependencyTests() - { - return [ - 0 => ['fixture1' => false, 'fixture2' => false, 'fixture3' => false], - 1 => ['fixture1' => true, 'fixture2' => false, 'fixture3' => false], - 2 => ['fixture1' => false, 'fixture2' => true, 'fixture3' => false], - 3 => ['fixture1' => false, 'fixture2' => false, 'fixture3' => true], - 4 => ['fixture1' => true, 'fixture2' => true, 'fixture3' => false], - 5 => ['fixture1' => false, 'fixture2' => true, 'fixture3' => true], - 6 => ['fixture1' => true, 'fixture2' => false, 'fixture3' => true], - 7 => ['fixture1' => true, 'fixture2' => true, 'fixture3' => true], - ]; - } - - protected function getLoadSequenceTests() - { - return [ - 0 => ['', ''], - 1 => ['321', '123'], - 2 => ['32', '23'], - 3 => ['3', '3'], - 4 => ['321', '123'], - 5 => ['32', '23'], - 6 => ['321', '123'], - 7 => ['321', '123'], - ]; - } -} diff --git a/tests/unit/framework/test/data/array_fixture.php b/tests/unit/framework/test/data/array_fixture.php deleted file mode 100644 index c5ccd4b..0000000 --- a/tests/unit/framework/test/data/array_fixture.php +++ /dev/null @@ -1,16 +0,0 @@ - [ - 'email' => 'customer1@example.com', - 'name' => 'customer1', - 'address' => 'address1', - 'status' => 1, - ], - 'customer2' => [ - 'email' => 'customer2@example.com', - 'name' => 'customer2', - 'address' => 'address2', - 'status' => 2, - ], -]; diff --git a/tests/unit/framework/test/data/customer.php b/tests/unit/framework/test/data/customer.php deleted file mode 100644 index c5ccd4b..0000000 --- a/tests/unit/framework/test/data/customer.php +++ /dev/null @@ -1,16 +0,0 @@ - [ - 'email' => 'customer1@example.com', - 'name' => 'customer1', - 'address' => 'address1', - 'status' => 1, - ], - 'customer2' => [ - 'email' => 'customer2@example.com', - 'name' => 'customer2', - 'address' => 'address2', - 'status' => 2, - ], -]; diff --git a/tests/unit/framework/validators/BooleanValidatorTest.php b/tests/unit/framework/validators/BooleanValidatorTest.php deleted file mode 100644 index d8441bc..0000000 --- a/tests/unit/framework/validators/BooleanValidatorTest.php +++ /dev/null @@ -1,60 +0,0 @@ -mockApplication(); - } - - public function testValidateValue() - { - $val = new BooleanValidator; - $this->assertTrue($val->validate(true)); - $this->assertTrue($val->validate(false)); - $this->assertTrue($val->validate('0')); - $this->assertTrue($val->validate('1')); - $this->assertFalse($val->validate('5')); - $this->assertFalse($val->validate(null)); - $this->assertFalse($val->validate([])); - $val->strict = true; - $this->assertTrue($val->validate('0')); - $this->assertTrue($val->validate('1')); - $this->assertFalse($val->validate(true)); - $this->assertFalse($val->validate(false)); - $val->trueValue = true; - $val->falseValue = false; - $this->assertFalse($val->validate('0')); - $this->assertFalse($val->validate([])); - $this->assertTrue($val->validate(true)); - $this->assertTrue($val->validate(false)); - } - - public function testValidateAttributeAndError() - { - $obj = new FakedValidationModel; - $obj->attrA = true; - $obj->attrB = '1'; - $obj->attrC = '0'; - $obj->attrD = []; - $val = new BooleanValidator; - $val->validateAttribute($obj, 'attrA'); - $this->assertFalse($obj->hasErrors('attrA')); - $val->validateAttribute($obj, 'attrC'); - $this->assertFalse($obj->hasErrors('attrC')); - $val->strict = true; - $val->validateAttribute($obj, 'attrB'); - $this->assertFalse($obj->hasErrors('attrB')); - $val->validateAttribute($obj, 'attrD'); - $this->assertTrue($obj->hasErrors('attrD')); - } -} diff --git a/tests/unit/framework/validators/CompareValidatorTest.php b/tests/unit/framework/validators/CompareValidatorTest.php deleted file mode 100644 index 239be30..0000000 --- a/tests/unit/framework/validators/CompareValidatorTest.php +++ /dev/null @@ -1,176 +0,0 @@ -mockApplication(); - } - - public function testValidateValueException() - { - $this->setExpectedException('yii\base\InvalidConfigException'); - $val = new CompareValidator; - $val->validate('val'); - } - - public function testValidateValue() - { - $value = 18449; - // default config - $val = new CompareValidator(['compareValue' => $value]); - $this->assertTrue($val->validate($value)); - $this->assertTrue($val->validate((string) $value)); - $this->assertFalse($val->validate($value + 1)); - foreach ($this->getOperationTestData($value) as $op => $tests) { - $val = new CompareValidator(['compareValue' => $value]); - $val->operator = $op; - foreach ($tests as $test) { - $this->assertEquals($test[1], $val->validate($test[0]), "Testing $op"); - } - } - } - - protected function getOperationTestData($value) - { - return [ - '===' => [ - [$value, true], - [(string) $value, true], - [(float) $value, true], - [$value + 1, false], - ], - '!=' => [ - [$value, false], - [(string) $value, false], - [(float) $value, false], - [$value + 0.00001, true], - [false, true], - ], - '!==' => [ - [$value, false], - [(string) $value, false], - [(float) $value, false], - [false, true], - ], - '>' => [ - [$value, false], - [$value + 1, true], - [$value - 1, false], - ], - '>=' => [ - [$value, true], - [$value + 1, true], - [$value - 1, false], - ], - '<' => [ - [$value, false], - [$value + 1, false], - [$value - 1, true], - ], - '<=' => [ - [$value, true], - [$value + 1, false], - [$value - 1, true], - ], - //'non-op' => [ - // [$value, false], - // [$value + 1, false], - // [$value - 1, false], - //], - ]; - } - - public function testValidateAttribute() - { - // invalid-array - $val = new CompareValidator; - $model = new FakedValidationModel; - $model->attr = ['test_val']; - $val->validateAttribute($model, 'attr'); - $this->assertTrue($model->hasErrors('attr')); - $val = new CompareValidator(['compareValue' => 'test-string']); - $model = new FakedValidationModel; - $model->attr_test = 'test-string'; - $val->validateAttribute($model, 'attr_test'); - $this->assertFalse($model->hasErrors('attr_test')); - $val = new CompareValidator(['compareAttribute' => 'attr_test_val']); - $model = new FakedValidationModel; - $model->attr_test = 'test-string'; - $model->attr_test_val = 'test-string'; - $val->validateAttribute($model, 'attr_test'); - $this->assertFalse($model->hasErrors('attr_test')); - $this->assertFalse($model->hasErrors('attr_test_val')); - $val = new CompareValidator(['compareAttribute' => 'attr_test_val']); - $model = new FakedValidationModel; - $model->attr_test = 'test-string'; - $model->attr_test_val = 'test-string-false'; - $val->validateAttribute($model, 'attr_test'); - $this->assertTrue($model->hasErrors('attr_test')); - $this->assertFalse($model->hasErrors('attr_test_val')); - // assume: _repeat - $val = new CompareValidator; - $model = new FakedValidationModel; - $model->attr_test = 'test-string'; - $model->attr_test_repeat = 'test-string'; - $val->validateAttribute($model, 'attr_test'); - $this->assertFalse($model->hasErrors('attr_test')); - $this->assertFalse($model->hasErrors('attr_test_repeat')); - $val = new CompareValidator; - $model = new FakedValidationModel; - $model->attr_test = 'test-string'; - $model->attr_test_repeat = 'test-string2'; - $val->validateAttribute($model, 'attr_test'); - $this->assertTrue($model->hasErrors('attr_test')); - $this->assertFalse($model->hasErrors('attr_test_repeat')); - // not existing op - $val = new CompareValidator(); - $val->operator = '<>'; - $model = FakedValidationModel::createWithAttributes(['attr_o' => 5, 'attr_o_repeat' => 5]); - $val->validateAttribute($model, 'attr_o'); - $this->assertTrue($model->hasErrors('attr_o')); - } - - public function testValidateAttributeOperators() - { - $value = 55; - foreach ($this->getOperationTestData($value) as $operator => $tests) { - $val = new CompareValidator(['operator' => $operator, 'compareValue' => $value]); - foreach ($tests as $test) { - $model = new FakedValidationModel; - $model->attr_test = $test[0]; - $val->validateAttribute($model, 'attr_test'); - $this->assertEquals($test[1], !$model->hasErrors('attr_test')); - } - - } - } - - public function testEnsureMessageSetOnInit() - { - foreach ($this->getOperationTestData(1337) as $operator => $tests) { - $val = new CompareValidator(['operator' => $operator]); - $this->assertTrue(strlen($val->message) > 1); - } - try { - new CompareValidator(['operator' => '<>']); - } catch (InvalidConfigException $e) { - return; - } catch (\Exception $e) { - $this->fail('InvalidConfigException expected' . get_class($e) . 'received'); - - return; - } - $this->fail('InvalidConfigException expected none received'); - } -} diff --git a/tests/unit/framework/validators/DateValidatorTest.php b/tests/unit/framework/validators/DateValidatorTest.php deleted file mode 100644 index 58e60a5..0000000 --- a/tests/unit/framework/validators/DateValidatorTest.php +++ /dev/null @@ -1,201 +0,0 @@ -mockApplication([ - 'timeZone' => 'UTC', - 'language' => 'ru-RU', - ]); - } - - protected function tearDown() - { - parent::tearDown(); - IntlTestHelper::resetIntlStatus(); - } - - public function testEnsureMessageIsSet() - { - $val = new DateValidator; - $this->assertTrue($val->message !== null && strlen($val->message) > 1); - } - - public function testIntlValidateValue() - { - $this->testValidateValue(); - - $this->mockApplication([ - 'language' => 'en-GB', - 'components' => [ - 'formatter' => [ - 'dateFormat' => 'short', - ] - ] - ]); - $val = new DateValidator(); - $this->assertTrue($val->validate('31/5/2017')); - $this->assertFalse($val->validate('5/31/2017')); - $val = new DateValidator(['format' => 'short', 'locale' => 'en-GB']); - $this->assertTrue($val->validate('31/5/2017')); - $this->assertFalse($val->validate('5/31/2017')); - - $this->mockApplication([ - 'language' => 'de-DE', - 'components' => [ - 'formatter' => [ - 'dateFormat' => 'short', - ] - ] - ]); - $val = new DateValidator(); - $this->assertTrue($val->validate('31.5.2017')); - $this->assertFalse($val->validate('5.31.2017')); - $val = new DateValidator(['format' => 'short', 'locale' => 'de-DE']); - $this->assertTrue($val->validate('31.5.2017')); - $this->assertFalse($val->validate('5.31.2017')); - } - - public function testValidateValue() - { - // test PHP format - $val = new DateValidator(['format' => 'php:Y-m-d']); - $this->assertFalse($val->validate('3232-32-32')); - $this->assertTrue($val->validate('2013-09-13')); - $this->assertFalse($val->validate('31.7.2013')); - $this->assertFalse($val->validate('31-7-2013')); - $this->assertFalse($val->validate('20121212')); - $this->assertFalse($val->validate('asdasdfasfd')); - $this->assertFalse($val->validate('2012-12-12foo')); - $this->assertFalse($val->validate('')); - $this->assertFalse($val->validate(time())); - $val->format = 'php:U'; - $this->assertTrue($val->validate(time())); - $val->format = 'php:d.m.Y'; - $this->assertTrue($val->validate('31.7.2013')); - $val->format = 'php:Y-m-!d H:i:s'; - $this->assertTrue($val->validate('2009-02-15 15:16:17')); - - // test ICU format - $val = new DateValidator(['format' => 'yyyy-MM-dd']); - $this->assertFalse($val->validate('3232-32-32')); - $this->assertTrue($val->validate('2013-09-13')); - $this->assertFalse($val->validate('31.7.2013')); - $this->assertFalse($val->validate('31-7-2013')); - $this->assertFalse($val->validate('20121212')); - $this->assertFalse($val->validate('asdasdfasfd')); - $this->assertFalse($val->validate('2012-12-12foo')); - $this->assertFalse($val->validate('')); - $this->assertFalse($val->validate(time())); - $val->format = 'dd.MM.yyyy'; - $this->assertTrue($val->validate('31.7.2013')); - $val->format = 'yyyy-MM-dd HH:mm:ss'; - $this->assertTrue($val->validate('2009-02-15 15:16:17')); - } - - public function testIntlValidateAttributePHPFormat() - { - $this->testValidateAttributePHPFormat(); - } - - public function testValidateAttributePHPFormat() - { - // error-array-add - $val = new DateValidator(['format' => 'php:Y-m-d']); - $model = new FakedValidationModel; - $model->attr_date = '2013-09-13'; - $val->validateAttribute($model, 'attr_date'); - $this->assertFalse($model->hasErrors('attr_date')); - $model = new FakedValidationModel; - $model->attr_date = '1375293913'; - $val->validateAttribute($model, 'attr_date'); - $this->assertTrue($model->hasErrors('attr_date')); - //// timestamp attribute - $val = new DateValidator(['format' => 'php:Y-m-d', 'timestampAttribute' => 'attr_timestamp']); - $model = new FakedValidationModel; - $model->attr_date = '2013-09-13'; - $model->attr_timestamp = true; - $val->validateAttribute($model, 'attr_date'); - $this->assertFalse($model->hasErrors('attr_date')); - $this->assertFalse($model->hasErrors('attr_timestamp')); - $this->assertEquals( - mktime(0, 0, 0, 9, 13, 2013), // 2013-09-13 -// DateTime::createFromFormat('Y-m-d', '2013-09-13')->getTimestamp(), - $model->attr_timestamp - ); - $val = new DateValidator(['format' => 'php:Y-m-d']); - $model = FakedValidationModel::createWithAttributes(['attr_date' => []]); - $val->validateAttribute($model, 'attr_date'); - $this->assertTrue($model->hasErrors('attr_date')); - - } - - public function testIntlValidateAttributeICUFormat() - { - $this->testValidateAttributeICUFormat(); - } - - public function testValidateAttributeICUFormat() - { - // error-array-add - $val = new DateValidator(['format' => 'yyyy-MM-dd']); - $model = new FakedValidationModel; - $model->attr_date = '2013-09-13'; - $val->validateAttribute($model, 'attr_date'); - $this->assertFalse($model->hasErrors('attr_date')); - $model = new FakedValidationModel; - $model->attr_date = '1375293913'; - $val->validateAttribute($model, 'attr_date'); - $this->assertTrue($model->hasErrors('attr_date')); - //// timestamp attribute - $val = new DateValidator(['format' => 'yyyy-MM-dd', 'timestampAttribute' => 'attr_timestamp']); - $model = new FakedValidationModel; - $model->attr_date = '2013-09-13'; - $model->attr_timestamp = true; - $val->validateAttribute($model, 'attr_date'); - $this->assertFalse($model->hasErrors('attr_date')); - $this->assertFalse($model->hasErrors('attr_timestamp')); - $this->assertEquals( - mktime(0, 0, 0, 9, 13, 2013), // 2013-09-13 -// DateTime::createFromFormat('Y-m-d', '2013-09-13')->getTimestamp(), - $model->attr_timestamp - ); - $val = new DateValidator(['format' => 'yyyy-MM-dd']); - $model = FakedValidationModel::createWithAttributes(['attr_date' => []]); - $val->validateAttribute($model, 'attr_date'); - $this->assertTrue($model->hasErrors('attr_date')); - $val = new DateValidator(['format' => 'yyyy-MM-dd']); - $model = FakedValidationModel::createWithAttributes(['attr_date' => '2012-12-12foo']); - $val->validateAttribute($model, 'attr_date'); - $this->assertTrue($model->hasErrors('attr_date')); - } - - public function testIntlMultibyteString() - { - $val = new DateValidator(['format' => 'dd MMM yyyy', 'locale' => 'de_DE']); - $model = FakedValidationModel::createWithAttributes(['attr_date' => '12 Mai 2014']); - $val->validateAttribute($model, 'attr_date'); - $this->assertFalse($model->hasErrors('attr_date')); - - $val = new DateValidator(['format' => 'dd MMM yyyy', 'locale' => 'ru_RU']); - $model = FakedValidationModel::createWithAttributes(['attr_date' => '12 мая 2014']); - $val->validateAttribute($model, 'attr_date'); - $this->assertFalse($model->hasErrors('attr_date')); - } -} diff --git a/tests/unit/framework/validators/DefaultValueValidatorTest.php b/tests/unit/framework/validators/DefaultValueValidatorTest.php deleted file mode 100644 index 80a0fdc..0000000 --- a/tests/unit/framework/validators/DefaultValueValidatorTest.php +++ /dev/null @@ -1,40 +0,0 @@ -mockApplication(); - } - - public function testValidateAttribute() - { - $val = new DefaultValueValidator; - $val->value = 'test_value'; - $obj = new \stdclass; - $obj->attrA = 'attrA'; - $obj->attrB = null; - $obj->attrC = ''; - // original values to chek which attritubes where modified - $objB = clone $obj; - $val->validateAttribute($obj, 'attrB'); - $this->assertEquals($val->value, $obj->attrB); - $this->assertEquals($objB->attrA, $obj->attrA); - $val->value = 'new_test_value'; - $obj = clone $objB; // get clean object - $val->validateAttribute($obj, 'attrC'); - $this->assertEquals('new_test_value', $obj->attrC); - $this->assertEquals($objB->attrA, $obj->attrA); - $val->validateAttribute($obj, 'attrA'); - $this->assertEquals($objB->attrA, $obj->attrA); - } -} diff --git a/tests/unit/framework/validators/EachValidatorTest.php b/tests/unit/framework/validators/EachValidatorTest.php deleted file mode 100644 index 3a50e59..0000000 --- a/tests/unit/framework/validators/EachValidatorTest.php +++ /dev/null @@ -1,75 +0,0 @@ -mockApplication(); - } - - public function testArrayFormat() - { - $validator = new EachValidator(['rule' => ['required']]); - - $this->assertFalse($validator->validate('not array')); - $this->assertTrue($validator->validate(['value'])); - } - - /** - * @depends testArrayFormat - */ - public function testValidate() - { - $validator = new EachValidator(['rule' => ['integer']]); - - $this->assertTrue($validator->validate([1, 3, 8])); - $this->assertFalse($validator->validate([1, 'text', 8])); - } - - /** - * @depends testArrayFormat - */ - public function testFilter() - { - $model = FakedValidationModel::createWithAttributes([ - 'attr_one' => [ - ' to be trimmed ' - ], - ]); - $validator = new EachValidator(['rule' => ['trim']]); - $validator->validateAttribute($model, 'attr_one'); - $this->assertEquals('to be trimmed', $model->attr_one[0]); - } - - /** - * @depends testValidate - */ - public function testAllowMessageFromRule() - { - $model = FakedValidationModel::createWithAttributes([ - 'attr_one' => [ - 'text' - ], - ]); - $validator = new EachValidator(['rule' => ['integer']]); - - $validator->allowMessageFromRule = true; - $validator->validateAttribute($model, 'attr_one'); - $this->assertContains('integer', $model->getFirstError('attr_one')); - - $model->clearErrors(); - $validator->allowMessageFromRule = false; - $validator->validateAttribute($model, 'attr_one'); - $this->assertNotContains('integer', $model->getFirstError('attr_one')); - } -} \ No newline at end of file diff --git a/tests/unit/framework/validators/EmailValidatorTest.php b/tests/unit/framework/validators/EmailValidatorTest.php deleted file mode 100644 index 4365a81..0000000 --- a/tests/unit/framework/validators/EmailValidatorTest.php +++ /dev/null @@ -1,118 +0,0 @@ -mockApplication(); - } - - public function testValidateValue() - { - $validator = new EmailValidator(); - - $this->assertTrue($validator->validate('sam@rmcreative.ru')); - $this->assertTrue($validator->validate('5011@gmail.com')); - $this->assertFalse($validator->validate('rmcreative.ru')); - $this->assertFalse($validator->validate('Carsten Brandt ')); - $this->assertFalse($validator->validate('"Carsten Brandt" ')); - $this->assertFalse($validator->validate('')); - $this->assertFalse($validator->validate('info@örtliches.de')); - $this->assertFalse($validator->validate('sam@рмкреатиф.ru')); - - $validator->allowName = true; - - $this->assertTrue($validator->validate('sam@rmcreative.ru')); - $this->assertTrue($validator->validate('5011@gmail.com')); - $this->assertFalse($validator->validate('rmcreative.ru')); - $this->assertTrue($validator->validate('Carsten Brandt ')); - $this->assertTrue($validator->validate('"Carsten Brandt" ')); - $this->assertTrue($validator->validate('')); - $this->assertFalse($validator->validate('info@örtliches.de')); - $this->assertFalse($validator->validate('sam@рмкреатиф.ru')); - $this->assertFalse($validator->validate('Informtation info@oertliches.de')); - $this->assertTrue($validator->validate('test@example.com')); - $this->assertTrue($validator->validate('John Smith ')); - $this->assertFalse($validator->validate('John Smith ')); - } - - public function testValidateValueIdn() - { - if (!function_exists('idn_to_ascii')) { - $this->markTestSkipped('Intl extension required'); - - return; - } - $validator = new EmailValidator(); - $validator->enableIDN = true; - - $this->assertTrue($validator->validate('5011@example.com')); - $this->assertTrue($validator->validate('example@äüößìà.de')); - $this->assertTrue($validator->validate('example@xn--zcack7ayc9a.de')); - $this->assertTrue($validator->validate('info@örtliches.de')); - $this->assertTrue($validator->validate('sam@рмкреатиф.ru')); - $this->assertTrue($validator->validate('sam@rmcreative.ru')); - $this->assertTrue($validator->validate('5011@gmail.com')); - $this->assertFalse($validator->validate('rmcreative.ru')); - $this->assertFalse($validator->validate('Carsten Brandt ')); - $this->assertFalse($validator->validate('"Carsten Brandt" ')); - $this->assertFalse($validator->validate('')); - - $validator->allowName = true; - - $this->assertTrue($validator->validate('info@örtliches.de')); - $this->assertTrue($validator->validate('Informtation ')); - $this->assertFalse($validator->validate('Informtation info@örtliches.de')); - $this->assertTrue($validator->validate('sam@рмкреатиф.ru')); - $this->assertTrue($validator->validate('sam@rmcreative.ru')); - $this->assertTrue($validator->validate('5011@gmail.com')); - $this->assertFalse($validator->validate('rmcreative.ru')); - $this->assertTrue($validator->validate('Carsten Brandt ')); - $this->assertTrue($validator->validate('"Carsten Brandt" ')); - $this->assertTrue($validator->validate('')); - $this->assertTrue($validator->validate('test@example.com')); - $this->assertTrue($validator->validate('John Smith ')); - $this->assertFalse($validator->validate('John Smith ')); - } - - public function testValidateValueMx() - { - $validator = new EmailValidator(); - - $validator->checkDNS = true; - $this->assertTrue($validator->validate('5011@gmail.com')); - - $validator->checkDNS = false; - $this->assertTrue($validator->validate('test@nonexistingsubdomain.example.com')); - $validator->checkDNS = true; - $this->assertFalse($validator->validate('test@nonexistingsubdomain.example.com')); - - $validator->checkDNS = true; - $validator->allowName = true; - $emails = [ - 'ipetrov@gmail.com', - 'Ivan Petrov ', - ]; - foreach($emails as $email) { - $this->assertTrue($validator->validate($email),"Email: '$email' failed to validate(checkDNS=true, allowName=true)"); - } - } - - public function testValidateAttribute() - { - $val = new EmailValidator(); - $model = new FakedValidationModel(); - $model->attr_email = '5011@gmail.com'; - $val->validateAttribute($model, 'attr_email'); - $this->assertFalse($model->hasErrors('attr_email')); - } -} diff --git a/tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php b/tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php deleted file mode 100644 index af1d277..0000000 --- a/tests/unit/framework/validators/ExistValidatorDriverTests/ExistValidatorPostgresTest.php +++ /dev/null @@ -1,12 +0,0 @@ -mockApplication(); - ActiveRecord::$db = $this->getConnection(); - } - - public function testValidateValueExpectedException() - { - try { - $val = new ExistValidator(); - $val->validate('ref'); - $this->fail('Exception should have been thrown at this time'); - } catch (Exception $e) { - $this->assertInstanceOf('yii\base\InvalidConfigException', $e); - $this->assertEquals('The "targetClass" property must be set.', $e->getMessage()); - } - // combine to save the time creating a new db-fixture set (likely ~5 sec) - try { - $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::className()]); - $val->validate('ref'); - $this->fail('Exception should have been thrown at this time'); - } catch (Exception $e) { - $this->assertInstanceOf('yii\base\InvalidConfigException', $e); - $this->assertEquals('The "targetAttribute" property must be configured as a string.', $e->getMessage()); - } - } - - public function testValidateValue() - { - $val = new ExistValidator(['targetClass' => ValidatorTestRefModel::className(), 'targetAttribute' => 'id']); - $this->assertTrue($val->validate(2)); - $this->assertTrue($val->validate(5)); - $this->assertFalse($val->validate(99)); - $this->assertFalse($val->validate(['1'])); - } - - public function testValidateAttribute() - { - // existing value on different table - $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::className(), 'targetAttribute' => 'id']); - $m = ValidatorTestRefModel::findOne(['id' => 1]); - $val->validateAttribute($m, 'ref'); - $this->assertFalse($m->hasErrors()); - // non-existing value on different table - $val = new ExistValidator(['targetClass' => ValidatorTestMainModel::className(), 'targetAttribute' => 'id']); - $m = ValidatorTestRefModel::findOne(['id' => 6]); - $val->validateAttribute($m, 'ref'); - $this->assertTrue($m->hasErrors('ref')); - // existing value on same table - $val = new ExistValidator(['targetAttribute' => 'ref']); - $m = ValidatorTestRefModel::findOne(['id' => 2]); - $val->validateAttribute($m, 'test_val'); - $this->assertFalse($m->hasErrors()); - // non-existing value on same table - $val = new ExistValidator(['targetAttribute' => 'ref']); - $m = ValidatorTestRefModel::findOne(['id' => 5]); - $val->validateAttribute($m, 'test_val_fail'); - $this->assertTrue($m->hasErrors('test_val_fail')); - // check for given value (true) - $val = new ExistValidator(); - $m = ValidatorTestRefModel::findOne(['id' => 3]); - $val->validateAttribute($m, 'ref'); - $this->assertFalse($m->hasErrors()); - // check for given defaults (false) - $val = new ExistValidator(); - $m = ValidatorTestRefModel::findOne(['id' => 4]); - $m->a_field = 'some new value'; - $val->validateAttribute($m, 'a_field'); - $this->assertTrue($m->hasErrors('a_field')); - // existing array - $val = new ExistValidator(['targetAttribute' => 'ref']); - $val->allowArray = true; - $m = new ValidatorTestRefModel(); - $m->test_val = [2, 3, 4, 5]; - $val->validateAttribute($m, 'test_val'); - $this->assertFalse($m->hasErrors('test_val')); - // non-existing array - $val = new ExistValidator(['targetAttribute' => 'ref']); - $val->allowArray = true; - $m = new ValidatorTestRefModel(); - $m->test_val = [95, 96, 97, 98]; - $val->validateAttribute($m, 'test_val'); - $this->assertTrue($m->hasErrors('test_val')); - // partial-existing array - $val = new ExistValidator(['targetAttribute' => 'ref']); - $val->allowArray = true; - $m = new ValidatorTestRefModel(); - $m->test_val = [2, 97, 3, 98]; - $val->validateAttribute($m, 'test_val'); - $this->assertTrue($m->hasErrors('test_val')); - // existing array (allowArray = false) - $val = new ExistValidator(['targetAttribute' => 'ref']); - $val->allowArray = false; - $m = new ValidatorTestRefModel(); - $m->test_val = [2, 3, 4, 5]; - $val->validateAttribute($m, 'test_val'); - $this->assertTrue($m->hasErrors('test_val')); - // non-existing array (allowArray = false) - $val = new ExistValidator(['targetAttribute' => 'ref']); - $val->allowArray = false; - $m = new ValidatorTestRefModel(); - $m->test_val = [95, 96, 97, 98]; - $val->validateAttribute($m, 'test_val'); - $this->assertTrue($m->hasErrors('test_val')); - } - - public function testValidateCompositeKeys() - { - $val = new ExistValidator([ - 'targetClass' => OrderItem::className(), - 'targetAttribute' => ['order_id', 'item_id'], - ]); - // validate old record - $m = OrderItem::findOne(['order_id' => 1, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertFalse($m->hasErrors('order_id')); - - // validate new record - $m = new OrderItem(['order_id' => 1, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertFalse($m->hasErrors('order_id')); - $m = new OrderItem(['order_id' => 10, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertTrue($m->hasErrors('order_id')); - - $val = new ExistValidator([ - 'targetClass' => OrderItem::className(), - 'targetAttribute' => ['id' => 'order_id'], - ]); - // validate old record - $m = Order::findOne(1); - $val->validateAttribute($m, 'id'); - $this->assertFalse($m->hasErrors('id')); - $m = Order::findOne(1); - $m->id = 10; - $val->validateAttribute($m, 'id'); - $this->assertTrue($m->hasErrors('id')); - - $m = new Order(['id' => 1]); - $val->validateAttribute($m, 'id'); - $this->assertFalse($m->hasErrors('id')); - $m = new Order(['id' => 10]); - $val->validateAttribute($m, 'id'); - $this->assertTrue($m->hasErrors('id')); - } -} diff --git a/tests/unit/framework/validators/FileValidatorTest.php b/tests/unit/framework/validators/FileValidatorTest.php deleted file mode 100644 index d2d0358..0000000 --- a/tests/unit/framework/validators/FileValidatorTest.php +++ /dev/null @@ -1,377 +0,0 @@ -mockApplication(); - } - - public function testAssureMessagesSetOnInit() - { - $val = new FileValidator(); - foreach (['message', 'uploadRequired', 'tooMany', 'wrongExtension', 'tooBig', 'tooSmall', 'wrongMimeType'] as $attr) { - $this->assertTrue(is_string($val->$attr)); - } - } - - public function testTypeSplitOnInit() - { - $val = new FileValidator(['extensions' => 'jpeg, jpg, gif']); - $this->assertEquals(['jpeg', 'jpg', 'gif'], $val->extensions); - - $val = new FileValidator(['extensions' => 'jpeg']); - $this->assertEquals(['jpeg'], $val->extensions); - - $val = new FileValidator(['extensions' => '']); - $this->assertEquals([], $val->extensions); - - $val = new FileValidator(['extensions' => []]); - $this->assertEquals([], $val->extensions); - - $val = new FileValidator(); - $this->assertEquals([], $val->extensions); - - $val = new FileValidator(['extensions' => ['jpeg', 'exe']]); - $this->assertEquals(['jpeg', 'exe'], $val->extensions); - } - - public function testMimeTypeSplitOnInit() - { - $val = new FileValidator(['mimeTypes' => 'text/plain, image/png']); - $this->assertEquals(['text/plain', 'image/png'], $val->mimeTypes); - - $val = new FileValidator(['mimeTypes' => 'text/plain']); - $this->assertEquals(['text/plain'], $val->mimeTypes); - - $val = new FileValidator(['mimeTypes' => '']); - $this->assertEquals([], $val->mimeTypes); - - $val = new FileValidator(['mimeTypes' => []]); - $this->assertEquals([], $val->mimeTypes); - - $val = new FileValidator(); - $this->assertEquals([], $val->mimeTypes); - - $val = new FileValidator(['mimeTypes' => ['text/plain', 'image/png']]); - $this->assertEquals(['text/plain', 'image/png'], $val->mimeTypes); - } - - public function testGetSizeLimit() - { - $size = $this->sizeToBytes(ini_get('upload_max_filesize')); - $val = new FileValidator(); - $this->assertEquals($size, $val->getSizeLimit()); - $val->maxSize = $size + 1; // set and test if value is overridden - $this->assertEquals($size, $val->getSizeLimit()); - $val->maxSize = abs($size - 1); - $this->assertEquals($size - 1, $val->getSizeLimit()); - $_POST['MAX_FILE_SIZE'] = $size + 1; - $this->assertEquals($size - 1, $val->getSizeLimit()); - $_POST['MAX_FILE_SIZE'] = abs($size - 2); - $this->assertSame($_POST['MAX_FILE_SIZE'], $val->getSizeLimit()); - } - - protected function sizeToBytes($sizeStr) - { - switch (substr($sizeStr, -1)) { - case 'M': - case 'm': - return (int) $sizeStr * 1048576; - case 'K': - case 'k': - return (int) $sizeStr * 1024; - case 'G': - case 'g': - return (int) $sizeStr * 1073741824; - default: - return (int) $sizeStr; - } - } - - public function testValidateAttributeMultiple() - { - $val = new FileValidator([ - 'maxFiles' => 2, - ]); - $m = FakedValidationModel::createWithAttributes(['attr_files' => 'path']); - $val->validateAttribute($m, 'attr_files'); - $this->assertTrue($m->hasErrors('attr_files')); - $m = FakedValidationModel::createWithAttributes(['attr_files' => []]); - $val->validateAttribute($m, 'attr_files'); - $this->assertTrue($m->hasErrors('attr_files')); - $this->assertSame($val->uploadRequired, current($m->getErrors('attr_files'))); - $m = FakedValidationModel::createWithAttributes( - [ - 'attr_files' => $this->createTestFiles( - [ - [ - 'name' => 'test_up_1.txt', - 'size' => 1024, - ], - [ - 'error' => UPLOAD_ERR_NO_FILE, - ], - ] - ) - ] - ); - $val->validateAttribute($m, 'attr_files'); - $this->assertFalse($m->hasErrors('attr_files')); - $m = FakedValidationModel::createWithAttributes([ - 'attr_files' => $this->createTestFiles([ - [''], [''], [''] - ]) - ]); - $val->validateAttribute($m, 'attr_files'); - $this->assertTrue($m->hasErrors()); - $this->assertTrue(stripos(current($m->getErrors('attr_files')), 'you can upload at most') !== false); - $m = FakedValidationModel::createWithAttributes( - [ - 'attr_images' => $this->createTestFiles( - [ - [ - 'name' => 'image.png', - 'size' => 1024, - 'type' => 'image/png' - ], - [ - 'name' => 'image.png', - 'size' => 1024, - 'type' => 'image/png' - ], - [ - 'name' => 'text.txt', - 'size' => 1024 - ], - ] - ) - ] - ); - $m->setScenario('validateMultipleFiles'); - $this->assertFalse($m->validate()); - $this->assertTrue(stripos(current($m->getErrors('attr_images')), - 'Only files with these extensions are allowed') !== false); - - $m = FakedValidationModel::createWithAttributes( - [ - 'attr_images' => $this->createTestFiles( - [ - [ - 'name' => 'image.png', - 'size' => 1024, - 'type' => 'image/png' - ], - [ - 'name' => 'image.png', - 'size' => 1024, - 'type' => 'image/png' - ], - ] - ) - ] - ); - $m->setScenario('validateMultipleFiles'); - $this->assertTrue($m->validate()); - - $m = FakedValidationModel::createWithAttributes( - [ - 'attr_image' => $this->createTestFiles( - [ - [ - 'name' => 'text.txt', - 'size' => 1024, - ], - ] - ) - ] - ); - $m->setScenario('validateFile'); - $this->assertFalse($m->validate()); - } - - /** - * @param array $params - * @return UploadedFile[] - */ - protected function createTestFiles($params = []) - { - $rndString = function ($len = 10) { - $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - $randomString = ''; - for ($i = 0; $i < $len; $i++) { - $randomString .= $characters[rand(0, strlen($characters) - 1)]; - } - - return $randomString; - }; - $files = []; - foreach ($params as $param) { - if (empty($param) && count($params) != 1) { - $files[] = ['no instance of UploadedFile']; - continue; - } - $name = isset($param['name']) ? $param['name'] : $rndString(); - $tempName = \Yii::getAlias('@yiiunit/runtime/validators/file/tmp/') . $name; - if (is_readable($tempName)) { - $size = filesize($tempName); - } else { - $size = isset($param['size']) ? $param['size'] : rand( - 1, - $this->sizeToBytes(ini_get('upload_max_filesize')) - ); - } - $type = isset($param['type']) ? $param['type'] : 'text/plain'; - $error = isset($param['error']) ? $param['error'] : UPLOAD_ERR_OK; - if (count($params) == 1) { - $error = empty($param) ? UPLOAD_ERR_NO_FILE : $error; - - return new UploadedFile([ - 'name' => $name, - 'tempName' => $tempName, - 'type' => $type, - 'size' => $size, - 'error' => $error - ]); - } - $files[] = new UploadedFile([ - 'name' => $name, - 'tempName' => $tempName, - 'type' => $type, - 'size' => $size, - 'error' => $error - ]); - } - - return $files; - } - - public function testValidateAttribute() - { - // single File - $val = new FileValidator(); - $m = $this->createModelForAttributeTest(); - $val->validateAttribute($m, 'attr_files'); - $this->assertFalse($m->hasErrors()); - $val->validateAttribute($m, 'attr_files_empty'); - $this->assertTrue($m->hasErrors('attr_files_empty')); - $this->assertSame($val->uploadRequired, current($m->getErrors('attr_files_empty'))); - - // single File with skipOnEmpty = false - $val = new FileValidator(['skipOnEmpty' => false]); - $m = $this->createModelForAttributeTest(); - $val->validateAttribute($m, 'attr_files'); - $this->assertFalse($m->hasErrors()); - $val->validateAttribute($m, 'attr_files_empty'); - $this->assertTrue($m->hasErrors('attr_files_empty')); - $this->assertSame($val->uploadRequired, current($m->getErrors('attr_files_empty'))); - $m = $this->createModelForAttributeTest(); - - // too big - $val = new FileValidator(['maxSize' => 128]); - $val->validateAttribute($m, 'attr_files'); - $this->assertTrue($m->hasErrors('attr_files')); - $this->assertTrue(stripos(current($m->getErrors('attr_files')), 'too big') !== false); - // to Small - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(['minSize' => 2048]); - $val->validateAttribute($m, 'attr_files'); - $this->assertTrue($m->hasErrors('attr_files')); - $this->assertTrue(stripos(current($m->getErrors('attr_files')), 'too small') !== false); - // UPLOAD_ERR_INI_SIZE/UPLOAD_ERR_FORM_SIZE - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_ini'); - $this->assertTrue($m->hasErrors('attr_err_ini')); - $this->assertTrue(stripos(current($m->getErrors('attr_err_ini')), 'too big') !== false); - // UPLOAD_ERR_PARTIAL - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_part'); - $this->assertTrue($m->hasErrors('attr_err_part')); - $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_part'))); - } - - public function testValidateAttributeType() - { - $val = new FileValidator([ - 'extensions' => 'jpeg, jpg', - 'checkExtensionByMimeType' => false, - ]); - $m = FakedValidationModel::createWithAttributes( - [ - 'attr_jpg' => $this->createTestFiles([['name' => 'one.jpeg']]), - 'attr_exe' => $this->createTestFiles([['name' => 'bad.exe']]), - ] - ); - $val->validateAttribute($m, 'attr_jpg'); - $this->assertFalse($m->hasErrors('attr_jpg')); - $val->validateAttribute($m, 'attr_exe'); - $this->assertTrue($m->hasErrors('attr_exe')); - $this->assertTrue(stripos(current($m->getErrors('attr_exe')), 'Only files with these extensions ') !== false); - } - - protected function createModelForAttributeTest() - { - return FakedValidationModel::createWithAttributes( - [ - 'attr_files' => $this->createTestFiles([ - ['name' => 'abc.jpg', 'size' => 1024, 'type' => 'image/jpeg'], - ]), - 'attr_files_empty' => $this->createTestFiles([[]]), - 'attr_err_ini' => $this->createTestFiles([['error' => UPLOAD_ERR_INI_SIZE]]), - 'attr_err_part' => $this->createTestFiles([['error' => UPLOAD_ERR_PARTIAL]]), - 'attr_err_tmp' => $this->createTestFiles([['error' => UPLOAD_ERR_NO_TMP_DIR]]), - 'attr_err_write' => $this->createTestFiles([['error' => UPLOAD_ERR_CANT_WRITE]]), - 'attr_err_ext' => $this->createTestFiles([['error' => UPLOAD_ERR_EXTENSION]]), - ] - ); - } - - public function testValidateAttributeErrPartial() - { - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_part'); - $this->assertTrue($m->hasErrors('attr_err_part')); - $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_part'))); - } - - public function testValidateAttributeErrCantWrite() - { - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_write'); - $this->assertTrue($m->hasErrors('attr_err_write')); - $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_write'))); - } - - public function testValidateAttributeErrExtension() - { - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_ext'); - $this->assertTrue($m->hasErrors('attr_err_ext')); - $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_ext'))); - } - - public function testValidateAttributeErrNoTmpDir() - { - $m = $this->createModelForAttributeTest(); - $val = new FileValidator(); - $val->validateAttribute($m, 'attr_err_tmp'); - $this->assertTrue($m->hasErrors('attr_err_tmp')); - $this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_tmp'))); - } -} diff --git a/tests/unit/framework/validators/FilterValidatorTest.php b/tests/unit/framework/validators/FilterValidatorTest.php deleted file mode 100644 index 1b77047..0000000 --- a/tests/unit/framework/validators/FilterValidatorTest.php +++ /dev/null @@ -1,66 +0,0 @@ -mockApplication(); - } - - public function testAssureExceptionOnInit() - { - $this->setExpectedException('yii\base\InvalidConfigException'); - new FilterValidator(); - } - - public function testValidateAttribute() - { - $m = FakedValidationModel::createWithAttributes([ - 'attr_one' => ' to be trimmed ', - 'attr_two' => 'set this to null', - 'attr_empty1' => '', - 'attr_empty2' => null, - 'attr_array' => ['Maria', 'Anna', 'Elizabeth'], - 'attr_array_skipped' => ['John', 'Bill'] - ]); - $val = new FilterValidator(['filter' => 'trim']); - $val->validateAttribute($m, 'attr_one'); - $this->assertSame('to be trimmed', $m->attr_one); - $val->filter = function ($value) { - return null; - }; - $val->validateAttribute($m, 'attr_two'); - $this->assertNull($m->attr_two); - $val->filter = [$this, 'notToBeNull']; - $val->validateAttribute($m, 'attr_empty1'); - $this->assertSame($this->notToBeNull(''), $m->attr_empty1); - $val->skipOnEmpty = true; - $val->validateAttribute($m, 'attr_empty2'); - $this->assertNotNull($m->attr_empty2); - $val->filter = function($value) { - - return implode(',', $value); - }; - $val->skipOnArray = false; - $val->validateAttribute($m, 'attr_array'); - $this->assertSame('Maria,Anna,Elizabeth', $m->attr_array); - $val->skipOnArray = true; - $val->validateAttribute($m, 'attr_array_skipped'); - $this->assertSame(['John', 'Bill'], $m->attr_array_skipped); - } - - public function notToBeNull($value) - { - return 'not null'; - } -} diff --git a/tests/unit/framework/validators/NumberValidatorTest.php b/tests/unit/framework/validators/NumberValidatorTest.php deleted file mode 100644 index 47bb1bb..0000000 --- a/tests/unit/framework/validators/NumberValidatorTest.php +++ /dev/null @@ -1,211 +0,0 @@ -mockApplication(); - } - - public function testEnsureMessageOnInit() - { - $val = new NumberValidator; - $this->assertTrue(is_string($val->message)); - $this->assertTrue(is_null($val->max)); - $val = new NumberValidator(['min' => -1, 'max' => 20, 'integerOnly' => true]); - $this->assertTrue(is_string($val->message)); - $this->assertTrue(is_string($val->tooSmall)); - $this->assertTrue(is_string($val->tooBig)); - } - - public function testValidateValueSimple() - { - $val = new NumberValidator(); - $this->assertTrue($val->validate(20)); - $this->assertTrue($val->validate(0)); - $this->assertTrue($val->validate(-20)); - $this->assertTrue($val->validate('20')); - $this->assertTrue($val->validate(25.45)); - $this->assertFalse($val->validate('25,45')); - $this->assertFalse($val->validate('12:45')); - $val = new NumberValidator(['integerOnly' => true]); - $this->assertTrue($val->validate(20)); - $this->assertTrue($val->validate(0)); - $this->assertFalse($val->validate(25.45)); - $this->assertTrue($val->validate('20')); - $this->assertFalse($val->validate('25,45')); - $this->assertTrue($val->validate('020')); - $this->assertTrue($val->validate(0x14)); - $this->assertFalse($val->validate('0x14')); // todo check this - } - - public function testValidateValueAdvanced() - { - $val = new NumberValidator(); - $this->assertTrue($val->validate('-1.23')); // signed float - $this->assertTrue($val->validate('-4.423e-12')); // signed float + exponent - $this->assertTrue($val->validate('12E3')); // integer + exponent - $this->assertFalse($val->validate('e12')); // just exponent - $this->assertFalse($val->validate('-e3')); - $this->assertFalse($val->validate('-4.534-e-12')); // 'signed' exponent - $this->assertFalse($val->validate('12.23^4')); // expression instead of value - $val = new NumberValidator(['integerOnly' => true]); - $this->assertFalse($val->validate('-1.23')); - $this->assertFalse($val->validate('-4.423e-12')); - $this->assertFalse($val->validate('12E3')); - $this->assertFalse($val->validate('e12')); - $this->assertFalse($val->validate('-e3')); - $this->assertFalse($val->validate('-4.534-e-12')); - $this->assertFalse($val->validate('12.23^4')); - } - - public function testValidateValueMin() - { - $val = new NumberValidator(['min' => 1]); - $this->assertTrue($val->validate(1)); - $this->assertFalse($val->validate(-1)); - $this->assertFalse($val->validate('22e-12')); - $this->assertTrue($val->validate(PHP_INT_MAX + 1)); - $val = new NumberValidator(['min' => 1], ['integerOnly' => true]); - $this->assertTrue($val->validate(1)); - $this->assertFalse($val->validate(-1)); - $this->assertFalse($val->validate('22e-12')); - $this->assertTrue($val->validate(PHP_INT_MAX + 1)); - } - - public function testValidateValueMax() - { - $val = new NumberValidator(['max' => 1.25]); - $this->assertTrue($val->validate(1)); - $this->assertFalse($val->validate(1.5)); - $this->assertTrue($val->validate('22e-12')); - $this->assertTrue($val->validate('125e-2')); - $val = new NumberValidator(['max' => 1.25, 'integerOnly' => true]); - $this->assertTrue($val->validate(1)); - $this->assertFalse($val->validate(1.5)); - $this->assertFalse($val->validate('22e-12')); - $this->assertFalse($val->validate('125e-2')); - } - - public function testValidateValueRange() - { - $val = new NumberValidator(['min' => -10, 'max' => 20]); - $this->assertTrue($val->validate(0)); - $this->assertTrue($val->validate(-10)); - $this->assertFalse($val->validate(-11)); - $this->assertFalse($val->validate(21)); - $val = new NumberValidator(['min' => -10, 'max' => 20, 'integerOnly' => true]); - $this->assertTrue($val->validate(0)); - $this->assertFalse($val->validate(-11)); - $this->assertFalse($val->validate(22)); - $this->assertFalse($val->validate('20e-1')); - } - - public function testValidateAttribute() - { - $val = new NumberValidator(); - $model = new FakedValidationModel(); - $model->attr_number = '5.5e1'; - $val->validateAttribute($model, 'attr_number'); - $this->assertFalse($model->hasErrors('attr_number')); - $model->attr_number = '43^32'; //expression - $val->validateAttribute($model, 'attr_number'); - $this->assertTrue($model->hasErrors('attr_number')); - $val = new NumberValidator(['min' => 10]); - $model = new FakedValidationModel(); - $model->attr_number = 10; - $val->validateAttribute($model, 'attr_number'); - $this->assertFalse($model->hasErrors('attr_number')); - $model->attr_number = 5; - $val->validateAttribute($model, 'attr_number'); - $this->assertTrue($model->hasErrors('attr_number')); - $val = new NumberValidator(['max' => 10]); - $model = new FakedValidationModel(); - $model->attr_number = 10; - $val->validateAttribute($model, 'attr_number'); - $this->assertFalse($model->hasErrors('attr_number')); - $model->attr_number = 15; - $val->validateAttribute($model, 'attr_number'); - $this->assertTrue($model->hasErrors('attr_number')); - $val = new NumberValidator(['max' => 10, 'integerOnly' => true]); - $model = new FakedValidationModel(); - $model->attr_number = 10; - $val->validateAttribute($model, 'attr_number'); - $this->assertFalse($model->hasErrors('attr_number')); - $model->attr_number = 3.43; - $val->validateAttribute($model, 'attr_number'); - $this->assertTrue($model->hasErrors('attr_number')); - $val = new NumberValidator(['min' => 1]); - $model = FakedValidationModel::createWithAttributes(['attr_num' => [1, 2, 3]]); - $val->validateAttribute($model, 'attr_num'); - $this->assertTrue($model->hasErrors('attr_num')); - } - - public function testEnsureCustomMessageIsSetOnValidateAttribute() - { - $val = new NumberValidator([ - 'tooSmall' => '{attribute} is to small.', - 'min' => 5 - ]); - $model = new FakedValidationModel(); - $model->attr_number = 0; - $val->validateAttribute($model, 'attr_number'); - $this->assertTrue($model->hasErrors('attr_number')); - $this->assertEquals(1, count($model->getErrors('attr_number'))); - $msgs = $model->getErrors('attr_number'); - $this->assertSame('attr_number is to small.', $msgs[0]); - } - - /** - * https://github.com/yiisoft/yii2/issues/3118 - */ - public function testClientValidateComparison() - { - $val = new NumberValidator([ - 'min' => 5, - 'max' => 10, - ]); - $model = new FakedValidationModel(); - $js = $val->clientValidateAttribute($model, 'attr_number', new View(['assetBundles' => ['yii\validators\ValidationAsset' => true]])); - $this->assertContains('"min":5', $js); - $this->assertContains('"max":10', $js); - - $val = new NumberValidator([ - 'min' => '5', - 'max' => '10', - ]); - $model = new FakedValidationModel(); - $js = $val->clientValidateAttribute($model, 'attr_number', new View(['assetBundles' => ['yii\validators\ValidationAsset' => true]])); - $this->assertContains('"min":5', $js); - $this->assertContains('"max":10', $js); - - $val = new NumberValidator([ - 'min' => 5.65, - 'max' => 13.37, - ]); - $model = new FakedValidationModel(); - $js = $val->clientValidateAttribute($model, 'attr_number', new View(['assetBundles' => ['yii\validators\ValidationAsset' => true]])); - $this->assertContains('"min":5.65', $js); - $this->assertContains('"max":13.37', $js); - - $val = new NumberValidator([ - 'min' => '5.65', - 'max' => '13.37', - ]); - $model = new FakedValidationModel(); - $js = $val->clientValidateAttribute($model, 'attr_number', new View(['assetBundles' => ['yii\validators\ValidationAsset' => true]])); - $this->assertContains('"min":5.65', $js); - $this->assertContains('"max":13.37', $js); - } -} diff --git a/tests/unit/framework/validators/RangeValidatorTest.php b/tests/unit/framework/validators/RangeValidatorTest.php deleted file mode 100644 index b4cbf32..0000000 --- a/tests/unit/framework/validators/RangeValidatorTest.php +++ /dev/null @@ -1,108 +0,0 @@ -mockApplication(); - } - - public function testInitException() - { - $this->setExpectedException('yii\base\InvalidConfigException', 'The "range" property must be set.'); - new RangeValidator(['range' => 'not an array']); - } - - public function testAssureMessageSetOnInit() - { - $val = new RangeValidator(['range' => []]); - $this->assertTrue(is_string($val->message)); - } - - public function testValidateValue() - { - $val = new RangeValidator(['range' => range(1, 10, 1)]); - $this->assertTrue($val->validate(1)); - $this->assertFalse($val->validate(0)); - $this->assertFalse($val->validate(11)); - $this->assertFalse($val->validate(5.5)); - $this->assertTrue($val->validate(10)); - $this->assertTrue($val->validate("10")); - $this->assertTrue($val->validate("5")); - } - - public function testValidateValueEmpty() - { - $val = new RangeValidator(['range' => range(10, 20, 1), 'skipOnEmpty' => false]); - $this->assertFalse($val->validate(null)); //row RangeValidatorTest.php:101 - $this->assertFalse($val->validate('0')); - $this->assertFalse($val->validate(0)); - $this->assertFalse($val->validate('')); - $val->allowArray = true; - $this->assertTrue($val->validate([])); - } - - public function testValidateArrayValue() - { - $val = new RangeValidator(['range' => range(1, 10, 1)]); - $val->allowArray = true; - $this->assertTrue($val->validate([1, 2, 3, 4, 5])); - $this->assertTrue($val->validate([6, 7, 8, 9, 10])); - $this->assertFalse($val->validate([0, 1, 2])); - $this->assertFalse($val->validate([10, 11, 12])); - $this->assertTrue($val->validate(["1", "2", "3", 4, 5, 6])); - } - - public function testValidateValueStrict() - { - $val = new RangeValidator(['range' => range(1, 10, 1), 'strict' => true]); - $this->assertTrue($val->validate(1)); - $this->assertTrue($val->validate(5)); - $this->assertTrue($val->validate(10)); - $this->assertFalse($val->validate("1")); - $this->assertFalse($val->validate("10")); - $this->assertFalse($val->validate("5.5")); - } - - public function testValidateArrayValueStrict() - { - $val = new RangeValidator(['range' => range(1, 10, 1), 'strict' => true]); - $val->allowArray = true; - $this->assertFalse($val->validate(["1", "2", "3", "4", "5", "6"])); - $this->assertFalse($val->validate(["1", "2", "3", 4, 5, 6])); - } - - public function testValidateValueNot() - { - $val = new RangeValidator(['range' => range(1, 10, 1), 'not' => true]); - $this->assertFalse($val->validate(1)); - $this->assertTrue($val->validate(0)); - $this->assertTrue($val->validate(11)); - $this->assertTrue($val->validate(5.5)); - $this->assertFalse($val->validate(10)); - $this->assertFalse($val->validate("10")); - $this->assertFalse($val->validate("5")); - } - - public function testValidateAttribute() - { - $val = new RangeValidator(['range' => range(1, 10, 1)]); - $m = FakedValidationModel::createWithAttributes(['attr_r1' => 5, 'attr_r2' => 999]); - $val->validateAttribute($m, 'attr_r1'); - $this->assertFalse($m->hasErrors()); - $val->validateAttribute($m, 'attr_r2'); - $this->assertTrue($m->hasErrors('attr_r2')); - $err = $m->getErrors('attr_r2'); - $this->assertTrue(stripos($err[0], 'attr_r2') !== false); - } -} diff --git a/tests/unit/framework/validators/RegularExpressionValidatorTest.php b/tests/unit/framework/validators/RegularExpressionValidatorTest.php deleted file mode 100644 index e9c3ce7..0000000 --- a/tests/unit/framework/validators/RegularExpressionValidatorTest.php +++ /dev/null @@ -1,55 +0,0 @@ -mockApplication(); - } - - public function testValidateValue() - { - $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); - $this->assertTrue($val->validate('b.4')); - $this->assertFalse($val->validate('b./')); - $this->assertFalse($val->validate(['a', 'b'])); - $val->not = true; - $this->assertFalse($val->validate('b.4')); - $this->assertTrue($val->validate('b./')); - $this->assertFalse($val->validate(['a', 'b'])); - } - - public function testValidateAttribute() - { - $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); - $m = FakedValidationModel::createWithAttributes(['attr_reg1' => 'b.4']); - $val->validateAttribute($m, 'attr_reg1'); - $this->assertFalse($m->hasErrors('attr_reg1')); - $m->attr_reg1 = 'b./'; - $val->validateAttribute($m, 'attr_reg1'); - $this->assertTrue($m->hasErrors('attr_reg1')); - } - - public function testMessageSetOnInit() - { - $val = new RegularExpressionValidator(['pattern' => '/^[a-zA-Z0-9](\.)?([^\/]*)$/m']); - $this->assertTrue(is_string($val->message)); - } - - public function testInitException() - { - $this->setExpectedException('yii\base\InvalidConfigException'); - $val = new RegularExpressionValidator(); - $val->validate('abc'); - } -} diff --git a/tests/unit/framework/validators/RequiredValidatorTest.php b/tests/unit/framework/validators/RequiredValidatorTest.php deleted file mode 100644 index ce62773..0000000 --- a/tests/unit/framework/validators/RequiredValidatorTest.php +++ /dev/null @@ -1,62 +0,0 @@ -mockApplication(); - } - - public function testValidateValueWithDefaults() - { - $val = new RequiredValidator(); - $this->assertFalse($val->validate(null)); - $this->assertFalse($val->validate([])); - $this->assertTrue($val->validate('not empty')); - $this->assertTrue($val->validate(['with', 'elements'])); - } - - public function testValidateValueWithValue() - { - $val = new RequiredValidator(['requiredValue' => 55]); - $this->assertTrue($val->validate(55)); - $this->assertTrue($val->validate("55")); - $this->assertTrue($val->validate("0x37")); - $this->assertFalse($val->validate("should fail")); - $this->assertTrue($val->validate(true)); - $val->strict = true; - $this->assertTrue($val->validate(55)); - $this->assertFalse($val->validate("55")); - $this->assertFalse($val->validate("0x37")); - $this->assertFalse($val->validate("should fail")); - $this->assertFalse($val->validate(true)); - } - - public function testValidateAttribute() - { - // empty req-value - $val = new RequiredValidator(); - $m = FakedValidationModel::createWithAttributes(['attr_val' => null]); - $val->validateAttribute($m, 'attr_val'); - $this->assertTrue($m->hasErrors('attr_val')); - $this->assertTrue(stripos(current($m->getErrors('attr_val')), 'blank') !== false); - $val = new RequiredValidator(['requiredValue' => 55]); - $m = FakedValidationModel::createWithAttributes(['attr_val' => 56]); - $val->validateAttribute($m, 'attr_val'); - $this->assertTrue($m->hasErrors('attr_val')); - $this->assertTrue(stripos(current($m->getErrors('attr_val')), 'must be') !== false); - $val = new RequiredValidator(['requiredValue' => 55]); - $m = FakedValidationModel::createWithAttributes(['attr_val' => 55]); - $val->validateAttribute($m, 'attr_val'); - $this->assertFalse($m->hasErrors('attr_val')); - } -} diff --git a/tests/unit/framework/validators/StringValidatorTest.php b/tests/unit/framework/validators/StringValidatorTest.php deleted file mode 100644 index 3f6100f..0000000 --- a/tests/unit/framework/validators/StringValidatorTest.php +++ /dev/null @@ -1,118 +0,0 @@ -mockApplication(); - } - - public function testValidateValue() - { - $val = new StringValidator(); - $this->assertFalse($val->validate(['not a string'])); - $this->assertTrue($val->validate('Just some string')); - } - - public function testValidateValueLength() - { - $val = new StringValidator(['length' => 25]); - $this->assertTrue($val->validate(str_repeat('x', 25))); - $this->assertTrue($val->validate(str_repeat('€', 25))); - $this->assertFalse($val->validate(str_repeat('x', 125))); - $this->assertFalse($val->validate('')); - $val = new StringValidator(['length' => [25]]); - $this->assertTrue($val->validate(str_repeat('x', 25))); - $this->assertTrue($val->validate(str_repeat('x', 1250))); - $this->assertFalse($val->validate(str_repeat('Ä', 24))); - $this->assertFalse($val->validate('')); - $val = new StringValidator(['length' => [10, 20]]); - $this->assertTrue($val->validate(str_repeat('x', 15))); - $this->assertTrue($val->validate(str_repeat('x', 10))); - $this->assertTrue($val->validate(str_repeat('x', 20))); - $this->assertFalse($val->validate(str_repeat('x', 5))); - $this->assertFalse($val->validate(str_repeat('x', 25))); - $this->assertFalse($val->validate('')); - // make sure min/max are overridden - $val = new StringValidator(['length' => [10, 20], 'min' => 25, 'max' => 35]); - $this->assertTrue($val->validate(str_repeat('x', 15))); - $this->assertFalse($val->validate(str_repeat('x', 30))); - } - - public function testValidateValueMinMax() - { - $val = new StringValidator(['min' => 10]); - $this->assertTrue($val->validate(str_repeat('x', 10))); - $this->assertFalse($val->validate('xxxx')); - $val = new StringValidator(['max' => 10]); - $this->assertTrue($val->validate('xxxx')); - $this->assertFalse($val->validate(str_repeat('y', 20))); - $val = new StringValidator(['min' => 10, 'max' => 20]); - $this->assertTrue($val->validate(str_repeat('y', 15))); - $this->assertFalse($val->validate('abc')); - $this->assertFalse($val->validate(str_repeat('b', 25))); - } - - public function testValidateAttribute() - { - $val = new StringValidator(); - $model = new FakedValidationModel(); - $model->attr_string = 'a tet string'; - $val->validateAttribute($model, 'attr_string'); - $this->assertFalse($model->hasErrors()); - $val = new StringValidator(['length' => 20]); - $model = new FakedValidationModel(); - $model->attr_string = str_repeat('x', 20); - $val->validateAttribute($model, 'attr_string'); - $this->assertFalse($model->hasErrors()); - $model = new FakedValidationModel(); - $model->attr_string = 'abc'; - $val->validateAttribute($model, 'attr_string'); - $this->assertTrue($model->hasErrors('attr_string')); - $val = new StringValidator(['max' => 2]); - $model = new FakedValidationModel(); - $model->attr_string = 'a'; - $val->validateAttribute($model, 'attr_string'); - $this->assertFalse($model->hasErrors()); - $model = new FakedValidationModel(); - $model->attr_string = 'abc'; - $val->validateAttribute($model, 'attr_string'); - $this->assertTrue($model->hasErrors('attr_string')); - $val = new StringValidator(['max' => 1]); - $model = FakedValidationModel::createWithAttributes(['attr_str' => ['abc']]); - $val->validateAttribute($model, 'attr_str'); - $this->assertTrue($model->hasErrors('attr_str')); - } - - public function testEnsureMessagesOnInit() - { - $val = new StringValidator(['min' => 1, 'max' => 2]); - $this->assertTrue(is_string($val->message)); - $this->assertTrue(is_string($val->tooLong)); - $this->assertTrue(is_string($val->tooShort)); - } - - public function testCustomErrorMessageInValidateAttribute() - { - $val = new StringValidator([ - 'min' => 5, - 'tooShort' => '{attribute} to short. Min is {min}', - ]); - $model = new FakedValidationModel(); - $model->attr_string = 'abc'; - $val->validateAttribute($model, 'attr_string'); - $this->assertTrue($model->hasErrors('attr_string')); - $errorMsg = $model->getErrors('attr_string'); - $this->assertEquals('attr_string to short. Min is 5', $errorMsg[0]); - } -} diff --git a/tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php b/tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php deleted file mode 100644 index d892193..0000000 --- a/tests/unit/framework/validators/UniqueValidatorDriverTests/UniqueValidatorPostgresTest.php +++ /dev/null @@ -1,13 +0,0 @@ -mockApplication(); - ActiveRecord::$db = $this->getConnection(); - } - - public function testAssureMessageSetOnInit() - { - $val = new UniqueValidator(); - $this->assertTrue(is_string($val->message)); - } - - public function testValidateAttributeDefault() - { - $val = new UniqueValidator(); - $m = ValidatorTestMainModel::find()->one(); - $val->validateAttribute($m, 'id'); - $this->assertFalse($m->hasErrors('id')); - $m = ValidatorTestRefModel::findOne(1); - $val->validateAttribute($m, 'ref'); - $this->assertTrue($m->hasErrors('ref')); - // new record: - $m = new ValidatorTestRefModel(); - $m->ref = 5; - $val->validateAttribute($m, 'ref'); - $this->assertTrue($m->hasErrors('ref')); - $m = new ValidatorTestRefModel(); - $m->id = 7; - $m->ref = 12121; - $val->validateAttribute($m, 'ref'); - $this->assertFalse($m->hasErrors('ref')); - $m->save(false); - $val->validateAttribute($m, 'ref'); - $this->assertFalse($m->hasErrors('ref')); - // array error - $m = FakedValidationModel::createWithAttributes(['attr_arr' => ['a', 'b']]); - $val->validateAttribute($m, 'attr_arr'); - $this->assertTrue($m->hasErrors('attr_arr')); - } - - public function testValidateAttributeOfNonARModel() - { - $val = new UniqueValidator(['targetClass' => ValidatorTestRefModel::className(), 'targetAttribute' => 'ref']); - $m = FakedValidationModel::createWithAttributes(['attr_1' => 5, 'attr_2' => 1313]); - $val->validateAttribute($m, 'attr_1'); - $this->assertTrue($m->hasErrors('attr_1')); - $val->validateAttribute($m, 'attr_2'); - $this->assertFalse($m->hasErrors('attr_2')); - } - - public function testValidateNonDatabaseAttribute() - { - $val = new UniqueValidator(['targetClass' => ValidatorTestRefModel::className(), 'targetAttribute' => 'ref']); - $m = ValidatorTestMainModel::findOne(1); - $val->validateAttribute($m, 'testMainVal'); - $this->assertFalse($m->hasErrors('testMainVal')); - $m = ValidatorTestMainModel::findOne(1); - $m->testMainVal = 4; - $val->validateAttribute($m, 'testMainVal'); - $this->assertTrue($m->hasErrors('testMainVal')); - } - - public function testValidateAttributeAttributeNotInTableException() - { - $this->setExpectedException('yii\db\Exception'); - $val = new UniqueValidator(); - $m = new ValidatorTestMainModel(); - $val->validateAttribute($m, 'testMainVal'); - } - - public function testValidateCompositeKeys() - { - $val = new UniqueValidator([ - 'targetClass' => OrderItem::className(), - 'targetAttribute' => ['order_id', 'item_id'], - ]); - // validate old record - $m = OrderItem::findOne(['order_id' => 1, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertFalse($m->hasErrors('order_id')); - $m->item_id = 1; - $val->validateAttribute($m, 'order_id'); - $this->assertTrue($m->hasErrors('order_id')); - - // validate new record - $m = new OrderItem(['order_id' => 1, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertTrue($m->hasErrors('order_id')); - $m = new OrderItem(['order_id' => 10, 'item_id' => 2]); - $val->validateAttribute($m, 'order_id'); - $this->assertFalse($m->hasErrors('order_id')); - - $val = new UniqueValidator([ - 'targetClass' => OrderItem::className(), - 'targetAttribute' => ['id' => 'order_id'], - ]); - // validate old record - $m = Order::findOne(1); - $val->validateAttribute($m, 'id'); - $this->assertTrue($m->hasErrors('id')); - $m = Order::findOne(1); - $m->id = 2; - $val->validateAttribute($m, 'id'); - $this->assertTrue($m->hasErrors('id')); - $m = Order::findOne(1); - $m->id = 10; - $val->validateAttribute($m, 'id'); - $this->assertFalse($m->hasErrors('id')); - - $m = new Order(['id' => 1]); - $val->validateAttribute($m, 'id'); - $this->assertTrue($m->hasErrors('id')); - $m = new Order(['id' => 10]); - $val->validateAttribute($m, 'id'); - $this->assertFalse($m->hasErrors('id')); - } -} diff --git a/tests/unit/framework/validators/UrlValidatorTest.php b/tests/unit/framework/validators/UrlValidatorTest.php deleted file mode 100644 index 5ae66c9..0000000 --- a/tests/unit/framework/validators/UrlValidatorTest.php +++ /dev/null @@ -1,103 +0,0 @@ -mockApplication(); - } - - public function testValidateValue() - { - $val = new UrlValidator; - $this->assertFalse($val->validate('google.de')); - $this->assertTrue($val->validate('http://google.de')); - $this->assertTrue($val->validate('https://google.de')); - $this->assertFalse($val->validate('htp://yiiframework.com')); - $this->assertTrue($val->validate('https://www.google.de/search?q=yii+framework&ie=utf-8&oe=utf-8' - .'&rls=org.mozilla:de:official&client=firefox-a&gws_rd=cr')); - $this->assertFalse($val->validate('ftp://ftp.ruhr-uni-bochum.de/')); - $this->assertFalse($val->validate('http://invalid,domain')); - $this->assertFalse($val->validate('http://äüö?=!"§$%&/()=}][{³²€.edu')); - } - - public function testValidateValueWithDefaultScheme() - { - $val = new UrlValidator(['defaultScheme' => 'https']); - $this->assertTrue($val->validate('yiiframework.com')); - $this->assertTrue($val->validate('http://yiiframework.com')); - } - - public function testValidateValueWithoutScheme() - { - $val = new UrlValidator(['pattern' => '/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)/i']); - $this->assertTrue($val->validate('yiiframework.com')); - } - - public function testValidateWithCustomScheme() - { - $val = new UrlValidator([ - 'validSchemes' => ['http', 'https', 'ftp', 'ftps'], - 'defaultScheme' => 'http', - ]); - $this->assertTrue($val->validate('ftp://ftp.ruhr-uni-bochum.de/')); - $this->assertTrue($val->validate('google.de')); - $this->assertTrue($val->validate('http://google.de')); - $this->assertTrue($val->validate('https://google.de')); - $this->assertFalse($val->validate('htp://yiiframework.com')); - // relative urls not supported - $this->assertFalse($val->validate('//yiiframework.com')); - } - - public function testValidateWithIdn() - { - if (!function_exists('idn_to_ascii')) { - $this->markTestSkipped('intl package required'); - - return; - } - $val = new UrlValidator([ - 'enableIDN' => true, - ]); - $this->assertTrue($val->validate('http://äüößìà.de')); - // converted via http://mct.verisign-grs.com/convertServlet - $this->assertTrue($val->validate('http://xn--zcack7ayc9a.de')); - } - - public function testValidateLength() - { - $url = 'http://' . str_pad('base', 2000, 'url') . '.de'; - $val = new UrlValidator; - $this->assertFalse($val->validate($url)); - } - - public function testValidateAttributeAndError() - { - $obj = new FakedValidationModel; - $obj->attr_url = 'http://google.de'; - $val = new UrlValidator; - $val->validateAttribute($obj, 'attr_url'); - $this->assertFalse($obj->hasErrors('attr_url')); - $this->assertSame('http://google.de', $obj->attr_url); - $obj = new FakedValidationModel; - $val->defaultScheme = 'http'; - $obj->attr_url = 'google.de'; - $val->validateAttribute($obj, 'attr_url'); - $this->assertFalse($obj->hasErrors('attr_url')); - $this->assertTrue(stripos($obj->attr_url, 'http') !== false); - $obj = new FakedValidationModel; - $obj->attr_url = 'gttp;/invalid string'; - $val->validateAttribute($obj, 'attr_url'); - $this->assertTrue($obj->hasErrors('attr_url')); - } -} diff --git a/tests/unit/framework/validators/ValidatorTest.php b/tests/unit/framework/validators/ValidatorTest.php deleted file mode 100644 index b5ae88a..0000000 --- a/tests/unit/framework/validators/ValidatorTest.php +++ /dev/null @@ -1,228 +0,0 @@ -mockApplication(); - } - - protected function getTestModel($additionalAttributes = []) - { - $attributes = array_merge( - ['attr_runMe1' => true, 'attr_runMe2' => true, 'attr_skip' => true], - $additionalAttributes - ); - - return FakedValidationModel::createWithAttributes($attributes); - } - - public function testCreateValidator() - { - $model = FakedValidationModel::createWithAttributes(['attr_test1' => 'abc', 'attr_test2' => '2013']); - /* @var $numberVal NumberValidator */ - $numberVal = TestValidator::createValidator('number', $model, ['attr_test1']); - $this->assertInstanceOf(NumberValidator::className(), $numberVal); - $numberVal = TestValidator::createValidator('integer', $model, ['attr_test2']); - $this->assertInstanceOf(NumberValidator::className(), $numberVal); - $this->assertTrue($numberVal->integerOnly); - $val = TestValidator::createValidator( - 'boolean', - $model, - ['attr_test1', 'attr_test2'], - ['on' => ['a', 'b']] - ); - $this->assertInstanceOf(BooleanValidator::className(), $val); - $this->assertSame(['a', 'b'], $val->on); - $this->assertSame(['attr_test1', 'attr_test2'], $val->attributes); - $val = TestValidator::createValidator( - 'boolean', - $model, - ['attr_test1', 'attr_test2'], - ['on' => ['a', 'b'], 'except' => ['c', 'd', 'e']] - ); - $this->assertInstanceOf(BooleanValidator::className(), $val); - $this->assertSame(['a', 'b'], $val->on); - $this->assertSame(['c', 'd', 'e'], $val->except); - $val = TestValidator::createValidator('inlineVal', $model, ['val_attr_a'], ['params' => ['foo' => 'bar']]); - $this->assertInstanceOf(InlineValidator::className(), $val); - $this->assertSame('inlineVal', $val->method); - $this->assertSame(['foo' => 'bar'], $val->params); - } - - public function testValidate() - { - $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2']]); - $model = $this->getTestModel(); - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertTrue($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - } - - public function testValidateWithAttributeIntersect() - { - $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2']]); - $model = $this->getTestModel(); - $val->validateAttributes($model, ['attr_runMe1']); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertFalse($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - } - - public function testValidateWithEmptyAttributes() - { - $val = new TestValidator(); - $model = $this->getTestModel(); - $val->validateAttributes($model, ['attr_runMe1']); - $this->assertFalse($val->isAttributeValidated('attr_runMe1')); - $this->assertFalse($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - $val->validateAttributes($model); - $this->assertFalse($val->isAttributeValidated('attr_runMe1')); - $this->assertFalse($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - } - - public function testValidateWithError() - { - $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2'], 'skipOnError' => false]); - $model = $this->getTestModel(); - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertTrue($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe2')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); - $val->validateAttributes($model, ['attr_runMe2']); - $this->assertEquals(2, $val->countAttributeValidations('attr_runMe2')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); - $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); - $val = new TestValidator(['attributes' => ['attr_runMe1', 'attr_runMe2'], 'skipOnError' => true]); - $model = $this->getTestModel(); - $val->enableErrorOnValidateAttribute(); - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertTrue($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_skip')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); - $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); - $val->validateAttributes($model, ['attr_runMe2']); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe2')); - $this->assertEquals(1, $val->countAttributeValidations('attr_runMe1')); - $this->assertEquals(0, $val->countAttributeValidations('attr_skip')); - } - - public function testValidateWithEmpty() - { - $val = new TestValidator([ - 'attributes' => [ - 'attr_runMe1', - 'attr_runMe2', - 'attr_empty1', - 'attr_empty2' - ], - 'skipOnEmpty' => true, - ]); - $model = $this->getTestModel(['attr_empty1' => '', 'attr_emtpy2' => ' ']); - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertTrue($val->isAttributeValidated('attr_runMe2')); - $this->assertFalse($val->isAttributeValidated('attr_empty1')); - $this->assertFalse($val->isAttributeValidated('attr_empty2')); - $model->attr_empty1 = 'not empty anymore'; - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_empty1')); - $this->assertFalse($val->isAttributeValidated('attr_empty2')); - $val = new TestValidator([ - 'attributes' => [ - 'attr_runMe1', - 'attr_runMe2', - 'attr_empty1', - 'attr_empty2' - ], - 'skipOnEmpty' => false, - ]); - $model = $this->getTestModel(['attr_empty1' => '', 'attr_emtpy2' => ' ']); - $val->validateAttributes($model); - $this->assertTrue($val->isAttributeValidated('attr_runMe1')); - $this->assertTrue($val->isAttributeValidated('attr_runMe2')); - $this->assertTrue($val->isAttributeValidated('attr_empty1')); - $this->assertTrue($val->isAttributeValidated('attr_empty2')); - } - - public function testIsEmpty() - { - $val = new TestValidator(); - $this->assertTrue($val->isEmpty(null)); - $this->assertTrue($val->isEmpty([])); - $this->assertTrue($val->isEmpty('')); - $this->assertFalse($val->isEmpty(5)); - $this->assertFalse($val->isEmpty(0)); - $this->assertFalse($val->isEmpty(new \stdClass())); - $this->assertFalse($val->isEmpty(' ')); - } - - public function testValidateValue() - { - $this->setExpectedException( - 'yii\base\NotSupportedException', - TestValidator::className() . ' does not support validateValue().' - ); - $val = new TestValidator(); - $val->validate('abc'); - } - - public function testClientValidateAttribute() - { - $val = new TestValidator(); - $this->assertNull( - $val->clientValidateAttribute($this->getTestModel(), 'attr_runMe1', []) - ); //todo pass a view instead of array - } - - public function testIsActive() - { - $val = new TestValidator(); - $this->assertTrue($val->isActive('scenA')); - $this->assertTrue($val->isActive('scenB')); - $val->except = ['scenB']; - $this->assertTrue($val->isActive('scenA')); - $this->assertFalse($val->isActive('scenB')); - $val->on = ['scenC']; - $this->assertFalse($val->isActive('scenA')); - $this->assertFalse($val->isActive('scenB')); - $this->assertTrue($val->isActive('scenC')); - } - - public function testAddError() - { - $val = new TestValidator(); - $m = $this->getTestModel(['attr_msg_val' => 'abc']); - $val->addError($m, 'attr_msg_val', '{attribute}::{value}'); - $errors = $m->getErrors('attr_msg_val'); - $this->assertEquals('attr_msg_val::abc', $errors[0]); - $m = $this->getTestModel(['attr_msg_val' => ['bcc']]); - $val->addError($m, 'attr_msg_val', '{attribute}::{value}'); - $errors = $m->getErrors('attr_msg_val'); - $this->assertEquals('attr_msg_val::array()', $errors[0]); - $m = $this->getTestModel(['attr_msg_val' => 'abc']); - $val->addError($m, 'attr_msg_val', '{attribute}::{value}::{param}', ['param' => 'param_value']); - $errors = $m->getErrors('attr_msg_val'); - $this->assertEquals('attr_msg_val::abc::param_value', $errors[0]); - } -} diff --git a/tests/unit/framework/web/AssetBundleTest.php b/tests/unit/framework/web/AssetBundleTest.php deleted file mode 100644 index 2f67ebe..0000000 --- a/tests/unit/framework/web/AssetBundleTest.php +++ /dev/null @@ -1,273 +0,0 @@ - - */ - -namespace yiiunit\framework\web; - -use Yii; -use yii\web\View; -use yii\web\AssetBundle; -use yii\web\AssetManager; - -/** - * @group web - */ -class AssetBundleTest extends \yiiunit\TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - - Yii::setAlias('@testWeb', '/'); - Yii::setAlias('@testWebRoot', '@yiiunit/data/web'); - } - - protected function getView() - { - $view = new View(); - $view->setAssetManager(new AssetManager([ - 'basePath' => '@testWebRoot/assets', - 'baseUrl' => '@testWeb/assets', - ])); - - return $view; - } - - public function testRegister() - { - $view = $this->getView(); - - $this->assertEmpty($view->assetBundles); - TestSimpleAsset::register($view); - $this->assertEquals(1, count($view->assetBundles)); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestSimpleAsset', $view->assetBundles); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestSimpleAsset'] instanceof AssetBundle); - - $expected = <<4 -EOF; - $this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); - } - - public function testSimpleDependency() - { - $view = $this->getView(); - - $this->assertEmpty($view->assetBundles); - TestAssetBundle::register($view); - $this->assertEquals(3, count($view->assetBundles)); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetLevel3', $view->assetBundles); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3'] instanceof AssetBundle); - - $expected = <<23 -4 -EOF; - $this->assertEqualsWithoutLE($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); - } - - public function positionProvider() - { - return [ - [View::POS_HEAD, true], - [View::POS_HEAD, false], - [View::POS_BEGIN, true], - [View::POS_BEGIN, false], - [View::POS_END, true], - [View::POS_END, false], - ]; - } - - /** - * @dataProvider positionProvider - */ - public function testPositionDependency($pos, $jqAlreadyRegistered) - { - $view = $this->getView(); - - $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestAssetBundle'] = [ - 'jsOptions' => [ - 'position' => $pos, - ], - ]; - - $this->assertEmpty($view->assetBundles); - if ($jqAlreadyRegistered) { - TestJqueryAsset::register($view); - } - TestAssetBundle::register($view); - $this->assertEquals(3, count($view->assetBundles)); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetLevel3', $view->assetBundles); - - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3'] instanceof AssetBundle); - - $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions); - $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions['position']); - $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions); - $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions['position']); - $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3']->jsOptions); - $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3']->jsOptions['position']); - - switch ($pos) { - case View::POS_HEAD: - $expected = << - -234 -EOF; - break; - case View::POS_BEGIN: - $expected = <<2 -34 -EOF; - break; - default: - case View::POS_END: - $expected = <<23 -4 -EOF; - break; - } - $this->assertEqualsWithoutLE($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); - } - - public function positionProvider2() - { - return [ - [View::POS_BEGIN, true], - [View::POS_BEGIN, false], - [View::POS_END, true], - [View::POS_END, false], - ]; - } - - /** - * @dataProvider positionProvider - */ - public function testPositionDependencyConflict($pos, $jqAlreadyRegistered) - { - $view = $this->getView(); - - $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestAssetBundle'] = [ - 'jsOptions' => [ - 'position' => $pos - 1, - ], - ]; - $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestJqueryAsset'] = [ - 'jsOptions' => [ - 'position' => $pos, - ], - ]; - - $this->assertEmpty($view->assetBundles); - if ($jqAlreadyRegistered) { - TestJqueryAsset::register($view); - } - $this->setExpectedException('yii\\base\\InvalidConfigException'); - TestAssetBundle::register($view); - } - - public function testCircularDependency() - { - $this->setExpectedException('yii\\base\\InvalidConfigException'); - TestAssetCircleA::register($this->getView()); - } - - public function testDuplicateAssetFile() - { - $view = $this->getView(); - - $this->assertEmpty($view->assetBundles); - TestSimpleAsset::register($view); - $this->assertEquals(1, count($view->assetBundles)); - $this->assertArrayHasKey('yiiunit\\framework\\web\\TestSimpleAsset', $view->assetBundles); - $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestSimpleAsset'] instanceof AssetBundle); - // register TestJqueryAsset which also has the jquery.js - TestJqueryAsset::register($view); - - $expected = <<4 -EOF; - $this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php')); - } -} - -class TestSimpleAsset extends AssetBundle -{ - public $basePath = '@testWebRoot/js'; - public $baseUrl = '@testWeb/js'; - public $js = [ - 'jquery.js', - ]; -} - -class TestAssetBundle extends AssetBundle -{ - public $basePath = '@testWebRoot/files'; - public $baseUrl = '@testWeb/files'; - public $css = [ - 'cssFile.css', - ]; - public $js = [ - 'jsFile.js', - ]; - public $depends = [ - 'yiiunit\\framework\\web\\TestJqueryAsset' - ]; -} - -class TestJqueryAsset extends AssetBundle -{ - public $basePath = '@testWebRoot/js'; - public $baseUrl = '@testWeb/js'; - public $js = [ - 'jquery.js', - ]; - public $depends = [ - 'yiiunit\\framework\\web\\TestAssetLevel3' - ]; -} - -class TestAssetLevel3 extends AssetBundle -{ - public $basePath = '@testWebRoot/js'; - public $baseUrl = '@testWeb/js'; -} - -class TestAssetCircleA extends AssetBundle -{ - public $basePath = '@testWebRoot/js'; - public $baseUrl = '@testWeb/js'; - public $js = [ - 'jquery.js', - ]; - public $depends = [ - 'yiiunit\\framework\\web\\TestAssetCircleB' - ]; -} - -class TestAssetCircleB extends AssetBundle -{ - public $basePath = '@testWebRoot/js'; - public $baseUrl = '@testWeb/js'; - public $js = [ - 'jquery.js', - ]; - public $depends = [ - 'yiiunit\\framework\\web\\TestAssetCircleA' - ]; -} diff --git a/tests/unit/framework/web/AssetConverterTest.php b/tests/unit/framework/web/AssetConverterTest.php deleted file mode 100644 index 15f699f..0000000 --- a/tests/unit/framework/web/AssetConverterTest.php +++ /dev/null @@ -1,87 +0,0 @@ - - */ - -namespace yiiunit\framework\web; - -use yii\helpers\FileHelper; -use yii\web\AssetConverter; - -/** - * @group web - */ -class AssetConverterTest extends \yiiunit\TestCase -{ - /** - * @var string temporary files path - */ - protected $tmpPath; - - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - $this->tmpPath = \Yii::$app->runtimePath . '/assetConverterTest_' . getmypid(); - if (!is_dir($this->tmpPath)) { - mkdir($this->tmpPath, 0777, true); - } - } - - protected function tearDown() - { - if (is_dir($this->tmpPath)) { - FileHelper::removeDirectory($this->tmpPath); - } - parent::tearDown(); - } - - // Tests : - - public function testConvert() - { - $tmpPath = $this->tmpPath; - file_put_contents($tmpPath . '/test.php', <<commands['php'] = ['txt', 'php {from} > {to}']; - $this->assertEquals('test.txt', $converter->convert('test.php', $tmpPath)); - - $this->assertTrue(file_exists($tmpPath . '/test.txt'), 'Failed asserting that asset output file exists.'); - $this->assertEquals("Hello World!\nHello Yii!", file_get_contents($tmpPath . '/test.txt')); - } - - /** - * @depends testConvert - */ - public function testForceConvert() - { - $tmpPath = $this->tmpPath; - file_put_contents($tmpPath . '/test.php', <<commands['php'] = ['txt', 'php {from} > {to}']; - - $converter->convert('test.php', $tmpPath); - $initialConvertTime = file_get_contents($tmpPath . '/test.txt'); - - usleep(1); - $converter->convert('test.php', $tmpPath); - $this->assertEquals($initialConvertTime, file_get_contents($tmpPath . '/test.txt')); - - $converter->forceConvert = true; - $converter->convert('test.php', $tmpPath); - $this->assertNotEquals($initialConvertTime, file_get_contents($tmpPath . '/test.txt')); - } -} diff --git a/tests/unit/framework/web/CacheSessionTest.php b/tests/unit/framework/web/CacheSessionTest.php deleted file mode 100644 index c81e01a..0000000 --- a/tests/unit/framework/web/CacheSessionTest.php +++ /dev/null @@ -1,36 +0,0 @@ -mockApplication(); - Yii::$app->set('cache', new FileCache()); - } - - public function testCacheSession() - { - $session = new CacheSession(); - - $session->writeSession('test', 'sessionData'); - $this->assertEquals('sessionData', $session->readSession('test')); - $session->destroySession('test'); - $this->assertEquals('', $session->readSession('test')); - } - - public function testInvalidCache() - { - $this->setExpectedException('\Exception'); - new CacheSession(['cache' => 'invalid']); - } -} diff --git a/tests/unit/framework/web/FormatterTest.php b/tests/unit/framework/web/FormatterTest.php deleted file mode 100644 index 1c99879..0000000 --- a/tests/unit/framework/web/FormatterTest.php +++ /dev/null @@ -1,77 +0,0 @@ -mockApplication(); - $this->response = new Response; - $this->formatter = $this->getFormatterInstance(); - } - - /** - * @return ResponseFormatterInterface - */ - abstract protected function getFormatterInstance(); - - /** - * Formatter should not format null - */ - public function testFormatNull() - { - $this->response->data = null; - $this->formatter->format($this->response); - $this->assertEquals(null, $this->response->content); - } - - /** - * @param mixed $data the data to be formatted - * @param string $json the expected JSON body - * @dataProvider formatScalarDataProvider - */ - public function testFormatScalar($data, $json) - { - $this->response->data = $data; - $this->formatter->format($this->response); - $this->assertEquals($json, $this->response->content); - } - - /** - * @param mixed $data the data to be formatted - * @param string $json the expected JSON body - * @dataProvider formatArrayDataProvider - */ - public function testFormatArrays($data, $json) - { - $this->response->data = $data; - $this->formatter->format($this->response); - $this->assertEquals($json, $this->response->content); - } - - /** - * @param mixed $data the data to be formatted - * @param string $json the expected JSON body - * @dataProvider formatObjectDataProvider - */ - public function testFormatObjects($data, $json) - { - $this->response->data = $data; - $this->formatter->format($this->response); - $this->assertEquals($json, $this->response->content); - } -} \ No newline at end of file diff --git a/tests/unit/framework/web/GroupUrlRuleTest.php b/tests/unit/framework/web/GroupUrlRuleTest.php deleted file mode 100644 index 29482d4..0000000 --- a/tests/unit/framework/web/GroupUrlRuleTest.php +++ /dev/null @@ -1,216 +0,0 @@ -mockApplication(); - } - - public function testCreateUrl() - { - $manager = new UrlManager(['cache' => null]); - $suites = $this->getTestsForCreateUrl(); - foreach ($suites as $i => $suite) { - list ($name, $config, $tests) = $suite; - $rule = new GroupUrlRule($config); - foreach ($tests as $j => $test) { - list ($route, $params, $expected) = $test; - $url = $rule->createUrl($manager, $route, $params); - $this->assertEquals($expected, $url, "Test#$i-$j: $name"); - } - } - } - - public function testParseRequest() - { - $manager = new UrlManager(['cache' => null]); - $request = new Request(['hostInfo' => 'http://en.example.com']); - $suites = $this->getTestsForParseRequest(); - foreach ($suites as $i => $suite) { - list ($name, $config, $tests) = $suite; - $rule = new GroupUrlRule($config); - foreach ($tests as $j => $test) { - $request->pathInfo = $test[0]; - $route = $test[1]; - $params = isset($test[2]) ? $test[2] : []; - $result = $rule->parseRequest($manager, $request); - if ($route === false) { - $this->assertFalse($result, "Test#$i-$j: $name"); - } else { - $this->assertEquals([$route, $params], $result, "Test#$i-$j: $name"); - } - } - } - } - - protected function getTestsForCreateUrl() - { - // structure of each test - // message for the test - // config for the URL rule - // list of inputs and outputs - // route - // params - // expected output - return [ - [ - 'no prefix', - [ - 'rules' => [ - 'login' => 'user/login', - 'logout' => 'user/logout', - ], - ], - [ - ['user/login', [], 'login'], - ['user/logout', [], 'logout'], - ['user/create', [], false], - ], - ], - [ - 'prefix only', - [ - 'prefix' => 'admin', - 'rules' => [ - 'login' => 'user/login', - 'logout' => 'user/logout', - ], - ], - [ - ['admin/user/login', [], 'admin/login'], - ['admin/user/logout', [], 'admin/logout'], - ['user/create', [], false], - ], - ], - [ - 'prefix and routePrefix different', - [ - 'prefix' => '_', - 'routePrefix' => 'admin', - 'rules' => [ - 'login' => 'user/login', - 'logout' => 'user/logout', - ], - ], - [ - ['admin/user/login', [], '_/login'], - ['admin/user/logout', [], '_/logout'], - ['user/create', [], false], - ], - ], - [ - 'ruleConfig with suffix', - [ - 'prefix' => '_', - 'routePrefix' => 'admin', - 'ruleConfig' => [ - 'suffix' => '.html', - 'class' => 'yii\\web\\UrlRule' - ], - 'rules' => [ - 'login' => 'user/login', - 'logout' => 'user/logout', - ], - ], - [ - ['admin/user/login', [], '_/login.html'], - ['admin/user/logout', [], '_/logout.html'], - ['user/create', [], false], - ], - ], - ]; - } - - protected function getTestsForParseRequest() - { - // structure of each test - // message for the test - // config for the URL rule - // list of inputs and outputs - // pathInfo - // expected route, or false if the rule doesn't apply - // expected params, or not set if empty - return [ - [ - 'no prefix', - [ - 'rules' => [ - 'login' => 'user/login', - 'logout' => 'user/logout', - ], - ], - [ - ['login', 'user/login'], - ['logout', 'user/logout'], - ['create', false], - ], - ], - [ - 'prefix only', - [ - 'prefix' => 'admin', - 'rules' => [ - 'login' => 'user/login', - 'logout' => 'user/logout', - ], - ], - [ - ['admin/login', 'admin/user/login'], - ['admin/logout', 'admin/user/logout'], - ['admin/create', false], - ['create', false], - ], - ], - [ - 'prefix and routePrefix different', - [ - 'prefix' => '_', - 'routePrefix' => 'admin', - 'rules' => [ - 'login' => 'user/login', - 'logout' => 'user/logout', - ], - ], - [ - ['_/login', 'admin/user/login'], - ['_/logout', 'admin/user/logout'], - ['_/create', false], - ['create', false], - ], - ], - [ - 'ruleConfig with suffix', - [ - 'prefix' => '_', - 'routePrefix' => 'admin', - 'ruleConfig' => [ - 'suffix' => '.html', - 'class' => 'yii\\web\\UrlRule' - ], - 'rules' => [ - 'login' => 'user/login', - 'logout' => 'user/logout', - ], - ], - [ - ['_/login.html', 'admin/user/login'], - ['_/logout.html', 'admin/user/logout'], - ['_/logout', false], - ['_/create.html', false], - ], - ], - ]; - } -} diff --git a/tests/unit/framework/web/JsonResponseFormatterTest.php b/tests/unit/framework/web/JsonResponseFormatterTest.php deleted file mode 100644 index ca49f48..0000000 --- a/tests/unit/framework/web/JsonResponseFormatterTest.php +++ /dev/null @@ -1,76 +0,0 @@ - - * @since 2.0.3 - * - * @group web - */ -class JsonResponseFormatterTest extends FormatterTest -{ - /** - * @return JsonResponseFormatter - */ - protected function getFormatterInstance() - { - return new JsonResponseFormatter(); - } - - public function formatScalarDataProvider() - { - return [ - [1, 1], - ['abc', '"abc"'], - [true, 'true'], - ["<>", '"<>"'], - ]; - } - - public function formatArrayDataProvider() - { - return [ - [[], "[]"], - [[1, 'abc'], '[1,"abc"]'], - [[ - 'a' => 1, - 'b' => 'abc', - ], '{"a":1,"b":"abc"}'], - [[ - 1, - 'abc', - [2, 'def'], - true, - ], '[1,"abc",[2,"def"],true]'], - [[ - 'a' => 1, - 'b' => 'abc', - 'c' => [2, '<>'], - true, - ], '{"a":1,"b":"abc","c":[2,"<>"],"0":true}'], - ]; - } - - public function formatObjectDataProvider() - { - return [ - [new Post(123, 'abc'), '{"id":123,"title":"abc"}'], - [[ - new Post(123, 'abc'), - new Post(456, 'def'), - ], '[{"id":123,"title":"abc"},{"id":456,"title":"def"}]'], - [[ - new Post(123, '<>'), - 'a' => new Post(456, 'def'), - ], '{"0":{"id":123,"title":"<>"},"a":{"id":456,"title":"def"}}'], - ]; - } -} diff --git a/tests/unit/framework/web/Post.php b/tests/unit/framework/web/Post.php deleted file mode 100644 index d6ebc68..0000000 --- a/tests/unit/framework/web/Post.php +++ /dev/null @@ -1,16 +0,0 @@ -id = $id; - $this->title = $title; - } -} \ No newline at end of file diff --git a/tests/unit/framework/web/RequestTest.php b/tests/unit/framework/web/RequestTest.php deleted file mode 100644 index 2d276f9..0000000 --- a/tests/unit/framework/web/RequestTest.php +++ /dev/null @@ -1,81 +0,0 @@ -assertEquals([], $request->parseAcceptHeader(' ')); - - $this->assertEquals([ - 'audio/basic' => ['q' => 1], - 'audio/*' => ['q' => 0.2], - ], $request->parseAcceptHeader('audio/*; q=0.2, audio/basic')); - - $this->assertEquals([ - 'application/json' => ['q' => 1, 'version' => '1.0'], - 'application/xml' => ['q' => 1, 'version' => '2.0', 'x'], - 'text/x-c' => ['q' => 1], - 'text/x-dvi' => ['q' => 0.8], - 'text/plain' => ['q' => 0.5], - ], $request->parseAcceptHeader('text/plain; q=0.5, - application/json; version=1.0, - application/xml; version=2.0; x, - text/x-dvi; q=0.8, text/x-c')); - } - - public function testPrefferedLanguage() - { - $this->mockApplication([ - 'language' => 'en', - ]); - - $request = new Request(); - $request->acceptableLanguages = []; - $this->assertEquals('en', $request->getPreferredLanguage()); - - $request = new Request(); - $request->acceptableLanguages = ['de']; - $this->assertEquals('en', $request->getPreferredLanguage()); - - $request = new Request(); - $request->acceptableLanguages = ['en-us', 'de', 'ru-RU']; - $this->assertEquals('en', $request->getPreferredLanguage(['en'])); - - $request = new Request(); - $request->acceptableLanguages = ['en-us', 'de', 'ru-RU']; - $this->assertEquals('de', $request->getPreferredLanguage(['ru', 'de'])); - $this->assertEquals('de-DE', $request->getPreferredLanguage(['ru', 'de-DE'])); - - $request = new Request(); - $request->acceptableLanguages = ['en-us', 'de', 'ru-RU']; - $this->assertEquals('de', $request->getPreferredLanguage(['de', 'ru'])); - - $request = new Request(); - $request->acceptableLanguages = ['en-us', 'de', 'ru-RU']; - $this->assertEquals('ru-ru', $request->getPreferredLanguage(['ru-ru'])); - - $request = new Request(); - $request->acceptableLanguages = ['en-us', 'de']; - $this->assertEquals('ru-ru', $request->getPreferredLanguage(['ru-ru', 'pl'])); - $this->assertEquals('ru-RU', $request->getPreferredLanguage(['ru-RU', 'pl'])); - - $request = new Request(); - $request->acceptableLanguages = ['en-us', 'de']; - $this->assertEquals('pl', $request->getPreferredLanguage(['pl', 'ru-ru'])); - } -} diff --git a/tests/unit/framework/web/ResponseTest.php b/tests/unit/framework/web/ResponseTest.php deleted file mode 100644 index 8a9c22d..0000000 --- a/tests/unit/framework/web/ResponseTest.php +++ /dev/null @@ -1,104 +0,0 @@ -mockApplication(); - $this->response = new \yii\web\Response; - } - - public function rightRanges() - { - // TODO test more cases for range requests and check for rfc compatibility - // http://www.w3.org/Protocols/rfc2616/rfc2616.txt - return [ - ['0-5', '0-5', 6, '12ёж'], - ['2-', '2-66', 65, 'ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?'], - ['-12', '55-66', 12, '(ёжик)=?'], - ]; - } - - /** - * @dataProvider rightRanges - */ - public function testSendFileRanges($rangeHeader, $expectedHeader, $length, $expectedContent) - { - $dataFile = \Yii::getAlias('@yiiunit/data/web/data.txt'); - $fullContent = file_get_contents($dataFile); - $_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader; - ob_start(); - $this->response->sendFile($dataFile)->send( ); - $content = ob_get_clean(); - - $this->assertEquals($expectedContent, $content); - $this->assertEquals(206, $this->response->statusCode); - $headers = $this->response->headers; - $this->assertEquals("bytes", $headers->get('Accept-Ranges')); - $this->assertEquals("bytes " . $expectedHeader . '/' . StringHelper::byteLength($fullContent), $headers->get('Content-Range')); - $this->assertEquals('text/plain', $headers->get('Content-Type')); - $this->assertEquals("$length", $headers->get('Content-Length')); - } - - public function wrongRanges() - { - // TODO test more cases for range requests and check for rfc compatibility - // http://www.w3.org/Protocols/rfc2616/rfc2616.txt - return [ - ['1-2,3-5,6-10'], // multiple range request not supported - ['5-1'], // last-byte-pos value is less than its first-byte-pos value - ['-100000'], // last-byte-pos bigger then content length - ['10000-'], // first-byte-pos bigger then content length - ]; - } - - /** - * @dataProvider wrongRanges - */ - public function testSendFileWrongRanges($rangeHeader) - { - $this->setExpectedException('yii\web\HttpException'); - - $dataFile = \Yii::getAlias('@yiiunit/data/web/data.txt'); - $_SERVER['HTTP_RANGE'] = 'bytes=' . $rangeHeader; - $this->response->sendFile($dataFile); - } - - protected function generateTestFileContent() - { - return '12ёжик3456798áèabcdefghijklmnopqrstuvwxyz!"§$%&/(ёжик)=?'; - } - - /** - * https://github.com/yiisoft/yii2/issues/7529 - */ - public function testSendContentAsFile() - { - ob_start(); - $this->response->sendContentAsFile('test', 'test.txt')->send([ - 'mimeType' => 'text/plain' - ]); - $content = ob_get_clean(); - - static::assertEquals('test', $content); - static::assertEquals(200, $this->response->statusCode); - $headers = $this->response->headers; - static::assertEquals('application/octet-stream', $headers->get('Content-Type')); - static::assertEquals('attachment; filename="test.txt"', $headers->get('Content-Disposition')); - static::assertEquals(4, $headers->get('Content-Length')); - } -} diff --git a/tests/unit/framework/web/UrlManagerTest.php b/tests/unit/framework/web/UrlManagerTest.php deleted file mode 100644 index 4a2097d..0000000 --- a/tests/unit/framework/web/UrlManagerTest.php +++ /dev/null @@ -1,372 +0,0 @@ -mockApplication(); - } - - public function testCreateUrl() - { - // default setting with '/' as base url - $manager = new UrlManager([ - 'baseUrl' => '/', - 'scriptUrl' => '', - 'cache' => null, - ]); - $url = $manager->createUrl(['post/view']); - $this->assertEquals('?r=post%2Fview', $url); - $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); - $this->assertEquals('?r=post%2Fview&id=1&title=sample+post', $url); - - // default setting with '/test/' as base url - $manager = new UrlManager([ - 'baseUrl' => '/test/', - 'scriptUrl' => '/test', - 'cache' => null, - ]); - $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); - $this->assertEquals('/test?r=post%2Fview&id=1&title=sample+post', $url); - - // pretty URL without rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'baseUrl' => '/', - 'scriptUrl' => '', - 'cache' => null, - ]); - $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); - $this->assertEquals('/post/view?id=1&title=sample+post', $url); - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'baseUrl' => '/test/', - 'scriptUrl' => '/test', - 'cache' => null, - ]); - $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); - $this->assertEquals('/test/post/view?id=1&title=sample+post', $url); - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'baseUrl' => '/test', - 'scriptUrl' => '/test/index.php', - 'cache' => null, - ]); - $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); - $this->assertEquals('/test/index.php/post/view?id=1&title=sample+post', $url); - - // todo: test showScriptName - - // pretty URL with rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post//', - 'route' => 'post/view', - ], - ], - 'baseUrl' => '/', - 'scriptUrl' => '', - ]); - $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); - $this->assertEquals('/post/1/sample+post', $url); - $url = $manager->createUrl(['post/index', 'page' => 1]); - $this->assertEquals('/post/index?page=1', $url); - - // rules with defaultAction - $url = $manager->createUrl(['/post', 'page' => 1]); - $this->assertEquals('/post?page=1', $url); - - // pretty URL with rules and suffix - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post/<id>/<title>', - 'route' => 'post/view', - ], - ], - 'baseUrl' => '/', - 'scriptUrl' => '', - 'suffix' => '.html', - ]); - $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post']); - $this->assertEquals('/post/1/sample+post.html', $url); - $url = $manager->createUrl(['post/index', 'page' => 1]); - $this->assertEquals('/post/index.html?page=1', $url); - - // pretty URL with rules that have host info - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post/<id>/<title>', - 'route' => 'post/view', - 'host' => 'http://<lang:en|fr>.example.com', - ], - ], - 'baseUrl' => '/test', - 'scriptUrl' => '/test', - ]); - $url = $manager->createUrl(['post/view', 'id' => 1, 'title' => 'sample post', 'lang' => 'en']); - $this->assertEquals('http://en.example.com/test/post/1/sample+post', $url); - $url = $manager->createUrl(['post/index', 'page' => 1]); - $this->assertEquals('/test/post/index?page=1', $url); - } - - /** - * https://github.com/yiisoft/yii2/issues/6717 - */ - public function testCreateUrlWithEmptyPattern() - { - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - 'rules' => [ - '' => 'front/site/index', - ], - 'baseUrl' => '/', - 'scriptUrl' => '', - ]); - $url = $manager->createUrl(['front/site/index']); - $this->assertEquals('/', $url); - $url = $manager->createUrl(['/front/site/index']); - $this->assertEquals('/', $url); - $url = $manager->createUrl(['front/site/index', 'page' => 1]); - $this->assertEquals('/?page=1', $url); - $url = $manager->createUrl(['/front/site/index', 'page' => 1]); - $this->assertEquals('/?page=1', $url); - - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - 'rules' => [ - '' => '/front/site/index', - ], - 'baseUrl' => '/', - 'scriptUrl' => '', - ]); - $url = $manager->createUrl(['front/site/index']); - $this->assertEquals('/', $url); - $url = $manager->createUrl(['/front/site/index']); - $this->assertEquals('/', $url); - $url = $manager->createUrl(['front/site/index', 'page' => 1]); - $this->assertEquals('/?page=1', $url); - $url = $manager->createUrl(['/front/site/index', 'page' => 1]); - $this->assertEquals('/?page=1', $url); - } - - public function testCreateAbsoluteUrl() - { - $manager = new UrlManager([ - 'baseUrl' => '/', - 'scriptUrl' => '', - 'hostInfo' => 'http://www.example.com', - 'cache' => null, - ]); - $url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post']); - $this->assertEquals('http://www.example.com?r=post%2Fview&id=1&title=sample+post', $url); - - $url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post'], 'https'); - $this->assertEquals('https://www.example.com?r=post%2Fview&id=1&title=sample+post', $url); - - $manager->hostInfo = 'https://www.example.com'; - $url = $manager->createAbsoluteUrl(['post/view', 'id' => 1, 'title' => 'sample post'], 'http'); - $this->assertEquals('http://www.example.com?r=post%2Fview&id=1&title=sample+post', $url); - } - - public function testParseRequest() - { - $manager = new UrlManager(['cache' => null]); - $request = new Request; - - // default setting without 'r' param - unset($_GET['r']); - $result = $manager->parseRequest($request); - $this->assertEquals(['', []], $result); - - // default setting with 'r' param - $_GET['r'] = 'site/index'; - $result = $manager->parseRequest($request); - $this->assertEquals(['site/index', []], $result); - - // default setting with 'r' param as an array - $_GET['r'] = ['site/index']; - $result = $manager->parseRequest($request); - $this->assertEquals(['', []], $result); - - // pretty URL without rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - ]); - // empty pathinfo - $request->pathInfo = ''; - $result = $manager->parseRequest($request); - $this->assertEquals(['', []], $result); - // normal pathinfo - $request->pathInfo = 'site/index'; - $result = $manager->parseRequest($request); - $this->assertEquals(['site/index', []], $result); - // pathinfo with module - $request->pathInfo = 'module/site/index'; - $result = $manager->parseRequest($request); - $this->assertEquals(['module/site/index', []], $result); - // pathinfo with trailing slashes - $request->pathInfo = '/module/site/index/'; - $result = $manager->parseRequest($request); - $this->assertEquals(['module/site/index/', []], $result); - - // pretty URL rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post/<id>/<title>', - 'route' => 'post/view', - ], - ], - ]); - // matching pathinfo - $request->pathInfo = 'post/123/this+is+sample'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); - // trailing slash is significant - $request->pathInfo = 'post/123/this+is+sample/'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/123/this+is+sample/', []], $result); - // empty pathinfo - $request->pathInfo = ''; - $result = $manager->parseRequest($request); - $this->assertEquals(['', []], $result); - // normal pathinfo - $request->pathInfo = 'site/index'; - $result = $manager->parseRequest($request); - $this->assertEquals(['site/index', []], $result); - // pathinfo with module - $request->pathInfo = 'module/site/index'; - $result = $manager->parseRequest($request); - $this->assertEquals(['module/site/index', []], $result); - - // pretty URL rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'suffix' => '.html', - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post/<id>/<title>', - 'route' => 'post/view', - ], - ], - ]); - // matching pathinfo - $request->pathInfo = 'post/123/this+is+sample.html'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); - // matching pathinfo without suffix - $request->pathInfo = 'post/123/this+is+sample'; - $result = $manager->parseRequest($request); - $this->assertFalse($result); - // empty pathinfo - $request->pathInfo = ''; - $result = $manager->parseRequest($request); - $this->assertEquals(['', []], $result); - // normal pathinfo - $request->pathInfo = 'site/index.html'; - $result = $manager->parseRequest($request); - $this->assertEquals(['site/index', []], $result); - // pathinfo without suffix - $request->pathInfo = 'site/index'; - $result = $manager->parseRequest($request); - $this->assertFalse($result); - - // strict parsing - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'enableStrictParsing' => true, - 'suffix' => '.html', - 'cache' => null, - 'rules' => [ - [ - 'pattern' => 'post/<id>/<title>', - 'route' => 'post/view', - ], - ], - ]); - // matching pathinfo - $request->pathInfo = 'post/123/this+is+sample.html'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); - // unmatching pathinfo - $request->pathInfo = 'site/index.html'; - $result = $manager->parseRequest($request); - $this->assertFalse($result); - } - - public function testParseRESTRequest() - { - $request = new Request; - - // pretty URL rules - $manager = new UrlManager([ - 'enablePrettyUrl' => true, - 'showScriptName' => false, - 'cache' => null, - 'rules' => [ - 'PUT,POST post/<id>/<title>' => 'post/create', - 'DELETE post/<id>' => 'post/delete', - 'post/<id>/<title>' => 'post/view', - 'POST/GET' => 'post/get', - ], - ]); - // matching pathinfo GET request - $_SERVER['REQUEST_METHOD'] = 'GET'; - $request->pathInfo = 'post/123/this+is+sample'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/view', ['id' => '123', 'title' => 'this+is+sample']], $result); - // matching pathinfo PUT/POST request - $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request->pathInfo = 'post/123/this+is+sample'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/create', ['id' => '123', 'title' => 'this+is+sample']], $result); - $_SERVER['REQUEST_METHOD'] = 'POST'; - $request->pathInfo = 'post/123/this+is+sample'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/create', ['id' => '123', 'title' => 'this+is+sample']], $result); - - // no wrong matching - $_SERVER['REQUEST_METHOD'] = 'POST'; - $request->pathInfo = 'POST/GET'; - $result = $manager->parseRequest($request); - $this->assertEquals(['post/get', []], $result); - - // createUrl should ignore REST rules - $this->mockApplication([ - 'components' => [ - 'request' => [ - 'hostInfo' => 'http://localhost/', - 'baseUrl' => '/app' - ] - ] - ], \yii\web\Application::className()); - $this->assertEquals('/app/post/delete?id=123', $manager->createUrl(['post/delete', 'id' => 123])); - $this->destroyApplication(); - - unset($_SERVER['REQUEST_METHOD']); - } -} diff --git a/tests/unit/framework/web/UrlRuleTest.php b/tests/unit/framework/web/UrlRuleTest.php deleted file mode 100644 index a376437..0000000 --- a/tests/unit/framework/web/UrlRuleTest.php +++ /dev/null @@ -1,710 +0,0 @@ -<?php - -namespace yiiunit\framework\web; - -use yii\web\UrlManager; -use yii\web\UrlRule; -use yii\web\Request; -use yiiunit\TestCase; - -/** - * @group web - */ -class UrlRuleTest extends TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - public function testCreateUrl() - { - $manager = new UrlManager(['cache' => null]); - $suites = $this->getTestsForCreateUrl(); - foreach ($suites as $i => $suite) { - list ($name, $config, $tests) = $suite; - $rule = new UrlRule($config); - foreach ($tests as $j => $test) { - list ($route, $params, $expected) = $test; - $url = $rule->createUrl($manager, $route, $params); - $this->assertEquals($expected, $url, "Test#$i-$j: $name"); - } - } - } - - public function testParseRequest() - { - $manager = new UrlManager(['cache' => null]); - $request = new Request(['hostInfo' => 'http://en.example.com']); - $suites = $this->getTestsForParseRequest(); - foreach ($suites as $i => $suite) { - list ($name, $config, $tests) = $suite; - $rule = new UrlRule($config); - foreach ($tests as $j => $test) { - $request->pathInfo = $test[0]; - $route = $test[1]; - $params = isset($test[2]) ? $test[2] : []; - $result = $rule->parseRequest($manager, $request); - if ($route === false) { - $this->assertFalse($result, "Test#$i-$j: $name"); - } else { - $this->assertEquals([$route, $params], $result, "Test#$i-$j: $name"); - } - } - } - } - - protected function getTestsForCreateUrl() - { - // structure of each test - // message for the test - // config for the URL rule - // list of inputs and outputs - // route - // params - // expected output - return [ - [ - 'empty pattern', - [ - 'pattern' => '', - 'route' => 'post/index', - ], - [ - ['post/index', [], ''], - ['comment/index', [], false], - ['post/index', ['page' => 1], '?page=1'], - ], - ], - [ - 'without param', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - ], - [ - ['post/index', [], 'posts'], - ['comment/index', [], false], - ['post/index', ['page' => 1], 'posts?page=1'], - ], - ], - [ - 'parsing only', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'mode' => UrlRule::PARSING_ONLY, - ], - [ - ['post/index', [], false], - ], - ], - [ - 'with param', - [ - 'pattern' => 'post/<page>', - 'route' => 'post/index', - ], - [ - ['post/index', [], false], - ['comment/index', [], false], - ['post/index', ['page' => 1], 'post/1'], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/1?tag=a'], - ], - ], - [ - 'with param requirement', - [ - 'pattern' => 'post/<page:\d+>', - 'route' => 'post/index', - ], - [ - ['post/index', ['page' => 'abc'], false], - ['post/index', ['page' => 1], 'post/1'], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/1?tag=a'], - ], - ], - [ - 'with multiple params', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - ], - [ - ['post/index', ['page' => '1abc'], false], - ['post/index', ['page' => 1], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/1-a'], - ], - ], - [ - 'with optional param', - [ - 'pattern' => 'post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], - ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2/a'], - ], - ], - [ - 'with optional param not in pattern', - [ - 'pattern' => 'post/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 2, 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], - ], - ], - [ - 'multiple optional params', - [ - 'pattern' => 'post/<page:\d+>/<tag>/<sort:yes|no>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'sort' => 'yes'], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'YES'], false], - ['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'yes'], 'post/a'], - ['post/index', ['page' => 2, 'tag' => 'a', 'sort' => 'yes'], 'post/2/a'], - ['post/index', ['page' => 2, 'tag' => 'a', 'sort' => 'no'], 'post/2/a/no'], - ['post/index', ['page' => 1, 'tag' => 'a', 'sort' => 'no'], 'post/a/no'], - ], - ], - [ - 'optional param and required param separated by dashes', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/-a'], - ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2-a'], - ], - ], - [ - 'optional param at the end', - [ - 'pattern' => 'post/<tag>/<page:\d+>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/a'], - ['post/index', ['page' => 2, 'tag' => 'a'], 'post/a/2'], - ], - ], - [ - 'consecutive optional params', - [ - 'pattern' => 'post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'tag' => 'a'], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post'], - ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2'], - ['post/index', ['page' => 1, 'tag' => 'b'], 'post/b'], - ['post/index', ['page' => 2, 'tag' => 'b'], 'post/2/b'], - ], - ], - [ - 'consecutive optional params separated by dash', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'tag' => 'a'], - ], - [ - ['post/index', ['page' => 1], false], - ['post/index', ['page' => '1abc', 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a'], 'post/-'], - ['post/index', ['page' => 1, 'tag' => 'b'], 'post/-b'], - ['post/index', ['page' => 2, 'tag' => 'a'], 'post/2-'], - ['post/index', ['page' => 2, 'tag' => 'b'], 'post/2-b'], - ], - ], - [ - 'route has parameters', - [ - 'pattern' => '<controller>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => [], - ], - [ - ['post/index', ['page' => 1], 'post/index?page=1'], - ['module/post/index', [], false], - ], - ], - [ - 'route has parameters with regex', - [ - 'pattern' => '<controller:post|comment>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => [], - ], - [ - ['post/index', ['page' => 1], 'post/index?page=1'], - ['comment/index', ['page' => 1], 'comment/index?page=1'], - ['test/index', ['page' => 1], false], - ['post', [], false], - ['module/post/index', [], false], - ['post/index', ['controller' => 'comment'], 'post/index?controller=comment'], - ], - ], - [ - 'route has default parameter', - [ - 'pattern' => '<controller:post|comment>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => ['action' => 'index'], - ], - [ - ['post/view', ['page' => 1], 'post/view?page=1'], - ['comment/view', ['page' => 1], 'comment/view?page=1'], - ['test/view', ['page' => 1], false], - ['test/index', ['page' => 1], false], - ['post/index', ['page' => 1], 'post?page=1'], - ], - ], - [ - 'empty pattern with suffix', - [ - 'pattern' => '', - 'route' => 'post/index', - 'suffix' => '.html', - ], - [ - ['post/index', [], ''], - ['comment/index', [], false], - ['post/index', ['page' => 1], '?page=1'], - ], - ], - [ - 'regular pattern with suffix', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'suffix' => '.html', - ], - [ - ['post/index', [], 'posts.html'], - ['comment/index', [], false], - ['post/index', ['page' => 1], 'posts.html?page=1'], - ], - ], - [ - 'empty pattern with slash suffix', - [ - 'pattern' => '', - 'route' => 'post/index', - 'suffix' => '/', - ], - [ - ['post/index', [], ''], - ['comment/index', [], false], - ['post/index', ['page' => 1], '?page=1'], - ], - ], - [ - 'regular pattern with slash suffix', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'suffix' => '/', - ], - [ - ['post/index', [], 'posts/'], - ['comment/index', [], false], - ['post/index', ['page' => 1], 'posts/?page=1'], - ], - ], - [ - 'with host info', - [ - 'pattern' => 'post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - 'host' => 'http://<lang:en|fr>.example.com', - ], - [ - ['post/index', ['page' => 1, 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a', 'lang' => 'en'], 'http://en.example.com/post/a'], - ], - ], - [ - 'with host info in pattern', - [ - 'pattern' => 'http://<lang:en|fr>.example.com/post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/index', ['page' => 1, 'tag' => 'a'], false], - ['post/index', ['page' => 1, 'tag' => 'a', 'lang' => 'en'], 'http://en.example.com/post/a'], - ], - ], - [ - 'with unicode', - [ - 'pattern' => '/blog/search/<tag:[a-zA-Zа-яА-Я0-9\_\+\-]{1,255}>', - 'route' => 'blog/search', - ], - [ - ['blog/search', ['tag' => 'метра'], 'blog/search/%D0%BC%D0%B5%D1%82%D1%80%D0%B0'], - ], - ], - ]; - } - - protected function getTestsForParseRequest() - { - // structure of each test - // message for the test - // config for the URL rule - // list of inputs and outputs - // pathInfo - // expected route, or false if the rule doesn't apply - // expected params, or not set if empty - return [ - [ - 'empty pattern', - [ - 'pattern' => '', - 'route' => 'post/index', - ], - [ - ['', 'post/index'], - ['a', false], - ], - ], - [ - 'without param', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - ], - [ - ['posts', 'post/index'], - ['a', false], - ], - ], - [ - 'with dot', // https://github.com/yiisoft/yii/issues/2945 - [ - 'pattern' => 'posts.html', - 'route' => 'post/index', - ], - [ - ['posts.html', 'post/index'], - ['postsahtml', false], - ], - ], - [ - 'creation only', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'mode' => UrlRule::CREATION_ONLY, - ], - [ - ['posts', false], - ], - ], - [ - 'with param', - [ - 'pattern' => 'post/<page>', - 'route' => 'post/index', - ], - [ - ['post/1', 'post/index', ['page' => '1']], - ['post/a', 'post/index', ['page' => 'a']], - ['post', false], - ['posts', false], - ], - ], - [ - 'with param requirement', - [ - 'pattern' => 'post/<page:\d+>', - 'route' => 'post/index', - ], - [ - ['post/1', 'post/index', ['page' => '1']], - ['post/a', false], - ['post/1/a', false], - ], - ], - [ - 'with multiple params', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - ], - [ - ['post/1-a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/a', false], - ['post/1', false], - ['post/1/a', false], - ], - ], - [ - 'with optional param', - [ - 'pattern' => 'post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/1/a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/2/a', 'post/index', ['page' => '2', 'tag' => 'a']], - ['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/1', 'post/index', ['page' => '1', 'tag' => '1']], - ], - ], - [ - 'with optional param not in pattern', - [ - 'pattern' => 'post/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/1', 'post/index', ['page' => '1', 'tag' => '1']], - ['post', false], - ], - ], - [ - 'multiple optional params', - [ - 'pattern' => 'post/<page:\d+>/<tag>/<sort:yes|no>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'sort' => 'yes'], - ], - [ - ['post/1/a/yes', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'yes']], - ['post/1/a/no', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'no']], - ['post/2/a/no', 'post/index', ['page' => '2', 'tag' => 'a', 'sort' => 'no']], - ['post/2/a', 'post/index', ['page' => '2', 'tag' => 'a', 'sort' => 'yes']], - ['post/a/no', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'no']], - ['post/a', 'post/index', ['page' => '1', 'tag' => 'a', 'sort' => 'yes']], - ['post', false], - ], - ], - [ - 'optional param and required param separated by dashes', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/1-a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/2-a', 'post/index', ['page' => '2', 'tag' => 'a']], - ['post/-a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/a', false], - ['post-a', false], - ], - ], - [ - 'optional param at the end', - [ - 'pattern' => 'post/<tag>/<page:\d+>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['post/a/1', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/a/2', 'post/index', ['page' => '2', 'tag' => 'a']], - ['post/a', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/2', 'post/index', ['page' => '1', 'tag' => '2']], - ['post', false], - ], - ], - [ - 'consecutive optional params', - [ - 'pattern' => 'post/<page:\d+>/<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'tag' => 'a'], - ], - [ - ['post/2/b', 'post/index', ['page' => '2', 'tag' => 'b']], - ['post/2', 'post/index', ['page' => '2', 'tag' => 'a']], - ['post', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post/b', 'post/index', ['page' => '1', 'tag' => 'b']], - ['post//b', false], - ], - ], - [ - 'consecutive optional params separated by dash', - [ - 'pattern' => 'post/<page:\d+>-<tag>', - 'route' => 'post/index', - 'defaults' => ['page' => 1, 'tag' => 'a'], - ], - [ - ['post/2-b', 'post/index', ['page' => '2', 'tag' => 'b']], - ['post/2-', 'post/index', ['page' => '2', 'tag' => 'a']], - ['post/-b', 'post/index', ['page' => '1', 'tag' => 'b']], - ['post/-', 'post/index', ['page' => '1', 'tag' => 'a']], - ['post', false], - ], - ], - [ - 'route has parameters', - [ - 'pattern' => '<controller>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => [], - ], - [ - ['post/index', 'post/index'], - ['module/post/index', false], - ], - ], - [ - 'route has parameters with regex', - [ - 'pattern' => '<controller:post|comment>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => [], - ], - [ - ['post/index', 'post/index'], - ['comment/index', 'comment/index'], - ['test/index', false], - ['post', false], - ['module/post/index', false], - ], - ], - [ - 'route has default parameter', - [ - 'pattern' => '<controller:post|comment>/<action>', - 'route' => '<controller>/<action>', - 'defaults' => ['action' => 'index'], - ], - [ - ['post/view', 'post/view'], - ['comment/view', 'comment/view'], - ['test/view', false], - ['post', 'post/index'], - ['posts', false], - ['test', false], - ['index', false], - ], - ], - [ - 'empty pattern with suffix', - [ - 'pattern' => '', - 'route' => 'post/index', - 'suffix' => '.html', - ], - [ - ['', 'post/index'], - ['.html', false], - ['a.html', false], - ], - ], - [ - 'regular pattern with suffix', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'suffix' => '.html', - ], - [ - ['posts.html', 'post/index'], - ['posts', false], - ['posts.HTML', false], - ['a.html', false], - ['a', false], - ], - ], - [ - 'empty pattern with slash suffix', - [ - 'pattern' => '', - 'route' => 'post/index', - 'suffix' => '/', - ], - [ - ['', 'post/index'], - ['a', false], - ], - ], - [ - 'regular pattern with slash suffix', - [ - 'pattern' => 'posts', - 'route' => 'post/index', - 'suffix' => '/', - ], - [ - ['posts/', 'post/index'], - ['posts', false], - ['a', false], - ], - ], - [ - 'with host info', - [ - 'pattern' => 'post/<page:\d+>', - 'route' => 'post/index', - 'host' => 'http://<lang:en|fr>.example.com', - ], - [ - ['post/1', 'post/index', ['page' => '1', 'lang' => 'en']], - ['post/a', false], - ['post/1/a', false], - ], - ], - [ - 'with host info in pattern', - [ - 'pattern' => 'http://<lang:en|fr>.example.com/post/<page:\d+>', - 'route' => 'post/index', - ], - [ - ['post/1', 'post/index', ['page' => '1', 'lang' => 'en']], - ['post/a', false], - ['post/1/a', false], - ], - ], - [ - 'host info + defaults', // https://github.com/yiisoft/yii2/issues/6871 - [ - 'pattern' => 'http://en.example.com/<page>', - 'route' => 'post/index', - 'defaults' => ['page' => 1], - ], - [ - ['', 'post/index', ['page' => 1]], - ['2', 'post/index', ['page' => 2]], - ], - ], - ]; - } -} diff --git a/tests/unit/framework/web/UserTest.php b/tests/unit/framework/web/UserTest.php deleted file mode 100644 index 9acb83b..0000000 --- a/tests/unit/framework/web/UserTest.php +++ /dev/null @@ -1,137 +0,0 @@ -<?php - - -namespace yii\web; - -/** - * Mock for the time() function for web classes - * @return int - */ -function time() -{ - return \yiiunit\framework\web\UserTest::$time ?: \time(); -} - -namespace yiiunit\framework\web; - -use yii\base\NotSupportedException; -use yii\base\Component; -use yii\rbac\PhpManager; -use yii\web\IdentityInterface; -use yii\web\UrlManager; -use yii\web\UrlRule; -use yii\web\Request; -use Yii; -use yiiunit\TestCase; - -/** - * @group web - */ -class UserTest extends TestCase -{ - /** - * @var integer virtual time to be returned by mocked time() function. - * Null means normal time() behavior. - */ - public static $time; - - protected function tearDown() - { - Yii::$app->session->removeAll(); - static::$time = null; - parent::tearDown(); - } - - public function testLoginExpires() - { - if (getenv('TRAVIS') == 'true') { - $this->markTestSkipped('Can not reliably test this on travis-ci.'); - } - - $appConfig = [ - 'components' => [ - 'user' => [ - 'identityClass' => UserIdentity::className(), - 'authTimeout' => 10, - ], - 'authManager' => [ - 'class' => PhpManager::className(), - 'itemFile' => '@runtime/user_test_rbac_items.php', - 'assignmentFile' => '@runtime/user_test_rbac_assignments.php', - 'ruleFile' => '@runtime/user_test_rbac_rules.php', - ] - ], - ]; - $this->mockWebApplication($appConfig); - - $am = Yii::$app->authManager; - $am->removeAll(); - $am->add($role = $am->createPermission('rUser')); - $am->add($perm = $am->createPermission('doSomething')); - $am->addChild($role, $perm); - $am->assign($role, 'user1'); - - Yii::$app->session->removeAll(); - static::$time = \time(); - Yii::$app->user->login(UserIdentity::findIdentity('user1')); - -// print_r(Yii::$app->session); -// print_r($_SESSION); - - $this->mockWebApplication($appConfig); - $this->assertFalse(Yii::$app->user->isGuest); - $this->assertTrue(Yii::$app->user->can('doSomething')); - - static::$time += 5; - $this->mockWebApplication($appConfig); - $this->assertFalse(Yii::$app->user->isGuest); - $this->assertTrue(Yii::$app->user->can('doSomething')); - - static::$time += 11; - $this->mockWebApplication($appConfig); - $this->assertTrue(Yii::$app->user->isGuest); - $this->assertFalse(Yii::$app->user->can('doSomething')); - - } - -} - -class UserIdentity extends Component implements IdentityInterface -{ - private static $ids = [ - 'user1', - 'user2', - 'user3', - ]; - - private $_id; - - public static function findIdentity($id) - { - if (in_array($id, static::$ids)) { - $identitiy = new static(); - $identitiy->_id = $id; - return $identitiy; - } - } - - public static function findIdentityByAccessToken($token, $type = null) - { - throw new NotSupportedException(); - } - - public function getId() - { - return $this->_id; - } - - public function getAuthKey() - { - throw new NotSupportedException(); - } - - public function validateAuthKey($authKey) - { - throw new NotSupportedException(); - } -} \ No newline at end of file diff --git a/tests/unit/framework/web/XmlResponseFormatterTest.php b/tests/unit/framework/web/XmlResponseFormatterTest.php deleted file mode 100644 index d98da3d..0000000 --- a/tests/unit/framework/web/XmlResponseFormatterTest.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php -/** - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yiiunit\framework\web; - -use yii\web\XmlResponseFormatter; - -/** - * @author Qiang Xue <qiang.xue@gmail.com> - * @since 2.0 - * - * @group web - */ -class XmlResponseFormatterTest extends FormatterTest -{ - /** - * @return XmlResponseFormatter - */ - protected function getFormatterInstance() - { - return new XmlResponseFormatter(); - } - - private $xmlHead = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - - private function addXmlHead(array $data) - { - foreach ($data as &$item) { - $item[1] = $this->xmlHead . $item[1]; - } - return $data; - } - - public function formatScalarDataProvider() - { - return $this->addXmlHead([ - [1, "<response>1</response>\n"], - ['abc', "<response>abc</response>\n"], - [true, "<response>1</response>\n"], - ["<>", "<response><></response>\n"], - ]); - } - - public function formatArrayDataProvider() - { - return $this->addXmlHead([ - [[], "<response/>\n"], - [[1, 'abc'], "<response><item>1</item><item>abc</item></response>\n"], - [[ - 'a' => 1, - 'b' => 'abc', - ], "<response><a>1</a><b>abc</b></response>\n"], - [[ - 1, - 'abc', - [2, 'def'], - true, - ], "<response><item>1</item><item>abc</item><item><item>2</item><item>def</item></item><item>1</item></response>\n"], - [[ - 'a' => 1, - 'b' => 'abc', - 'c' => [2, '<>'], - true, - ], "<response><a>1</a><b>abc</b><c><item>2</item><item><></item></c><item>1</item></response>\n"], - ]); - } - - public function formatObjectDataProvider() - { - return $this->addXmlHead([ - [new Post(123, 'abc'), "<response><Post><id>123</id><title>abc\n"], - [[ - new Post(123, 'abc'), - new Post(456, 'def'), - ], "123abc456def\n"], - [[ - new Post(123, '<>'), - 'a' => new Post(456, 'def'), - ], "123<>456def\n"], - ]); - } -} diff --git a/tests/unit/framework/widgets/ActiveFieldTest.php b/tests/unit/framework/widgets/ActiveFieldTest.php deleted file mode 100644 index df419a8..0000000 --- a/tests/unit/framework/widgets/ActiveFieldTest.php +++ /dev/null @@ -1,366 +0,0 @@ - - * - * @group widgets - */ -class ActiveFieldTest extends \yiiunit\TestCase -{ - private $activeField; - private $helperModel; - private $helperForm; - private $attributeName = 'attributeName'; - - protected function setUp() - { - parent::setUp(); - // dirty way to have Request object not throwing exception when running testHomeLinkNull() - $_SERVER['SCRIPT_FILENAME'] = "index.php"; - $_SERVER['SCRIPT_NAME'] = "index.php"; - - $this->mockWebApplication(); - - Yii::setAlias('@testWeb', '/'); - Yii::setAlias('@testWebRoot', '@yiiunit/data/web'); - - $this->helperModel = new DynamicModel(['attributeName']); - ob_start(); - $this->helperForm = new ActiveForm(['action' => '/something']); - ob_end_clean(); - - $this->activeField = new ActiveFieldExtend(true); - $this->activeField->form = $this->helperForm; - $this->activeField->form->setView($this->getView()); - $this->activeField->model = $this->helperModel; - $this->activeField->attribute = $this->attributeName; - } - - public function testRenderNoContent() - { - $expectedValue = << - - - -
            - -EOD; - - $actualValue = $this->activeField->render(); - $this->assertEqualsWithoutLE($expectedValue, $actualValue); - } - - /** - * @todo discuss|review Expected HTML shouldn't be wrapped only by the $content? - */ - public function testRenderWithCallableContent() - { - // field will be the html of the model's attribute wrapped with the return string below. - $field = $this->attributeName; - $content = function($field) { - return "
            $field
            "; - }; - - $expectedValue = << -
            - - - -
            -
            - -EOD; - - $actualValue = $this->activeField->render($content); - $this->assertEqualsWithoutLE($expectedValue, $actualValue); - } - - public function testBeginHasErros() - { - $this->helperModel->addError($this->attributeName, "Error Message"); - - $expectedValue = '
            '; - $actualValue = $this->activeField->begin(); - - $this->assertEquals($expectedValue, $actualValue); - } - - public function testBeginAttributeIsRequered() - { - $this->helperModel->addRule($this->attributeName, 'required'); - - $expectedValue = '
            '; - $actualValue = $this->activeField->begin(); - - $this->assertEquals($expectedValue, $actualValue); - } - - public function testBeginHasErrorAndRequired() - { - $this->helperModel->addError($this->attributeName, "Error Message"); - $this->helperModel->addRule($this->attributeName, 'required'); - - $expectedValue = '
            '; - $actualValue = $this->activeField->begin(); - - $this->assertEquals($expectedValue, $actualValue); - } - - public function testEnd() - { - $expectedValue = '
            '; - $actualValue = $this->activeField->end(); - - $this->assertEquals($expectedValue, $actualValue); - - // other tag - $expectedValue = ""; - $this->activeField->options['tag'] = 'article'; - $actualValue = $this->activeField->end(); - - $this->assertTrue($actualValue === $expectedValue); - } - - public function testLabel() - { - $expectedValue = ''; - $this->activeField->label(); - - $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); - - // label = false - $expectedValue = ''; - $this->activeField->label(false); - - $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); - - // $label = 'Label Name' - $label = 'Label Name'; - $expectedValue = <<{$label} -EOT; - $this->activeField->label($label); - - $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); - } - - - public function testError() - { - $expectedValue = ''; - $this->activeField->label(); - - $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); - - // label = false - $expectedValue = ''; - $this->activeField->label(false); - - $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); - - // $label = 'Label Name' - $label = 'Label Name'; - $expectedValue = <<{$label} -EOT; - $this->activeField->label($label); - - $this->assertEquals($expectedValue, $this->activeField->parts['{label}']); - } - - public function testHint() - { - $expectedValue = '
            Hint Content
            '; - $this->activeField->hint('Hint Content'); - - $this->assertEquals($expectedValue, $this->activeField->parts['{hint}']); - } - - public function testInput() - { - $expectedValue = << -EOD; - $this->activeField->input("password"); - - $this->assertEquals($expectedValue, $this->activeField->parts['{input}']); - - // with options - $expectedValue = << -EOD; - $this->activeField->input("password", ['weird' => 'value']); - - $this->assertEquals($expectedValue, $this->activeField->parts['{input}']); - } - - public function testTextInput() - { - $expectedValue = << -EOD; - $this->activeField->textInput(); - $this->assertEquals($expectedValue, $this->activeField->parts['{input}']); - } - - public function testHiddenInput() - { - $expectedValue = << -EOD; - $this->activeField->hiddenInput(); - $this->assertEquals($expectedValue, $this->activeField->parts['{input}']); - } - - public function testListBox() - { - $expectedValue = << -EOD; - $this->activeField->listBox(["1" => "Item One", "2" => "Item 2"]); - $this->assertEqualsWithoutLE($expectedValue, $this->activeField->parts['{input}']); - } - - - - public function testGetClientOptionsReturnEmpty() - { - // setup: we want the real deal here! - $this->activeField->setClientOptionsEmpty(false); - - // expected empty - $actualValue = $this->activeField->getClientOptions(); - $this->assertTrue(empty($actualValue) === true); - } - - public function testGetClientOptionsWithActiveAttributeInScenario() - { - $this->activeField->setClientOptionsEmpty(false); - - $this->activeField->model->addRule($this->attributeName, 'yiiunit\framework\widgets\TestValidator'); - $this->activeField->form->enableClientValidation = false; - - // expected empty - $actualValue = $this->activeField->getClientOptions(); - $this->assertTrue(empty($actualValue) === true); - - } - - public function testGetClientOptionsClientValidation() - { - $this->activeField->setClientOptionsEmpty(false); - - $this->activeField->model->addRule($this->attributeName, 'yiiunit\framework\widgets\TestValidator'); - $this->activeField->enableClientValidation = true; - $actualValue = $this->activeField->getClientOptions(); - $expectedJsExpression = "function (attribute, value, messages, deferred, \$form) {return true;}"; - $this->assertEquals($expectedJsExpression, $actualValue['validate']); - - $this->assertTrue(!isset($actualValue['validateOnChange'])); - $this->assertTrue(!isset($actualValue['validateOnBlur'])); - $this->assertTrue(!isset($actualValue['validateOnType'])); - $this->assertTrue(!isset($actualValue['validationDelay'])); - $this->assertTrue(!isset($actualValue['enableAjaxValidation'])); - - $this->activeField->validateOnChange = $expectedValidateOnChange = false; - $this->activeField->validateOnBlur = $expectedValidateOnBlur = false; - $this->activeField->validateOnType = $expectedValidateOnType = true; - $this->activeField->validationDelay = $expectedValidationDelay = 100; - $this->activeField->enableAjaxValidation = $expectedEnableAjaxValidation = true; - - $actualValue = $this->activeField->getClientOptions(); - - $this->assertTrue($expectedValidateOnChange === $actualValue['validateOnChange']); - $this->assertTrue($expectedValidateOnBlur === $actualValue['validateOnBlur']); - $this->assertTrue($expectedValidateOnType === $actualValue['validateOnType']); - $this->assertTrue($expectedValidationDelay === $actualValue['validationDelay']); - $this->assertTrue($expectedEnableAjaxValidation === $actualValue['enableAjaxValidation']); - } - - public function testGetClientOptionsValidatorWhenClientSet() - { - $this->activeField->setClientOptionsEmpty(false); - $this->activeField->enableAjaxValidation = true; - $this->activeField->model->addRule($this->attributeName, 'yiiunit\framework\widgets\TestValidator'); - - foreach($this->activeField->model->validators as $validator) { - $validator->whenClient = "function (attribute, value) { return 'yii2' == 'yii2'; }"; // js - } - - $actualValue = $this->activeField->getClientOptions(); - $expectedJsExpression = "function (attribute, value, messages, deferred, \$form) {if ((function (attribute, value) " - . "{ return 'yii2' == 'yii2'; })(attribute, value)) { return true; }}"; - - $this->assertEquals($expectedJsExpression, $actualValue['validate']->expression); - } - - /** - * Helper methods - */ - protected function getView() - { - $view = new View(); - $view->setAssetManager(new AssetManager([ - 'basePath' => '@testWebRoot/assets', - 'baseUrl' => '@testWeb/assets', - ])); - - return $view; - } - -} - -/** - * Helper Classes - */ -class ActiveFieldExtend extends ActiveField -{ - private $getClientOptionsEmpty; - - public function __construct($getClientOptionsEmpty = true) - { - $this->getClientOptionsEmpty = $getClientOptionsEmpty; - } - - public function setClientOptionsEmpty($value) - { - $this->getClientOptionsEmpty = (bool) $value; - } - - /** - * Useful to test other methods from ActiveField, that call ActiveField::getClientOptions() - * but it's return value is not relevant for the test being run. - */ - public function getClientOptions() - { - return ($this->getClientOptionsEmpty) ? [] : parent::getClientOptions(); - } -} - -class TestValidator extends \yii\validators\Validator -{ - - public function clientValidateAttribute($object, $attribute, $view) - { - return "return true;"; - } - - public function setWhenClient($js) - { - $this->whenClient = $js; - } -} diff --git a/tests/unit/framework/widgets/ActiveFormTest.php b/tests/unit/framework/widgets/ActiveFormTest.php deleted file mode 100644 index ac3a4f2..0000000 --- a/tests/unit/framework/widgets/ActiveFormTest.php +++ /dev/null @@ -1,77 +0,0 @@ - - */ - -namespace yiiunit\framework\widgets; - -use yii\base\DynamicModel; -use yii\widgets\ActiveForm; - -/** - * @group widgets - */ -class ActiveFormTest extends \yiiunit\TestCase -{ - protected function setUp() - { - parent::setUp(); - $this->mockApplication(); - } - - public function testBooleanAttributes() - { - $o = ['template' => '{input}']; - - $model = new DynamicModel(['name']); - ob_start(); - $form = new ActiveForm(['action' => '/something']); - ob_end_clean(); - - $this->assertEqualsWithoutLE(<< - -
            -EOF -, (string) $form->field($model, 'name', $o)->input('email', ['required' => true])); - - $this->assertEqualsWithoutLE(<< - -
            -EOF - , (string) $form->field($model, 'name', $o)->input('email', ['required' => false])); - - - $this->assertEqualsWithoutLE(<< - - -EOF - , (string) $form->field($model, 'name', $o)->input('email', ['required' => 'test'])); - - } - - public function testIssue5356() - { - $o = ['template' => '{input}']; - - $model = new DynamicModel(['categories']); - $model->categories = 1; - ob_start(); - $form = new ActiveForm(['action' => '/something']); - ob_end_clean(); - - // https://github.com/yiisoft/yii2/issues/5356 - $this->assertEqualsWithoutLE(<< - - -EOF - , (string) $form->field($model, 'categories', $o)->listBox(['apple', 'banana', 'avocado'], ['multiple' => true])); - } -} diff --git a/tests/unit/framework/widgets/BreadcrumbsTest.php b/tests/unit/framework/widgets/BreadcrumbsTest.php deleted file mode 100644 index 6997e5c..0000000 --- a/tests/unit/framework/widgets/BreadcrumbsTest.php +++ /dev/null @@ -1,175 +0,0 @@ - - * - * @group widgets - */ -class BreadcrumbsTest extends \yiiunit\TestCase -{ - private $breadcrumbs; - - protected function setUp() - { - parent::setUp(); - // dirty way to have Request object not throwing exception when running testHomeLinkNull() - $_SERVER['SCRIPT_FILENAME'] = "/index.php"; - $_SERVER['SCRIPT_NAME'] = "/index.php"; - - $this->mockWebApplication(); - $this->breadcrumbs = new Breadcrumbs(); - } - - public function testHomeLinkNull() - { - $this->breadcrumbs->homeLink = null; - $this->breadcrumbs->links = ['label' => 'My Home Page', 'url' => 'http://my.example.com/yii2/link/page']; - - $expectedHtml = "
            • Home
            • \n" - . "
            • My Home Page
            • \n" - . "
            • http://my.example.com/yii2/link/page
            • \n" - . "
            "; - - ob_start(); - $this->breadcrumbs->run(); - $actualHtml = ob_get_contents(); - ob_end_clean(); - - $this->assertEquals($expectedHtml, $actualHtml); - } - - public function testEmptyLinks() - { - $this->assertNull($this->breadcrumbs->run()); - } - - public function testHomeLinkFalse() - { - $this->breadcrumbs->homeLink = false; - $this->breadcrumbs->links = ['label' => 'My Home Page', 'url' => 'http://my.example.com/yii2/link/page']; - - $expectedHtml = "
            • My Home Page
            • \n" - . "
            • http://my.example.com/yii2/link/page
            • \n" - . "
            "; - - ob_start(); - $this->breadcrumbs->run(); - $actualHtml = ob_get_contents(); - ob_end_clean(); - - $this->assertEquals($expectedHtml, $actualHtml); - } - - - public function testHomeLink() - { - $this->breadcrumbs->homeLink = ['label' => 'home-link']; - $this->breadcrumbs->links = ['label' => 'My Home Page', 'url' => 'http://my.example.com/yii2/link/page']; - - $expectedHtml = "
            • home-link
            • \n" - . "
            • My Home Page
            • \n" - . "
            • http://my.example.com/yii2/link/page
            • \n" - . "
            "; - - ob_start(); - $this->breadcrumbs->run(); - $actualHtml = ob_get_contents(); - ob_end_clean(); - - $this->assertEquals($expectedHtml, $actualHtml); - } - - public function testRenderItemException() - { - $link = ['url' => 'http://localhost/yii2']; - $method = $this->reflectMethod(); - $this->setExpectedException('yii\base\InvalidConfigException'); - $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); - } - - public function testRenderItemLabelOnly() - { - $link = ['label' => 'My-
            Test-Label']; - $method = $this->reflectMethod(); - $encodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); - - $this->assertEquals("
          1. My-<br>Test-Label
          2. \n", $encodedValue); - - //without encodeLabels - $this->breadcrumbs->encodeLabels = false; - $unencodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); - - $this->assertEquals("
          3. My-
            Test-Label
          4. \n", $unencodedValue); - } - - public function testEncodeOverride() - { - $link = ['label' => 'My-
            Test-Label', 'encode' => false]; - $method = $this->reflectMethod(); - $result = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); - - $this->assertEquals("
          5. My-
            Test-Label
          6. \n", $result); - - //without encodeLabels - $this->breadcrumbs->encodeLabels = false; - $unencodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); - - $this->assertEquals("
          7. My-
            Test-Label
          8. \n", $unencodedValue); - } - - public function testRenderItemWithLabelAndUrl() - { - $link = ['label' => 'My-
            Test-Label', 'url' => 'http://localhost/yii2']; - $method = $this->reflectMethod(); - $encodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); - - $this->assertEquals("
          9. My-<br>Test-Label
          10. \n", $encodedValue); - - // without encodeLabels - $this->breadcrumbs->encodeLabels = false; - $unencodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); - $this->assertEquals("
          11. My-
            Test-Label
          12. \n", $unencodedValue); - } - - public function testRenderItemTemplate() - { - $link = ['label' => 'My-
            Test-Label', 'url' => 'http://localhost/yii2', 'template' => "{link}\n"]; - $method = $this->reflectMethod(); - $encodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); - - $this->assertEquals("My-<br>Test-Label\n", $encodedValue); - - // without encodeLabels - $this->breadcrumbs->encodeLabels = false; - $unencodedValue = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); - $this->assertEquals("My-
            Test-Label
            \n", $unencodedValue); - } - - public function testExtraOptions() - { - $link = [ - 'label' => 'demo', - 'url' => 'http://example.com', - 'class' => 'external', - ]; - $method = $this->reflectMethod(); - $result = $method->invoke($this->breadcrumbs, $link, $this->breadcrumbs->itemTemplate); - $this->assertEquals('
          13. demo
          14. ' . "\n", $result); - } - - /** - * Helper methods - */ - protected function reflectMethod($class = '\yii\widgets\Breadcrumbs', $method = 'renderItem') - { - $value = new \ReflectionMethod($class, $method); - $value->setAccessible(true); - - return $value; - } -} diff --git a/tests/unit/framework/widgets/LinkSorterTest.php b/tests/unit/framework/widgets/LinkSorterTest.php deleted file mode 100644 index 01dc32e..0000000 --- a/tests/unit/framework/widgets/LinkSorterTest.php +++ /dev/null @@ -1,76 +0,0 @@ -getConnection(); - $this->mockWebApplication(); - $this->breadcrumbs = new Breadcrumbs(); - } - - public function testLabelsSimple() - { - $dataProvider = new ActiveDataProvider([ - 'query' => Order::find(), - 'models' => [new Order()], - 'totalCount' => 1, - 'sort' => [ - 'route' => 'site/index', - ], - ]); - - ob_start(); - echo ListView::widget([ - 'dataProvider' => $dataProvider, - 'layout' => "{sorter}", - ]); - $actualHtml = ob_get_clean(); - - $this->assertTrue(strpos($actualHtml, 'Customer') !== false); - $this->assertTrue(strpos($actualHtml, 'Invoice Total') !== false); - } - - public function testLabelsExplicit() - { - $dataProvider = new ActiveDataProvider([ - 'query' => Order::find(), - 'models' => [new Order()], - 'totalCount' => 1, - 'sort' => [ - 'attributes' => ['total'], - 'route' => 'site/index', - ], - ]); - - ob_start(); - echo ListView::widget([ - 'dataProvider' => $dataProvider, - 'layout' => "{sorter}", - ]); - $actualHtml = ob_get_clean(); - - $this->assertFalse(strpos($actualHtml, 'Customer') !== false); - $this->assertTrue(strpos($actualHtml, 'Invoice Total') !== false); - } - -} diff --git a/tests/unit/framework/widgets/MenuTest.php b/tests/unit/framework/widgets/MenuTest.php deleted file mode 100644 index 2b57898..0000000 --- a/tests/unit/framework/widgets/MenuTest.php +++ /dev/null @@ -1,104 +0,0 @@ -mockApplication(); - } - - public function testEncodeLabel() - { - $output = Menu::widget([ - 'route' => 'test/test', - 'params' => [], - 'encodeLabels' => true, - 'items' => [ - [ - 'encode' => false, - 'label' => ' Users', - 'url' => '#', - ], - [ - 'encode' => true, - 'label' => 'Authors & Publications', - 'url' => '#', - ], - ] - ]); - - $this->assertEqualsWithoutLE(<<
          15. Users
          16. -
          17. Authors & Publications
          18. -HTML - , $output); - - $output = Menu::widget([ - 'route' => 'test/test', - 'params' => [], - 'encodeLabels' => false, - 'items' => [ - [ - 'encode' => false, - 'label' => ' Users', - 'url' => '#', - ], - [ - 'encode' => true, - 'label' => 'Authors & Publications', - 'url' => '#', - ], - ] - ]); - - $this->assertEqualsWithoutLE(<<
          19. Users
          20. -
          21. Authors & Publications
          22. -HTML - , $output); - - } - - /** - * @see https://github.com/yiisoft/yii2/issues/8064 - */ - public function testTagOption() - { - $output = Menu::widget([ - 'route' => 'test/test', - 'params' => [], - 'encodeLabels' => true, - 'options' => [ - 'tag' => false, - ], - 'items' => [ - [ - 'label' => 'item1', - 'url' => '#', - 'options' => ['tag' => 'div'], - ], - [ - 'label' => 'item2', - 'url' => '#', - 'options' => ['tag' => false], - ], - ] - ]); - - $this->assertEqualsWithoutLE(<<item1 -item2 -HTML - , $output); - } - - -} diff --git a/tests/unit/framework/widgets/SpacelessTest.php b/tests/unit/framework/widgets/SpacelessTest.php deleted file mode 100644 index ae41b4c..0000000 --- a/tests/unit/framework/widgets/SpacelessTest.php +++ /dev/null @@ -1,41 +0,0 @@ -\n"; - - Spaceless::begin(); - echo "\t
            \n"; - - Spaceless::begin(); - echo "\t\t
            \n"; - echo "\t\t\t

            This is a left bar!

            \n"; - echo "\t\t
            \n\n"; - echo "\t\t
            \n"; - echo "\t\t\t

            This is a right bar!

            \n"; - echo "\t\t
            \n"; - Spaceless::end(); - - echo "\t
            \n"; - Spaceless::end(); - - echo "\t

            Bye!

            \n"; - echo "\n"; - - $expected = "\n

            This is a left bar!

            ". - "

            This is a right bar!

            \t

            Bye!

            \n\n"; - $this->assertEquals($expected, ob_get_clean()); - } -} diff --git a/tests/unit/runtime/.gitignore b/tests/unit/runtime/.gitignore deleted file mode 100644 index 5e31724..0000000 --- a/tests/unit/runtime/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* -!.gitignore -!/coveralls/.gitkeep diff --git a/tests/unit/runtime/coveralls/.gitkeep b/tests/unit/runtime/coveralls/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/web/app/assets/.gitignore b/tests/web/app/assets/.gitignore deleted file mode 100644 index 72e8ffc..0000000 --- a/tests/web/app/assets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/tests/web/app/index.php b/tests/web/app/index.php deleted file mode 100644 index 72d3189..0000000 --- a/tests/web/app/index.php +++ /dev/null @@ -1,6 +0,0 @@ -run(); diff --git a/tests/web/app/protected/config/main.php b/tests/web/app/protected/config/main.php deleted file mode 100644 index 0b67a5f..0000000 --- a/tests/web/app/protected/config/main.php +++ /dev/null @@ -1,3 +0,0 @@ - 'item 1', - 'value 2' => 'item 2', - 'value 3' => 'item 3', - ], isset($_POST['test']) ? $_POST['test'] : null, - function ($index, $label, $name, $value, $checked) { - return Html::label( - $label . ' ' . Html::checkbox($name, $value, $checked), - null, ['class' => 'inline checkbox'] - ); - }); - echo Html::submitButton(); - echo Html::endForm(); - print_r($_POST); - } -} diff --git a/tests/web/app/protected/runtime/.gitignore b/tests/web/app/protected/runtime/.gitignore deleted file mode 100644 index 72e8ffc..0000000 --- a/tests/web/app/protected/runtime/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/tests/web/app/protected/views/site/index.php b/tests/web/app/protected/views/site/index.php deleted file mode 100644 index cc86af6..0000000 --- a/tests/web/app/protected/views/site/index.php +++ /dev/null @@ -1,8 +0,0 @@ -